Windows-Server-2012-R2

Windows 2012 R2 和 Linux Centos7 之間的 TCP 套接字連接錯誤

  • July 4, 2018

我在 Windows 2012 R2 機器和 Linux CentOS7 之間的 TCP 套接字連接問題。當我執行一個從 Linux 向 Windows perl 服務發送多條消息的 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

終於我找到了解決方案!干擾 Windows 和 Centos7 之間連接的是以下配置,我們在 /etc/sysctl.conf 中使用:

   net.ipv4.tcp_tw_recycle = 1

我已將其更改為:

   net.ipv4.tcp_tw_recycle = 0

我已經使用該配置重新啟動了 Centos7 上的網路,並且它再次雙向發送 TCP 消息並沒有失敗。

引用自:https://serverfault.com/questions/917730