一般来讲,一个(服务)进程listen了一个端口,如果重复启动,则会报端口被占用的错误,听起来也很合理。突然发现linux上出现了SO_REUSEPORT,似乎多个进程可以同时listen同一个端口。
测试脚本 server.php:
1 2 3 4 5 6 7 8 9 10 |
<?php $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_set_option($socket, SOL_SOCKET, SO_REUSEPORT, 1); socket_bind($socket, "127.0.0.1", 2345); socket_listen($socket); while($s = socket_accept($socket)) { $str = socket_read($s, 2048, PHP_NORMAL_READ); socket_write($s, posix_getpid().":".$str); socket_close($s); } |
注意:
- centos7上如果是yum安装的php,则posix模块的安装方式是: yum install -y php-process (这个名字不叫posix)
- 启动之后,如果用yum安装的nc来测试,会出现连接被refused的情况,这是因为centos7上的nc默认用的是tcp6(socket_create时使用AF_INET6),一个服务确定的是连接的3要素:协议、IP、端口;切记,tcp和tcp6是两种不同的协议 ; 解决办法:添加 -4选项,即: nc -4 localhost 2345
执行:
php server.php &
既然设置了SO_REUSEPORT,则应该可以再启动一个吧?结果,同时启动两个,则两个进程都被stop了
再看: 去掉 ‘&’ 来执行 php server.php ,不放打开多个terminal,我这里打开了两个,发现两个进程都没有再停止了
再打开一个terminal,执行:
while :; do echo “hello”|nc -4 localhost 2345;done
输出里面混杂出现两个进程的pid,证明:两个进程在同时提供服务了;
注意: 即使是多个进程在提供服务,netstat中看到的却只有一个进程在listen
(mac下测试相同脚本,结果是: netstat中可以看到多个进程在listen,但是实际测试却只有一个进程在提供服务,反正我也不同mac来提供线上服务,这里就不研究mac了)
问题: 为什么我这个脚本不能推到后台执行????????
strace 跟踪发现,可能和标准输出有关系(这个应该也是centos7和前面版本的差异),把标准输出重定向走:
php server.php >/dev/null &
这样就不会停止了,之于标准错误、标准输入是否会有其他的影响,这个这里就不再研究了
总结:
SO_REUSEPORT 真心不错
参考资料:
http://www.blogjava.net/yongboy/archive/2015/02/04/422732.html