Workerman 源码中,主进程关闭端口复用;为啥会让主进程创建mainSocket

meows
        // Get column mapping for UI
        foreach(static::getUiColumns() as $column_name => $prop){
            !isset($worker->{$prop}) && $worker->{$prop} = 'NNNN';
            $prop_length = \strlen($worker->{$prop});
            $key = '_max' . \ucfirst(\strtolower($column_name)) . 'NameLength';
            static::$$key = \max(static::$$key, $prop_length);
        }

        // Listen.
        if (!$worker->reusePort) {
            $worker->listen();
        }

关闭端口复用疑问:
1、“服务端套接字”为什么不直接通过forkWorkersForLinux() 在子进程创建;要在主进程创建“服务端套接字”,通过子进程复制父进程mainSocket 呢?
请问是因为,关闭端口复用情况下;主进程单独监听端口,不会报出“端口被占用错误”?

        // Remove other listener.

foreach(static::$_workers as $key => $one_worker) {
if ($one_worker->workerId !== $worker->workerId) {
$one_worker->unlisten();
unset(static::$_workers[$key]);
}
}

2、创建新的子进程监听服务端口,取消其它“服务端套接字”;这个是什么意思?创建出来的子进程,不应该只复制master的“服务端套接字”,为什么还要unlisten()?

\stream_context_set_option($this->_context, 'socket', 'so_reuseport', 1);

3、reusePort = true , 我即使注释掉上面这个代码,多个子进程未提醒“端口占用问题”。是因为我本地WSL linux 版本高的原因?

            $socket = \socket_import_stream($this->_mainSocket);

\socket_set_option($socket, \SOL_SOCKET, \SO_KEEPALIVE, 1);

4、SO_KEEPALIVE 连接复用,这个配置参数指的是长连接,实际体现是什么样子?

1507 2 0
2个回答

walkor

1、如果没开reusePort,进程A监听某端口后,进程B就无法再监听这个端口,否则会报错address already in use
所以需要主进程监听某个端口,通过fork来实现多个进程监听同一端口

2、主进程为了业务需要可能执行了多个端口监听,主进程fork出子进程后,子进程继承了主进程的监听,其实子进程不需要所有的监听,所以会关闭不需要的监听,只保留一个属于自己的监听

3、WSL没试过,不清楚。一般情况linux系统在没开reusePort的情况下不允许重复监听端口

4、SO_KEEPALIVE 是一个TCP选项,当连接空闲一段时间后TCP底层会发送keepalive报文。SO_KEEPALIVE开启后可以用来检测死连接,避免死连接占用服务器资源。如果把发送keepalive报文间隔缩短,也可以用来tcp保活,防止连接长时间不通讯被路由节点或者防火墙等断开。

  • 暂无评论
meows

4、SO_KEEPALIVE 是一个TCP选项,这个选项我注释掉。

643 138.624632 127.0.0.1 127.0.0.1 TCP 45 [TCP Keep-Alive] 56182 → 19000 [ACK] Seq=7220 Ack=12535 Win=10135 Len=1
516 111.607103 127.0.0.1 127.0.0.1 TCP 44 19000 → 57377 [ACK] Seq=1 Ack=3 Win=10233 Len=0

56182:浏览器客户端端口
19000: Workerman http端口
我注释掉“SO_KEEPALIVE”选项,Wireshark 捕获日志,发现 “TCP Keep-Alive” 来自客户端发出,Workerman 作出回应。这是系统配置默认会出现,还是因为客户端主动发起呢??
“SO_KEEPALIVE”选项生效后,连接处于空闲状态,“TCP Keep-Alive” 数据包是由客户端还是服务器发送出来呢???

            if (! isset($this->_fd[$fd_key])) {
               .....
           } else {
               $fd_val = $this->_fd[$fd_key];
               $res = true;
               if ($flag === self::EV_READ) {
                   if (($fd_val & SWOOLE_EVENT_READ) !== SWOOLE_EVENT_READ) {
                      $res = Event::set($fd, $func, null, SWOOLE_EVENT_READ |  >SWOOLE_EVENT_WRITE);
                       $this->_fd[$fd_key] |= SWOOLE_EVENT_READ;
                   }
               } else {
                   if (($fd_val & SWOOLE_EVENT_WRITE) !== SWOOLE_EVENT_WRITE) {
                       $res = Event::set($fd, null, $func, SWOOLE_EVENT_READ |  >SWOOLE_EVENT_WRITE);
                       $this->_fd[$fd_key] |= SWOOLE_EVENT_WRITE;
                   }
               }
           }

5、Events 命名空间下Swoole 循环事件,\Workerman\Events\EventInterface::add()

请问为什么不直接通过 Swoole\Event::isset(mixed $fd, int $events = SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE): bool ,这种方式判断FD是否已经注册读写事件,然后作出事件“读/写” 修改操作??

  • walkor 2021-10-25

    TCP Keep-Alive 2个端都可以发,SO_KEEPALIVE网上有很详细的说明,可以自行查阅。
    Swoole 循环事件不是我写的,是其他人发的pr,我没仔细研究过

  • meows 2021-10-25

    感谢!

年代过于久远,无法发表回答
🔝