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

Multithreading 套接字消息将挂起,直到Perl中的线程完成,multithreading,perl,sockets,Multithreading,Perl,Sockets,我正在尝试编写通过Unix套接字进行双向通信的Perl代码。它需要做以下几件事: 客户端代码通过套接字发送请求 服务器代码读取请求 服务器执行任何应该立即执行的操作 服务器创建一个新线程来执行可能需要很长时间的附加操作 服务器通过套接字发送响应 客户端收到响应 新线程在发送响应后继续工作 我现在已经把大部分工作做好了,但有一个问题。步骤1-5可以正常工作,但是在步骤6,客户端在线程退出之前无法读取响应。(尽管回复或多或少是立即发出的)你知道我做错了什么吗 我在Ubuntu Lucid上使用Per

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

  • 客户端代码通过套接字发送请求
  • 服务器代码读取请求
  • 服务器执行任何应该立即执行的操作
  • 服务器创建一个新线程来执行可能需要很长时间的附加操作
  • 服务器通过套接字发送响应
  • 客户端收到响应
  • 新线程在发送响应后继续工作
  • 我现在已经把大部分工作做好了,但有一个问题。步骤1-5可以正常工作,但是在步骤6,客户端在线程退出之前无法读取响应。(尽管回复或多或少是立即发出的)你知道我做错了什么吗

    我在Ubuntu Lucid上使用Perl5.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
    严格使用;
    使用插座;
    我的$socket_name='catsock';
    my$client\u message=“你好,服务器,这是客户端。”;
    我的$SOCK;
    socket($SOCK,PF_UNIX,SOCK_STREAM,0)或die“socket:$!”;
    连接($SOCK,sockaddr_un($socket_name))或死“连接:$!”;
    $|=1,选择$作为选择$SOCK;#启用自动刷新
    打印$SOCK$client_消息;#发送消息
    关闭($SOCK,1)#写完
    打印“已发送:$client\u消息\n”;
    我的$server_message=do{local$/;};#得到回应
    打印“已接收:$server\u消息\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;
    }
    
    #/usr/bin/perl
    严格使用;
    使用插座;
    使用线程;
    使用线程::共享;
    子线程函数
    {
    打印“在新线程中等待5秒…\n”;
    睡眠(5);
    打印“正在退出线程…\n\n”;
    }
    my$server\u message=“你好,客户端,这是服务器。”;
    我的$socket_name='catsock';
    我的$SERVER;
    我的客户;
    socket($SERVER,PF_UNIX,SOCK_STREAM,0)或die“socket:$!”;
    取消链接($socket\u name);
    绑定($SERVER,sockaddr\u un($socket\u name))或死“绑定:$!”;
    chmod(0660,$socket_name);
    监听($SERVER,SOMAXCONN)或死掉“监听:$!”;
    打印“服务器在$socket\u name上启动\n\n”;
    而(1){
    接受($CLIENT,$SERVER);
    my$client_message=do{local$/;};#获取整个消息
    打印“已接收:$client\u消息\n”;
    打印“创建新线程…\n”;
    my$thr=threads->create(\&threadfunc);
    $thr->detach();
    打印$CLIENT$server_消息;#发送响应
    打印“已发送:$server\u消息\n\n”;
    关闭$CLIENT;
    }
    
    当我运行此程序时,会发生以下情况:

  • 客户端发送“你好,服务器,这是客户端。”
  • 服务器接收客户端的消息
  • 服务器创建一个新线程
  • 服务器发送“你好客户端,这是服务器。”
  • 客户端现在应该收到消息,但它没有
  • 服务器上的新线程休眠5秒
  • 线程出口
  • 现在,客户端接收服务器的消息,即使它是在5秒钟前发送的。为什么?
  • (当输入流耗尽时,此选项也将挂起5秒钟,但同时至少会显示输入中的每个字符)

    TCP套接字连接的一端永远无法真正知道连接的另一端是否仍处于活动状态,这是一个“特性”。网络程序员求助于其他约定——在每条消息的开头对消息长度进行编码,在每条消息的结尾使用特殊标记,实现心跳——以确定可以从套接字安全读取多少输入(您可能还需要查看的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
    
    并将客户端脚本更改为

    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
    
    my$server\u message=do{local$/=“\n”;}如果您对$/设置有疑心
    我的$server_消息=;#如果你不是
    
    你会得到更接近你期望的结果

    (当输入流耗尽时,此选项也将挂起5秒钟,但同时至少会显示输入中的每个字符)

    TCP套接字连接的一端永远无法真正知道连接的另一端是否仍处于活动状态,这是一个“特性”。网络程序员求助于其他约定——在每条消息的开头对消息长度进行编码,在每条消息的结尾使用特殊标记,实现心跳——以确定可以从套接字安全读取多少输入(您可能还需要查看的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
    
    并将客户端脚本更改为

    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
    
    my$server\u message=do{local$/=“\n”;}如果您对$/设置有疑心
    我的$server_消息=;#如果你不是
    

    您将得到更接近预期的结果。

    在接受后将
    $CLIENT
    设置为自动刷新?是否可能是服务器线程在$thread->detach方法中阻塞,因此在工作线程退出之前,$CLIENT上的写操作不会执行?@feroze-额外的线程将连接保持打开状态5秒钟(虽然我不确定确切的方式--线程有一个
    $CLIENT
    的私有副本,并且在所有副本都超出范围之前连接可能不会关闭),但它不会延迟写入
    $CLIENT
    .print$CLIENT“$server\u message\n”?#wild guessset
    $CLIENT
    在接受后自动刷新?是否可能是服务器线程在$thread->detach方法中阻塞,因此在工作线程退出之前,$CLIENT上的写操作不会执行?@feroze-额外的线程将连接保持打开状态5秒钟(虽然我不确定具体是如何实现的——线程有一个
    $CLIENT
    的私有副本,而连接没有c。)