Назад | Перейти на главную страницу

Ошибка соединения с сокетами TCP между Windows 2012 R2 и Linux Centos7

У меня проблема с подключением 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-сообщений в обоих направлениях.