我在 Windows 2012 R2 计算机和 Linux CentOS7 之间的 TCP 套接字连接方面遇到了问题。当我运行 perl 客户端,从 Linux 向 Windows perl 服务发送多条消息时,它始终工作正常。但是,如果我从 Windows 向 Linux 服务运行相同的客户端,有时它不会连接,并且需要大约 60 秒才能恢复。当两个客户端几乎同时执行时,就会发生这种情况。就好像 Linux 在向 Windows 发送消息后暂时关闭了所有监听端口一样。我也尝试过用 C 编写的客户端/服务器,情况也一样。
这是客户端代码:
#!perl
use Socket;
use Getopt::Long;
use Time::HiRes;
GetOptions( "msg=s" => \$msg,
"ip=s" => \$server,
"port=s" => \$port );
$y=20;
$totalTime=0;
for(my $i=0;$i<$y;$i++){
$ti=Time::HiRes::time();
&gjmsimplecli($msg.' '.$i, $server, $port);
$TestTime{"Result"} = Time::HiRes::time() - $ti;
$totalTime += $TestTime{"Result"};
print "Test $i \t[$TestTime{Result}] server [$server] port [$port]\n";
if ($TestTime{Result}>40){
$contadordemora++;
push(@demora,$i);
}
}
$promedio=$totalTime / $y;
print "Tiempo Promedio: [$promedio]\n";
print "Mensajes con demoras [$contadordemora] \n[@demora]\n";
sub gjmsimplecli {
my $msg = shift;
my $server = shift; # Host IP running the server
my $port = shift; # Host IP running the server
my $len = length($msg2JM);
$msg .= '#'x(1024-$len);
my $maxretrieve = 100;
my $retrieve = $maxretrieve;
my $msge = '';
while($retrieve){
if ($retrieve<100) { print " Retrieve - Last socket [$t11] connect [$t22] syswrite [$t33] sec\n"; }
$retrieve--;
$msge = '';
$t00 = Time::HiRes::time();
# create the socket, connect to the port
socket($socket,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2])
or $msge= "Error socket: $!";
$t11 = Time::HiRes::time() - $t00;
if ($msge ne '') { next; }
connect( $socket, pack_sockaddr_in($port, inet_aton($server)))
or $msge= "Error connect: $!";
$t22 = Time::HiRes::time() - $t00;
if ($msge ne '') { close($socket); next; }
syswrite $socket, $msg, 1024 or $msge = "Error syswrite: $!";
$t33 = Time::HiRes::time() - $t00;
if ($msge eq '') { $retrieve = 0; }
select(undef, undef, undef, 0.01);
if ($socket) { close($socket) }
}
}
这就是服务器代码:
#!perl
# Filename : server.pl
use POSIX;
use Socket;
sub makelisten {
my ( $proto );
#port and protocol
$port = shift || 3201;
$proto = getprotobyname('tcp') or die("getprotobyname: cannot get proto: $!");
#bind at inet address
socket( LISTFD, PF_INET, SOCK_STREAM, $proto );
setsockopt( LISTFD, SOL_SOCKET, SO_REUSEADDR, 1 );
setsockopt( LISTFD, SOL_SOCKET, SO_LINGER,pack("II",1,10)) or die "Can't set SO_LINGER: $!";
bind( LISTFD, sockaddr_in( $port, INADDR_ANY ) ) or die("bind: $!");
listen( LISTFD, SOMAXCONN ) or die("listen: $!");
return LISTFD;
}
$LISTFD=makelisten(shift);
print "SERVER started on port $port\n";
LOOP: while (1) {
my ($NEW_SOCKET,$msg);
unless (my $paddr = accept($NEW_SOCKET, $LISTFD) ) { close($NEW_SOCKET); next LOOP; }
# First socket reading
sysread $NEW_SOCKET, $msg, 1024||print " Error getting the message: $!";
close($NEW_SOCKET);
$msg =~ s/#+$//g;
print "gsimple msg [$msg]\n";
select(undef, undef, undef, 0.01);
}
有人能帮帮我吗?我可以在 Centos 或 Windows 中配置什么来避免每次请求同时到达时出现这种烦人的 60 秒阻塞?
对于测试你可以运行服务器像这样:
Linux:
perl ./serv.pl 3201
视窗:
perl .\serv.pl 3202
运行客户端像这样:
Linux:
perl ./test_sendmsg.pl --msg="mensaje de prueba" --ip=replace_your_ip_windows --port=3202
视窗:
perl .\test_sendmsg.pl --msg="mensaje de prueba" --ip=replace_your_ip_linux --port=3201
答案1
我终于找到了解决方案!干扰 Windows 和 Centos7 之间连接的是我们在 /etc/sysctl.conf 中使用的以下配置:
net.ipv4.tcp_tw_recycle = 1
我已将其更改为:
net.ipv4.tcp_tw_recycle = 0
我已经使用该配置重新启动了 Centos7 上的网络,并且它在两个方向上发送 TCP 消息时没有再次失败。