У меня проблема с подключением TCP-сокетов между машиной Windows 2012 R2 и Linux CentOS7. Когда я запускаю клиент 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
Windows:
perl .\serv.pl 3202
Запускаем клиентов как это:
Linux:
perl ./test_sendmsg.pl --msg="mensaje de prueba" --ip=replace_your_ip_windows --port=3202
Windows:
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-сообщений в обоих направлениях.