套接字消息挂起,直到线程在Perl中完成

时间:2010-09-10 00:02:49

标签: multithreading perl sockets

我正在尝试编写通过Unix套接字进行双向通信的Perl代码。它需要做以下事情:

  1. 客户端代码通过套接字发送请求
  2. 服务器代码读取请求
  3. 服务器执行应立即执行的任何操作
  4. 服务器创建一个新线程以执行可能需要很长时间的其他操作
  5. 服务器通过套接字发送响应
  6. 客户收到回复
  7. 发送回复后新线程继续工作
  8. 我现在已经完成了大部分工作,但有一个问题。步骤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;
    }
    

    当我运行时,会发生以下情况:

    1. 客户端发送“Hello服务器,这是客户端。”
    2. 服务器接收客户端的消息
    3. 服务器创建新线程
    4. 服务器发送“Hello客户端,这是服务器。”
    5. 客户端现在应该收到消息,但事实并非如此。
    6. 服务器上的新线程休眠5秒
    7. 线程退出
    8. 现在客户端收到服务器的消息,即使它是在5秒前发送的。为什么?

1 个答案:

答案 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

您将获得更接近您期望的结果。