无法检测到与 $sock->connected() 的关闭连接

can't detect closed connection with $sock->connected()

我正在尝试 - 但失败了 - 让 perl 服务器检测并摆脱与断开连接的客户端的连接。我到处看,建议的方法是使用套接字的 ->connected() 方法,但在我的例子中它失败了。

这是绝对最小化的服务器:

#!/usr/bin/perl
use IO::Socket;
STDOUT->autoflush(1);


my $server = new IO::Socket::INET (
                                Listen => 7,
                                Reuse   => 1,
                                LocalAddr => '192.168.0.29',
                                LocalPort => '11501',
                                Proto => 'tcp',
                                 );
die "Could not create socket: $!\n" unless $server;

print "Waiting for clients\n";

while ($client = $server->accept()) {
        print "Client connected\n";
        do {
                $client->recv($received,1024);
                print $received;
                select(undef, undef, undef, 0.1); # wait 0.1s before next read, not to spam the console if recv returns immediately
                print ".";
        } while( $client->connected() );
        print "Client disconnected\n";
}

我用 Netcat 连接到服务器,一切正常,服务器接收我发送的任何东西,但是当我按 ctrl-C 中断 Netcat 时,'recv' 不再等待,但是 $client->connected() 仍然 returns 一个类似真实的值,主循环永远不会 returns 等待下一个客户端。

(注意 - 上面的例子已经被绝对最小化以显示问题,但在完整的程序中,套接字设置为非阻塞,所以我相信我不能简单地依赖 recv 返回一个空字符串。除非我错了?)

connected 不能用于可靠地了解对等方是否已启动关闭。文档中几乎逐字逐句地提到了它:

Note that this method considers a half-open TCP socket to be "in a connected state". [...] Thus, in general, it cannot be used to reliably learn whether the peer has initiated a graceful shutdown because in most cases (see below) the local TCP state machine remains in CLOSE-WAIT until the local application calls "shutdown" in IO::Socket or close. Only at that point does this function return undef.

(强调我的。)

如果另一端断开连接,recv 将 return 0。因此只需检查 return 由 recv 编辑的值。

while (1) { 
   my $rv = $client->recv(my $received, 64*1024); 
   die($!) if !defined($rv);     # Error occurred when not defined.
   last if $received eq "";      # EOF reached when zero.

   print($received);
}

其他错误修复:上面现在在 print.

之前调用 recv

其他错误修复:删除了无用的睡眠。 recv 如果没有收到任何内容,将阻止。

性能修复:没有理由只要求 1024 字节。如果有任何可用数据,它将被 returned。因此,您不妨要求更多以减少对 recvprint.

的调用次数

请注意,即使使用此解决方案,也不会检测到不正常的断开连接(断电、网络中断等)。可以使用超时或心跳机制来解决这个问题。