无法检测到与 $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。因此,您不妨要求更多以减少对 recv
和 print
.
的调用次数
请注意,即使使用此解决方案,也不会检测到不正常的断开连接(断电、网络中断等)。可以使用超时或心跳机制来解决这个问题。
我正在尝试 - 但失败了 - 让 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。因此,您不妨要求更多以减少对 recv
和 print
.
请注意,即使使用此解决方案,也不会检测到不正常的断开连接(断电、网络中断等)。可以使用超时或心跳机制来解决这个问题。