我正在编写一个简单的TCP客户端和服务器Perl脚本。到现在为止,我使用wireshark验证了三路TCP握手,并且建立了连接。但当我尝试发送或恢复数据时,什么也不会发生。
1)客户端和服务器之间的主要区别只是服务器增加了一个LISTEN参数,使它能够侦听传入的连接?
2)在recv和显示数据之间是否缺少任何步骤?
3)当程序第一次执行while循环时,难道不应该至少发送硬编码字符串“$response”吗?
#!/usr/bin/perl
use IO::Socket;
use Getopt::Long;
#$IP_addr = $ARGV[0];
#$tgt_port = $ARG[1];
#netcat client
$port = 9040;
$sock = IO::Socket::INET->new( PeerAddr => 'localhost',
PeerPort => $port,
LocalPort => 9000,
Proto => 'tcp')
or die "\nunable to bind on localhost : $port...";
while ($sock){
#Get the clients IP and port number
$client_IP = $sock -> peerhost();
#$client_IP = 'localhost';
$client_port = $sock -> peerport();
print "\n Connected to $client_IP $client_port \n";
#Reading from socket
$data;
$sock ->recv($data, 1024);
print $data;
#writing to socket
$sock->autoflush(1);
$response = "response: OK recvd\n" ;
$sock->send($response);
shutdown($sock,1);
}
$sock -> close();
服务器如下:
#!/usr/bin/perl
use IO::Socket;
use Getopt::Long;
#$IP_addr = $ARGV[0];
#$tgt_port = $ARG[1];
#netcat server
$port = 9040;
$sock = IO::Socket::INET->new( Listen => 1,
LocalAddr => 'localhost',
LocalPort => $port,
Proto => 'tcp')
or die "\nunable to bind on localhost : $port...";
while ($sock){
print "\nListening on port $port ...\n";
$sock = $sock -> accept();
#Get the clients IP and port number
$client_IP = $sock->peerhost();
$client_port = $sock->peerport();
print "\n Connected from $client_IP $client_port \n";
#Reading from socket
$data ->recv($sock, 1024);
print $data;
#writing to socket
$sock->autoflush(1);
$response = "oohlalala" ;
$sock -> send($response);
shutdown($sock, 1);
}
$sock -> close();
来自IO::套接字:
从1.18版开始,所有IO::Socket对象都默认开启自动刷新。早期版本的情况并非如此。
Perl 2.0版于1988年发布。您最有可能使用的是Perl5.x版本。
https://perldoc.perl.org/io/socket.html
这里有一个很好的,简短的,关于插座的基本描述。
您的服务器代码可能隐藏了一些正在发生的事情。如果是这样写的话,就更能说明问题了:
$server_socket = IO::Socket::INET(.....);
...
...
my $client_socket = $server_socket->accept();
...
...
use strict;
use warnings;
use 5.020;
use autodie;
use Data::Dumper;
use IO::Socket::INET;
use Socket qw( :crlf ); # "\x0D\x0A" constants CRLF and $CRLF
my $host = 'localhost';
my $port = 15_678;
my $server_socket = IO::Socket::INET->new(
Listen => 5,
LocalPort => $port,
LocalAddr => $host,
Proto => 'tcp',
ReuseAddr => 1,
ReusePort => 1
);
say "Server listening on port: $port\n";
while (my $client_socket = $server_socket->accept() ) {
my $client_ip = $client_socket->peerhost();
my $client_port = $client_socket->peerport();
say "Connection from $client_ip:$client_port";
{
local $/ = CRLF; # $/ is the input record separator, which is "\n"
#by default. Both <$INFILE> and getline() read up to
#and including the input record separator.
while(my $line = $client_socket->getline) { #Blocks until CRLF is read
#from the socket or the other
#side closes the socket.
chomp $line; #chomp() removes input record separator from end of line.
say "Server received: $line";
my $response = reverse $line;
$client_socket->send("$response$CRLF");
say "Server sent: $response";
}
} #Here $/ is restored to whatever it was before this parenthesized block.
#That is what declaring a variable as local does.
say "-" x 30;
#Execution arrives here after the client closes the socket:
$client_socket->shutdown(2); #Send signals to other side of socket.
#Not necessary in this example because other threads
#aren't also reading from the socket.
$client_socket->close(); #Close the filehandle associated with the socket.
}
注意,就像读取文件一样,getline将在接收到eof信号时返回到目前为止读取的所有内容,并且对于while循环的下一次迭代,getline将返回undef,从而终止while循环。
client.pl:
use strict;
use warnings;
use 5.020;
use autodie;
use Data::Dumper;
use IO::Socket::INET;
use Socket qw( :crlf ); #\x0D\x0A constants CRLF and $CRLF
my $port = 15_678;
my @lines = (
"hello world",
"goodbye mars",
);
my $sock = IO::Socket::INET->new("localhost:$port");
for my $line(@lines){
my $server_ip = $sock->peerhost();
my $server_port = $sock->peerport();
say "Connected to $server_ip:$server_port";
$sock->send("$line$CRLF");
say "Client sent: $line";
my $response;
{
local $/ = CRLF;
$response = $sock->getline();
chomp $response;
}
say "Client received: $response";
say '-' x 30;
}
#Tell the server that no more data is coming from this client:
$sock->shutdown(2); #Send signals to other side of socket.
$sock->close(); #Close the filehandle associated with the socket.
运行客户端程序两次后...
Server listening on port: 15678
Connection from 127.0.0.1:56085
Server received: hello world
Server sent: dlrow olleh
Server received: goodbye mars
Server sent: sram eybdoog
------------------------------
Connection from 127.0.0.1:56096
Server received: hello world
Server sent: dlrow olleh
Server received: goodbye mars
Server sent: sram eybdoog
------------------------------
$ perl client.pl
Connected to 127.0.0.1:15678
Client sent: hello world
Client received: dlrow olleh
------------------------------
Connected to 127.0.0.1:15678
Client sent: goodbye mars
Client received: sram eybdoog
------------------------------
$ perl client.pl
Connected to 127.0.0.1:15678
Client sent: hello world
Client received: dlrow olleh
------------------------------
Connected to 127.0.0.1:15678
Client sent: goodbye mars
Client received: sram eybdoog
------------------------------
$
4)shutdown($sock,1)和sleep(1)在此实现中有何不同?让套接字Hibernate可以吗?还是应该使用shutdown($sock,1)向客户机/服务器发出数据已发送的信号?
我不确定shutdown()和sleep()在任何方面是如何相关的。sleep()会在指定的时间内停止代码的执行,而shutdown()会向套接字的另一端发送一些内容。
“关闭套接字”,即调用shutdown()
,以标记数据的结束,这是您可以采用的另一种协议。这使得事情变得很简单:一方只是继续以某种read语句从套接字读取,当另一方关闭套接字时,read将返回。这里有一个例子:
use strict;
use warnings;
use 5.020;
use autodie;
use Data::Dumper;
use IO::Socket::INET;
my $host = 'localhost';
my $port = 15_678;
my $server_socket = IO::Socket::INET->new(
Listen => 5,
LocalPort => $port,
LocalAddr => $host,
Proto => 'tcp',
ReuseAddr => 1,
ReusePort => 1
);
say "Server listening on port: $port\n";
while (my $client_socket = $server_socket->accept() ) {
my $client_ip = $client_socket->peerhost();
my $client_port = $client_socket->peerport();
say "Connection from $client_ip:$client_port";
my $data;
{
local $/ = undef; #This input record separtor will never be found...
$data = <$client_socket>; #...so this reads everything--including newlines--until it gets an eof signal.
}
say "Server received: $data";
my $response = reverse $data;
$client_socket->send($response);
$client_socket->shutdown(2); #Doesn't close filehandle -- merely sends signals.
$client_socket->close(); ##Close the filehandle associated with the socket.
say "Server sent: $response";
say "-" x 30;
}
use strict;
use warnings;
use 5.020;
use autodie;
use Data::Dumper;
use IO::Socket::INET;
my $port = 15_678;
my @data = (
"hello \n world", #Now newlines are in the data
"goodbye \n mars",
);
for my $data (@data){
my $sock = IO::Socket::INET->new("localhost:$port");
my $server_ip = $sock->peerhost();
my $server_port = $sock->peerport();
say "Connected to $server_ip:$server_port";
$sock->send($data);
say "Client sent: $data";
$sock->shutdown(1);
my $response;
{
local $/ = undef; #This input record separtor will never be found...
$response = <$sock>; ##...so this reads everything--including newlines--until it gets an eof signal.
}
$sock->shutdown(0);
$sock->close();
say "Client received: $response";
say '-' x 30;
}
服务器输出:
Server listening on port: 15678
Connection from 127.0.0.1:53139
Server received: hello
world
Server sent: dlrow
olleh
------------------------------
Connection from 127.0.0.1:53140
Server received: goodbye
mars
Server sent: sram
eybdoog
------------------------------
客户端输出:
Connected to 127.0.0.1:15678
Client sent: hello
world
Client received: dlrow
olleh
------------------------------
Connected to 127.0.0.1:15678
Client sent: goodbye
mars
Client received: sram
eybdoog
------------------------------
我的问题是为什么接收端没有得到发送的数据包? 注意:我的目标是在建立的连接上发送带有错误校验和的TCP数据包,并由不scapy的TCP服务器接收,提前谢谢!!
OpenSSL版本:OpenSSL 1.1.0g 要创建证书,我运行以下命令: openssl genrsa-des3-out server.key 2048 openssl x509-请求-天数365-输入server.csr-签名密钥server.key-输出server.crt ...新的TLSV1.2密码是AES256-GCM-SHA384 服务器公钥为2048位 支持安全重新协商 ...
问题内容: 我的GO版本是1.1.1 连接关闭后服务器收到的消息,但设置了NoDelay。 有什么不对 问题答案: 您的代码似乎没有任何根本性的错误,因此我猜错误是在服务器端。 如果在端口5432上创建本地TCP服务器,则可以对此进行测试。 尝试运行下面的服务器代码,然后针对它测试客户端代码。它只是将所有接收到的数据回显到stdout。 按下回车键后,您应该看到发送给客户端的每一行都已打印(没有换
我使用Android应用程序通过TCP套接字与同一局域网上的PC java应用程序进行通信、发送和接收消息。下面是我在android中使用的Asynctask的代码,用于发送消息并从PC接收回复: } 我在onPostExcecute中的祝酒词中显示PC的回复。 Android通过BufferedWriter发送消息,而PC上的java应用程序在BufferedReader中接收消息。 PC在收到
在套接字最终接受另一端消失的情况下,什么指定了这个超时?是操作系统(Ubuntu 11.04),还是来自TCP/IP规范,还是套接字配置选项?
我使用tcpdump从客户端捕获数据包,每个数据包都是分段到最大1448字节的数据,但是head只有5字节,为什么我可以成功读取head,但是下面的data recv()操作又会返回ee?当数据已经到达recv缓冲区时,recv是否可能返回EAGAIN?在我看来,我可以读取前5个字节,所以必须有更多的数据在recv缓冲区读取。 可能与TCP/IP协议栈中的组装过程有关。代码如下所示,每个pdu r