我正在尝试编写通过Unix套接字进行双向通信的Perl代码。它需要做以下事情:
我现在已经完成了大部分工作,但有一个问题。步骤1 - 5工作正常,但在步骤6,客户端无法读取响应,直到线程退出。 (即使响应立即发送或多或少)我知道我做错了什么?
我在Ubuntu Lucid上使用Perl 5.10.1。
以下是一个例子:
客户代码:
#!/usr/bin/perl
use strict;
use Socket;
my $socket_name = 'catsock';
my $client_message = "Hello server, this is the client.";
my $SOCK;
socket($SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
connect($SOCK, sockaddr_un($socket_name)) or die "connect: $!";
$| = 1, select $_ for select $SOCK; # turn on autoflush
print $SOCK $client_message; # send the message
shutdown($SOCK,1); # finished writing
print "sent: $client_message\n";
my $server_message = do { local $/; <$SOCK> }; # get the response
print "recieved: $server_message\n\n";
服务器代码
#!/usr/bin/perl
use strict;
use Socket;
use threads;
use threads::shared;
sub threadfunc
{
print " waiting 5 seconds in new thread...\n";
sleep(5);
print " exiting thread...\n\n";
}
my $server_message = "Hello client, this is the server.";
my $socket_name = 'catsock';
my $SERVER;
my $CLIENT;
socket($SERVER, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
unlink($socket_name);
bind($SERVER, sockaddr_un($socket_name)) or die "bind: $!";
chmod(0660, $socket_name);
listen($SERVER, SOMAXCONN) or die "listen: $!";
print "server started on $socket_name\n\n";
while(1) {
accept($CLIENT, $SERVER);
my $client_message = do { local $/; <$CLIENT> }; # grab entire message
print "recieved: $client_message\n";
print "creating new thread...\n";
my $thr = threads->create(\&threadfunc);
$thr->detach();
print $CLIENT $server_message; # send the response
print "sent: $server_message\n\n";
close $CLIENT;
}
当我运行时,会发生以下情况:
答案 0 :(得分:3)
my $server_message = do { local $/; <$SOCK> }
客户端脚本中的对我来说很有趣。通过将$/
设置为undef
,您要求<$SOCK>
语句从句柄$SOCK
读取所有输入,直到文件结束。在此上下文中,文件结尾表示套接字的另一端已关闭连接。
服务器正在传递消息,您可以看到是否将上面的行更改为
print "Received message: ";
print while $_ = getc($SOCK);
(当输入流耗尽时,这也会挂起5秒,但在此期间它至少会显示输入中的每个字符。)
这是一个“功能”,TCP套接字连接的一端永远不会真正知道连接的另一端是否仍然存在。网络程序员采用其他约定 - 在每条消息的开头编码消息长度,用特殊标记结束每条消息,实现心跳 - 确定可以安全地从套接字读取多少输入(您可能还希望看到进入select
)的4参数版本
对于这个问题,一种可能性是应用以下约定:来自服务器的所有消息都应以换行结束。将服务器脚本更改为
print $CLIENT $server_message, "\n";
并将客户端脚本更改为
my $server_message = do { local $/="\n"; <$SOCK> }; # if you're paranoid about $/ setting
my $server_message = <$SOCK>; # if you're not
您将获得更接近您期望的结果。