我正在玩Mojolicious和websockets。我想将服务器上多个外部命令的输出发送到网页。我没有连接和接收消息的问题,但我也想将消息发送回服务器以停止外部命令,同时让其他人继续将消息发送回客户端。我还希望一旦退出就停止检查外部命令。
外部命令只是一个单行程序,每隔几秒就会发出一个整数。我有两个websockets,在单独的div
s中显示数字。单击任一停止按钮会发送消息,但是我需要弄清楚如何关闭该websocket(并且只关闭websocket)并关闭外部命令。
当我连接websocket时,我运行外部命令并设置Mojo::IOLoop->recurring
以检查是否有输出。
当我想要停止时,我认为我应该拨打Mojo::IOLoop->remove($id)
,但这似乎并没有完全删除它,我收到了Mojo::Reactor::Poll: Timer failed: Can't call method "is_websocket" on an undefined value
等错误消息。
如果我在控制器对象上调用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;
}
可能从这个答案中受益的其他问题:
答案 0 :(得分:1)
我玩了一下这个。 Logioniz's answer让我觉得我自己不应该轮询或处理文件句柄细节。我还是不知道它挂在哪里。
相反,我使用Mojo::Reactor&#39; io
来设置要监控的文件句柄:
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的东西。
答案 1 :(得分:0)