Mojolicious повторное использование ранее установленного соединения
Я пытаюсь повторно использовать ранее установленное соединение веб-сокета, чтобы избежать рукопожатия веб-сокета. Я обнаружил, что пользовательская транзакция websocket может быть построена с использованием build_websocket_tx
(подробнее здесь), и есть идентификатор соединения для каждого соединения через веб-сокет, который можно получить с помощью connection
подпрограмма, определенная в Mojo::Transaction
(подробнее здесь). Могу ли я как-то объединить оба из них, чтобы повторно использовать соединение? Есть ли другой способ сделать это?
PS: соединения Websocket должны быть последовательными и многоразовыми. Но Mojolicoious не предоставляет таких опций для веб-сокетов.
РЕДАКТИРОВАТЬ
Пример кода без повторного использования соединения.
#!/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;
1 ответ
Предварительные условия: для запуска клиентского скрипта Mojolicious с отладочной информацией:
MOJO_EVENTEMITTER_DEBUG=1 MOJO_USERAGENT_DEBUG=1 perl mua.pl
Как и в версии 7.43, Mojo::UserAgent
имеет встроенный пул соединений, но специально отказывается использовать его для WebSockets. Это может быть связано с тем, что, как вы сказали, WebSockets находится в состоянии с состоянием, и если UserAgent слепо повторно использует соединения, это может вызвать хаос. Однако, если ваше приложение знает, как их безопасно использовать, это другое дело.
Этот вопрос недавно возник в канале IRC для Mojolicious, и Шри, автор, сказал:
16:28 sri mohawk: некоторые фреймворки, такие как phoenix, имеют собственный протокол более высокого уровня поверх веб-сокетов для мультиплексирования нескольких каналов https://hexdocs.pm/phoenix/channels.html 16:28 звучит так, как ты и хочешь 16:28 у mojolicious должно быть что-то подобное, но пока нет [...] 16:42 Шри не сложно построить на вершине милосердия, но сейчас вы должны сделать это сами 16:42 в конечном счете, я бы надеялся, что у нас это будет в ядре, без части шины сообщений 16:43 но управление каналом и маршрутизация [...] 16:50 jberger mohawk Я написал Mojolicious::Plugin::Multiplex, который может помочь 16:51 Для примера инструмента более высокого уровня
Я признаю, что ОП сказал:
Единственный способ, которым я смог повторно использовать соединение, - это сохранить объект транзакции и использовать его при последующих вызовах.
Однако, поскольку код в настоящее время, кажется, это единственный путь. Этот код демонстрирует, как создать, поддерживать и использовать свой собственный пул соединений:
#!/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
использует наименее недавно использованное соединение в этом пуле- отправлять сообщение каждые две секунды, регистрируя одноразовый обратный вызов "по сообщению" для обработки ответа
Для простоты он не проверяет, что соединения все еще работают, когда получает их из пула, и использует первую двухсекундную задержку для инициализации всех 5 соединений.
Использование time
звонки демонстрирует увеличение скорости от использования этого пула. Ваш предоставленный код занимает (в моей системе) около 300 мс, чтобы установить соединение, затем отправить и получить. Использование пула занимает около 120 мс.