应用程序的目的是侦听特定的UDP多播,然后将数据转发到连接到服务器的任何TCP客户端。代码工作正常,但在TCP客户端断开连接后,我的套接字没有关闭。套接字实用程序实用程序显示套接字保持打开状态,并且所有UDP数据继续转发到客户端。我认为问题在于“if($ write-> connected())”块,因为它总是返回true,即使TCP客户端不再连接。我使用标准的Windows Telnet连接到服务器并查看数据。当我关闭telnet时,TCP套接字假设在服务器上关闭。
为什么connected()将连接显示为活动状态,即使它们不是?另外,我应该使用什么替代方案呢?
代码:
#!/usr/bin/perl
use IO::Socket::Multicast;
use IO::Socket;
use IO::Select;
my $tcp_port = "4550";
my $tcp_socket = IO::Socket::INET->new(
Listen => SOMAXCONN,
LocalAddr => '0.0.0.0',
LocalPort => $tcp_port,
Proto => 'tcp',
ReuseAddr => 1,
);
use Socket qw(IPPROTO_TCP TCP_NODELAY);
setsockopt( $tcp_socket, IPPROTO_TCP, TCP_NODELAY, 1);
use constant GROUP => '239.2.0.81';
use constant PORT => '6550';
my $udp_socket= IO::Socket::Multicast->new(Proto=>'udp',LocalPort=>PORT);
$udp_socket->mcast_add(GROUP) || die "Couldn't set group: $!\n";
my $read_select = IO::Select->new();
my $write_select = IO::Select->new();
$read_select->add($tcp_socket);
$read_select->add($udp_socket);
## Loop forever, reading data from the UDP socket and writing it to the
## TCP socket(s).
while (1) {
## No timeout specified (see docs for IO::Select). This will block until a TCP
## client connects or we have data.
my @read = $read_select->can_read();
foreach my $read (@read) {
if ($read == $tcp_socket) {
## Handle connect from TCP client. Note that UDP connections are
## stateless (no accept necessary)...
my $new_tcp = $read->accept();
$write_select->add($new_tcp);
}
elsif ($read == $udp_socket) {
## Handle data received from UDP socket...
my $recv_buffer;
$udp_socket->recv($recv_buffer, 1024, undef);
## Write the data read from UDP out to the TCP client(s). Again, no
## timeout. This will block until a TCP socket is writable.
my @write = $write_select->can_write();
foreach my $write (@write) {
## Make sure the socket is still connected before writing.
if ($write->connected()) {
$write->send($recv_buffer);
}
else {
$write_select->remove($write);
close $write;
}
}
}
}
}
答案 0 :(得分:5)
我对perl或perl套接字一无所知,但我想不出一个套接字API提供了一种知道套接字是否连接的方法。事实上,我很确定TCP实际上并没有像这样立即知道。这告诉我,connected()并没有告诉你你认为它告诉你什么。 (我不知道,但我敢打赌它告诉你你是否已经打电话给连接/接受)
通常套接字会告诉您它们通过读取或写入零字节而断开连接 - 您可能需要检查写入的返回值以查看它是否返回零
答案 1 :(得分:2)
感谢您的反馈。我找到了一个似乎对我有用的解决方案(感谢斯图尔特)。它就像检查返回值一样简单:
$resultsend = $write->send($recv_buffer);
if (!$resultsend) {
$write_select->remove($write);
close $write;
}
客户端断开连接后,TCP套接字现已关闭。
答案 2 :(得分:1)
IO :: Socket connected方法只是告诉您套接字是否处于连接状态,即在创建套接字后是否在其上调用“connect”。正如斯图尔特所说,没有通用的方法可以判断TCP套接字的另一端是否已关闭,以及您是否“仍处于连接状态”。
答案 3 :(得分:0)
离开我的头顶,试试:
ReuseAddr => 0
我不仅仅确定IO :: Socket的神奇之处在于导致你的问题。