我在玩Mojolicious和websockets。我想将服务器上多个外部命令的输出发送到网页。我在连接和接收消息方面没有问题,但是我也想将消息发送回服务器以停止外部命令,同时让其他人继续将消息发送回客户端。我也想在退出外部命令后停止检查。

外部命令只是一个单行代码,每几秒钟吐出一个整数。我有两个websocket,分别在div中显示数字。单击任何一个停止按钮都会发送消息,但这是我需要弄清楚如何关闭该websocket(仅该websocket)并关闭外部命令的地方。

perl - 关闭连接到Mojo WebSocket的Mojo::IOLoop重复事件-LMLPHP

当我连接websocket时,我运行外部命令并设置一个Mojo::IOLoop->recurring来检查是否有输出。

当我想停止时,我认为应该调用Mojo::IOLoop->remove($id),但这似乎并不能完全删除它,并且会收到类似Mojo::Reactor::Poll: Timer failed: Can't call method "is_websocket" on an undefined value的错误消息。

如果我在 Controller 对象上调用finish来关闭websocket,似乎一切都停止了。

我有整个Mojolicious::Lite app as a gist,但这是我需要的部分

use feature qw(signatures);
no warnings qw(experimental::signatures);
## other boilerplate redacted

websocket '/find' => sub ( $c ) {
    state $loop = Mojo::IOLoop->singleton;

    app->log->debug( "websocket for find" );
    $c->inactivity_timeout( 50 );

    my $id;
    $c->on( message => sub ( $ws, $message ) {
        my $json = decode_json( $message );
        my $command = $json->{c};
        my $name    = $json->{n};

        app->log->debug( "Got $command command for $name" );
        if( $command eq "start" ) {
            $id = run_command( $ws );
            app->log->debug( "run_command for $name returned [$id]" );
            }
        elsif( $command eq "stop" ) {
            app->log->debug( "stopping loop for $name [$id]" );
            # XXX What should I do here?
            # $ws->finish;
            # $loop->remove( $id );
            }
        elsif( $command eq "open" ) {
            app->log->debug( "opening websocket for $name" );
            }
        }
        );
     $c->on(
        finish => sub ( $c, $code ) {
            app->log->debug("WebSocket closed with status $code");
            }
        );
    };

app->start;

sub run_command ( $ws ) {
    app->log->debug( "In run_command: $ws" );
    open my $fh, "$^X -le '\$|++; while(1) { print int rand(100); sleep 3 }' |";
    $fh->autoflush;

    my $id;
    $id = Mojo::IOLoop->recurring( 1 => sub ($loop) {
        my $m = <$fh>;
        unless( defined $m ) {
            app->log->debug( "Closing down recurring loop from the inside [$id]" );
            # XXX: what should I do here?
            close $fh;
            return;
            };
        chomp $m;
        app->log->debug( "Input [$m] for [$id] from $fh" );
        $ws->send( encode_json( { 'm' => $m } ) );
        });

    return $id;
    }

可能从此答案中受益的其他问题:
  • Output command to socket without buffering using Mojo::IOLoop
  • 最佳答案

    我玩了一下。 Logioniz's answer让我认为我自己不应该轮询或处理文件句柄详细信息。我仍然不知道它卡在哪里。

    相反,我使用Mojo::Reactorio设置了要监视的文件句柄:

    sub run_command ( $ws ) {
        my $pid = open my $fh, "$^X -le '\$|++; print \$\$; while(1) { print int rand(100); sleep 3 }' |";
        $fh->autoflush;
    
        my $reactor = Mojo::IOLoop->singleton->reactor->io(
            $fh => sub ($reactor, $writeable) {
                my $m = <$fh>;
                chomp $m;
                $ws->send( encode_json( { 'm' => $m } ) );
                }
            );
    
        return ( $fh, $pid );
        }
    

    完成该命令后,我可以取消监视该文件句柄并终止进程。我完成了websocket:
        elsif( $command eq "stop" ) {
            $loop->reactor->watch( $fh, 0, 0 );
            kill 'KILL', $pid or app->log->debug( "Could not kill $pid: $!" );
            $ws->finish;
            }
    

    我仍然不知道为什么remove($fh)不起作用。我想我正在以这种方式泄漏一些IOLoop的操作。

    关于perl - 关闭连接到Mojo WebSocket的Mojo::IOLoop重复事件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36673303/

    10-10 16:10