自定义主循环中Net::Async::WebSocket::Server连接失败求助
自定义主循环下Net::Async::WebSocket::Server无法建立连接的问题
我希望实现一个由自定义主循环而非IO::Async::Loop控制的WebSocket服务器,代码如下:
my $sslSocket = IO::Socket::SSL->new( Listen => 5, LocalPort => XXX, Proto => 'tcp', SSL_startHandshake => 0, SSL_cert_file => 'XXX', SSL_key_file => 'XXX', ) or die "failed to listen: $!"; my $server = Net::Async::WebSocket::Server->new( on_client => sub { my ( undef, $client ) = @_; $client->configure( on_text_frame => sub { my ( $self, $frame ) = @_; $self->send_text_frame( $frame ); }, ); }, on_handshake => sub { my ( $self, $client, $hs, $continue ) = @_; $continue->( 1 ); } ); my $loop = IO::Async::Loop->new; $loop->add( $server ); $server->listen( handle => $sslSocket )->get;
我在自定义主循环中,仅当监听套接字$sslSocket有数据可读时才调用$loop->loop_once,代码如下:
while(1){ # something before if (//data to read) { $loop->loop_once; } # something after }
但WebSocket连接始终无法建立,所有回调函数都未被触发。我猜测自己误解了loop_once的用途,但不清楚具体问题所在。我尝试过使用$loop->run方法,此时连接可以正常建立,但这不符合我的需求。期望实现的效果是:调用loop_once时,WebSocket服务器能处理待处理的请求。
问题原因
你的自定义循环只关注监听套接字$sslSocket的可读事件,但WebSocket连接的建立过程远不止这一步:
- 客户端发起TCP连接后,会生成新的客户端套接字;
- 后续需要完成SSL握手、HTTP升级到WebSocket的握手流程;
- 这些步骤都依赖新客户端套接字的读写事件,而你的循环完全没处理这些事件,导致握手流程卡壳,回调自然不会触发。
loop_once的作用是处理当前loop中所有已就绪的事件,但前提是你得让loop知道哪些事件已经就绪——而你只给了它监听套接字的事件,漏掉了其他关键事件。
解决办法
不要手动判断单个套接字的状态,而是让IO::Async::Loop自己管理所有需要监听的文件描述符,修改自定义循环如下:
while (1) { # something before # 获取当前loop需要监听的所有文件描述符集合 my ( $read_fds, $write_fds, $except_fds ) = $loop->pre_wait; # 等待事件发生,这里设置0.1秒超时(可根据需求调整) my $nfound = select( $read_fds, $write_fds, $except_fds, 0.1 ); if ($nfound > 0) { # 处理所有已就绪的事件 $loop->loop_once; } # something after }
关键说明
$loop->pre_wait:返回当前loop中所有注册的文件描述符(包括监听套接字、已建立的客户端套接字等)的读、写、异常事件集合;select:等待这些集合中的任意事件发生,确保不会漏掉任何关键步骤;- 只有当有事件就绪时调用
loop_once,既满足自定义循环的控制权需求,又能让WebSocket服务器完整处理连接建立和消息交互的所有流程。
内容的提问来源于stack exchange,提问作者Talkabout
相关产品推荐
相关产品推荐

