Как я могу диагностировать «Не могу определить адрес партнера» в моем сценарии Perl TCP? - PullRequest
4 голосов
/ 22 февраля 2010

У меня есть этот маленький скрипт, который хорошо справляется со своей работой, но иногда он не работает. Сбой в 2 случаях:

  1. с ошибкой отправки: Cannot determine peer address at ./tcp-new.pl line 52

  2. без вывода или чего-либо еще, он просто не может доставить то, что получил на подключенный клиент Tcp. Обычно это происходит после того, как я отключаюсь от сервера, иду домой и подключаюсь снова. Для исправления этого требуется перезагрузка, и она начинает работать. Иногда за этой проблемой следует проблема, упомянутая в пункте 1.

Примечание: это не проблема, когда я отключаюсь и снова подключаюсь к нему в течение короткого промежутка времени (если не возникает ошибка 1)

Так может ли кто-нибудь помочь мне сделать этот код более стабильным, чтобы мне не приходилось перезапускать его каждый день?

#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket;
use IO::Select;

my $tcp_port = "10008";
my $udp_port = "2099";

my $tcp_socket = IO::Socket::INET->new(
  Listen => SOMAXCONN,  LocalPort => $tcp_port,
  Proto  => 'tcp',      ReuseAddr => 1,
);
my $udp_socket = IO::Socket::INET->new(
  LocalPort => $udp_port, Proto => 'udp',
);

my $read_select  = IO::Select->new();
my $write_select = IO::Select->new();

$read_select->add($tcp_socket);
$read_select->add($udp_socket);

while (1) {
  my @read = $read_select->can_read();

  foreach my $read (@read) {

    if ($read == $tcp_socket) {

        my $new_tcp = $read->accept();
        $write_select->add($new_tcp);

    } elsif ($read == $udp_socket) {

        my $recv_buffer;
        $udp_socket->recv($recv_buffer, 1024, undef);

        my @write = $write_select->can_write();
        foreach my $write (@write) {
            $write->send($recv_buffer);
        }
    }
  }
}

Ответы [ 3 ]

2 голосов
/ 22 февраля 2010

Ошибка Cannot determine peer address означает, что getpeername() вернул false. Это, вероятно, означает, что сокет был закрыт с другой стороны, возможно, между вызовом can_write() и вызовом send. Вы, вероятно, должны удалить его из выбранного набора и двигаться дальше.

1 голос
/ 28 апреля 2014

Найдена та же проблема с носком, не имеющим peeraddress.

Глядя на IO :: Сокет на http://search.cpan.org/src/GBARR/IO-1.2301/IO/Socket.pm показывает:

sub send { @_ >= 2 && @_ <= 4 or croak 'usage: $sock->send(BUF, [FLAGS, [TO]] +)'; 
my $sock = $_[0]; my $flags = $_[2] || 0; my $peer = $_[3] || $sock->peername; 
croak 'send: Cannot determine peer address' unless($peer);

Таким образом, вы должны позаботиться о том, чтобы либо имя равноправного узла инициализировалось при создании объекта, либо предоставлялось адресом равноправного узла в качестве третьего аргумента send ().

if (! $sock->peeraddr()) {
         $log->warn("No peer, will croak!");
}
0 голосов
/ 16 апреля 2010

В сценарии, когда ваш сценарий дает сбой сразу, без каких-либо сообщений об ошибках, это, вероятно, связано с необработанным сигналом, обычно SIGPIPE.Это может произойти, если операция сокета получает сигнал во время операции отправки.Я могу достаточно легко воспроизвести его в моих собственных системах, имитируя множество одновременных подключений с большим объемом данных к tcp-серверу и одновременно уничтожая эти клиентские подключения.Запустите strace на вашем скрипте, и вы сможете увидеть сигнал достаточно четко.Тем не менее, я пытаюсь выяснить, как воспроизвести ошибку «Не удается определить адрес узла», но безрезультатно ...

...