Mojolicious重新使用先前建立的连接

时间:2017-08-04 02:03:09

标签: perl mojolicious mojo

我正在尝试重用以前建立的websocket连接以避免websocket握手。我发现可以使用build_websocket_tx(更多细节here)构建自定义websocket事务,并且每个websocket连接都有一个连接标识符,可以使用connection中定义的子例程来检索它。 1}}(更多细节here)。我可以以某种方式将这两者结合起来重新使用连接吗?还有另一种方法吗?

PS:Websocket连接应该是一致的和可重用的。但是Mojolicoious没有为websocket连接提供任何这样的选择。

修改

没有连接重复使用的示例代码。

Mojo::Transaction

1 个答案:

答案 0 :(得分:2)

预备:使用调试信息运行Mojolicious客户端脚本:

MOJO_EVENTEMITTER_DEBUG=1 MOJO_USERAGENT_DEBUG=1 perl mua.pl

截至7.43版,Mojo::UserAgentbuilt-in connection poolingspecifically refuses to use it for WebSockets。这可能是因为正如你所说,WebSockets是有状态的,如果UserAgent盲目地重用连接,那么可能会导致混乱。但是,如果您的应用程序知道如何安全地重用它们,那就不同了。

最近在Mojolicious的IRC频道中提出了这个问题,sri, the author, said

16:28   sri     mohawk: some frameworks like phoenix have their own higher level protocol on top of websockets to multiplex multiple channels https://hexdocs.pm/phoenix/channels.html
16:28       sounds like that's what you want
16:28       mojolicious should have something like that, but doesn't yet
[...]
16:42   sri     it's not hard to build on top of mojolicious, but for now you have to do that yourself
16:42       ultimately i'd hope for us to have it in core, without the message bus part
16:43       but channel management and routing
[...]
16:50   jberger mohawk I did write Mojolicious::Plugin::Multiplex which might help
16:51       For an example of a higher level tool

我承认OP说:

  

我能够重用连接的唯一方法是存储事务对象并在后续调用中使用它。

但是,正如当前的代码所示,这似乎是唯一的方法。此代码演示了如何创建,维护和使用您自己的连接池:

#!/usr/bin/perl

use strict;
use warnings;
use Mojo::UserAgent;
use Time::HiRes qw(time);
$| = 1;
my $REQ = {
    type => "ping",
    reqid => 0,
};
my $URL = "wss://trello.com/1/Session/socket";
my $SECONDS = 2;
my $POOL_SIZE = 5;

my $ua = Mojo::UserAgent->new;
my @pool;

sub make_conn {
  my ($ua, $url, $pool) = @_;
  $ua->websocket($URL => sub {
    my (undef, $tx) = @_;
    die "error: ", $tx->res->error->{message}, "\n" if $tx->res->error;
    die 'Not a websocket connection' unless $tx->is_websocket;
    push @$pool, $tx;
  });
}

# pool gets pushed onto, shifted off, so using recently-used connection
sub send_message {
  my ($pool, $request, $start) = @_;
  my $tx = shift @$pool;
  die "got bad connection" unless $tx; # error checking needs improving
  $tx->once(message => sub {
    my (undef, $msg) = @_;
    print "got back: $msg\n";
print "took: ", time - $start, "\n";
    push @$pool, $tx;
  });
  $tx->send({json => $request});
}

make_conn($ua, $URL, \@pool) for (1..5); # establish pool

# every 2 secs, send a message
my $timer_cb;
$timer_cb = sub {
  my $loop = shift;
  print "every $SECONDS\n";
  send_message(\@pool, $REQ, time);
  $loop->timer($SECONDS => $timer_cb);
};
Mojo::IOLoop->timer($SECONDS => $timer_cb);

Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

在高层次上,它的工作原理如下:

  • 在泳池中建立5个连接
  • send_message使用该池中最近最少使用的连接
  • 每两秒发送一条消息,注册一次性“on message”回调以处理响应

为了简单起见,它不检查连接从池中获取时是否仍然有效,并依赖于前两秒延迟来初始化所有5个连接。

time调用的使用证明了使用此池的速度提升。您提供的代码(在我的系统上)大约需要300毫秒来启动连接,然后发送和接收。使用游泳池需要大约120毫秒。