Perl: разветвление соединения WSS приводит к закрытию сокета при выходе из дочернего процесса (не происходит с WS) - PullRequest
0 голосов
/ 05 октября 2018

(отредактировано для предоставления сокращенного тестового примера согласно комментариям ниже)

Я сталкиваюсь со странной ситуацией, когда, если я разветвляюсь на соединение "WSS", чтобы отправить сообщение, сокет закрывается, когдаребенок выходит.Тем не менее, когда я выполняю разветвление для обработки соединения «WS», соединение остается открытым при выходе из дочернего процесса.

  • Сведения о сервере: Perl 5.26, Ubuntu 16
  • Сведения о клиенте: Perl 5.18, OSX

Код сервера:

use Net::WebSocket::Server;
use IO::Socket::SSL;

$SIG{CHLD}='IGNORE';

my $enable_ssl = 1; # If you make this one the problem reveals itself

# you need to point this to your own certs
my $ssl_cert_file =  "/etc/letsencrypt/live/mydomain/fullchain.pem";
my $ssl_key_file =  "/etc/letsencrypt/live/mydomain/privkey.pem";

# To show the problem, all I'm doing is I'm forking and sending current time
sub process {
    my $serv = shift;
    my $pid = fork();
    if ($pid == 0 ) {
        print ("fork start\n");
        $_->send_utf8(time) for $serv->connections;
        print ("fork end\n");
        exit 0;
    }
}

my $ssl_server;

if ($ssl_enable) {
$ssl_server = IO::Socket::SSL->new(
              Listen        => 10,
              LocalPort     => 9000,
              Proto         => 'tcp',
              Reuse     => 1,
              ReuseAddr     => 1,
              SSL_cert_file => $ssl_cert_file,
              SSL_key_file  => $ssl_key_file
            );
 }

Net::WebSocket::Server->new(
    listen => $enable_ssl? $ssl_server: 9000,
    tick_period=>5,
    on_tick=> sub {
        my ($serv) = @_;
        process($serv);
        #$_->send_utf8(time) for $serv->connections;
    },
 )->start;

Вот код клиента:

my $client = AnyEvent::WebSocket::Client->new;

# replace with your server
$client->connect("wss://myserver:9000")->cb(sub {
  our $connection = eval { shift->recv };
  if($@) {
    print ("connection error");
    warn $@;
    return;
  }

  # recieve message from the websocket...
  $connection->on(each_message => sub {
    my($connection, $message) = @_;
    my $msg = $message->body;
    print ("GOT $msg\n");
  });


});

AnyEvent->condvar->recv;

Ожидаемое поведение

Клиент будет продолжать отображать метки времени

Наблюдаемое поведение

Клиент получает самое первое сообщение и печатает его.Когда сервер выходит из своего форка, клиент перестает получать больше сообщений, и соединение прерывается

Как заставить его работать

У нас есть два варианта:

  1. Не подключайтесь к серверу.Отправьте сообщение непосредственно в процесс sub
  2. Не используйте SSL

Поэтому я пришел к выводу, что SSL + fork == problem.

Мысли?

1 Ответ

0 голосов
/ 05 октября 2018

Поэтому я пришел к выводу, что проблема SSL + fork ==.

Да, проблема в том, что сначала выполняется SSL-рукопожатие, а затем разветвление.Таким образом, состояние SSL пространства пользователя будет создано в родительском объекте, а ветвь дублирована в дочернем элементе, и эти два состояния SSL будут синхронизированы при первой отправке или получении данных SSL.Это означает, что невозможно работать с одним и тем же сокетом SSL от двух процессов.

Если действительно необходимо, чтобы и родительский, и дочерний процессы использовали одно и то же соединение SSL с одноранговым узлом, чем дочерний процесс должен использовать родительский как«прокси-сервер», то есть дочерний элемент не связывается напрямую с одноранговым узлом SSL, но дочерний элемент должен обмениваться данными с родителем в обычном режиме (например, с помощью пары сокетов), который затем может переслать сообщение одноранговому узлу SSL.Таким образом, состояние SSL поддерживается только в родительском процессе.

Но с учетом того, что для одного соединения одновременно должна обрабатываться только одно сообщение, вместо этого может быть возможно не форк для одного тика, а форкдочерний элемент для каждого соединения, которое обрабатывает все сообщения в этом соединении.В этом случае рукопожатие SSL можно полностью выполнить в дочернем процессе, прослушивая у родителя TCP-сокет, а не сокет SSL, разветвляя on_connect, а затем обновляя соединение до SSL в клиенте, используя IO::Socket::start_SSL.Это также имело бы преимущество в том, что блокирующее рукопожатие SSL (которое включает несколько циклов и, следовательно, занимает некоторое время) будет выполнено в разветвленном дочернем элементе и не создаст родительский блок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...