【问题标题】:Mojolicious re-using a previously established connectionMojolicious 重用先前建立的连接
【发布时间】:2018-01-11 19:47:16
【问题描述】:

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

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

编辑

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

#!/usr/bin/perl

use strict;
use warnings;

use Mojo::UserAgent;
use JSON qw |encode_json|;

my $ua = Mojo::UserAgent->new;
my $url = "wss://trello.com/1/Session/socket";

$| = 1;

sub _connect {
    my $req = {
        type => "ping",
        reqid=> 0
    };
    $ua->websocket(
        $url => sub {
            my ($ua, $tx) = @_;

            die "error: ", $tx->res->error->{message}, "\n" if $tx->res->error;
            die 'Not a websocket connection' unless $tx->is_websocket;

            # Connection established.
            $tx->on(
                message => sub {
                    my ($tx, $msg) = @_;
                    print "$msg\n";
                    $tx->closed; #Close connection
                });
            $tx->send(encode_json($req));
        });
}

sub reuse_conn {
    # Re use connection
}

_connect();

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

【问题讨论】:

  • 你想通过'重用'连接来完成什么?
  • @Сухой27 因为 websocket 是一个有状态的协议。我想跟踪所有已经授权的 websocket 连接,这样我就不必为每个客户端请求一次又一次地重新授权每个连接的开销。这对您来说可能没有意义,但它需要克服一次又一次重新发送相同请求的大量开销。
  • 我不确定我的理解是否正确,但是一旦您建立了客户端连接并设置了事件处理程序,您就可以使用此连接,直到网络出现故障或另一方将其关闭。此时您必须启动新的客户端连接。 “重用”不太适合这种方案。
  • @Сухой27 实际上,您做对了。考虑整个过程是异步的,假设连接已经建立,一段时间后用户发送另一个请求,我想做的是使用之前建立的连接(如果它没有关闭),而不是为每个请求创建一个新连接用户制作的。我们为用户发送的每个请求都创建一个连接听起来不是错的吗?至少在 websocket 的上下文中是这样。 Websockets 连接应该是持久的和可重用的。
  • @Ed。我添加了不重用连接的代码 sn-p。我能够重用连接的唯一方法是存储事务对象并在后续调用中使用它。

标签: perl mojolicious mojo


【解决方案1】:

预备:运行带有调试信息的 Mojolicious 客户端脚本:

MOJO_EVENTEMITTER_DEBUG=1 MOJO_USERAGENT_DEBUG=1 perl mua.pl

在版本 7.43 中,Mojo::UserAgent 具有 built-in connection poolingspecifically refuses to use it for WebSockets。这很可能是因为正如您所说,WebSockets 是有状态的,如果 UserAgent 盲目地重用连接,那可能会导致混乱。但是,如果您的应用程序知道如何安全地重用它们,那就另当别论了。

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

16:28 sri mohawk:一些框架,如 phoenix,在 websockets 之上有自己的更高级别的协议来多路复用多个通道 https://hexdocs.pm/phoenix/channels.html 16:28 听起来这就是你想要的 16:28 mojolicious 应该有类似的东西,但还没有 [...] 16:42 sri 建立在 mojolicious 之上并不难,但现在你必须自己做 16:42 最终我希望我们将它放在核心中,没有消息总线部分 16:43 但频道管理和路由 [...] 16:50 jberger mohawk 我确实写了 Mojolicious::Plugin::Multiplex 这可能会有所帮助 16:51 更高级别工具的示例

我承认 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 毫秒。

【讨论】:

  • 感谢您的详尽回答。但我已经意识到这一点。您附加的两个代码参考可能对未来的研究有所帮助。
  • 我已经添加了 jberger 关于metacpan.org/pod/Mojolicious::Plugin::Multiplex 的注释,这也可能有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-03
  • 2016-05-04
  • 1970-01-01
  • 2011-05-29
  • 2017-12-23
相关资源
最近更新 更多