通过 fork 创建子进程的方式可以实现父子进程监听相同的端口。

方法:在绑定端口号(bind函数)之后,监听端口号之前(listen函数),用fork()函数生成子进程,这样子进程就可以克隆父进程,达到监听同一个端口的目的。

# 代码示例:一主一子
import socket
import select
import sys
import struct
import os
import time if __name__ == '__main__':
pid = os.getpid()
s1 = socket.socket() # 创建 socket 对象
# host = socket.gethostname() # 获取本地主机名
host = '127.0.0.1'
port1 = 12346 # 设置端口号
# port2 = 12347 # --关键代码--
s1.bind((host, port1))
pid1 = os.fork() print("我会被主子进程分别执行一次")
# 也可以分别写到分子进程里
s1.listen(5)
# --关键代码-- while True:
if pid1 == 0:
# s1.listen(5)
print("子进程")
socket1, addr1 = s1.accept()
print(addr1)
socket1.send("子进程响应".encode('utf-8'))
socket1.close()
print('结束服务端子进程')
else:
# s1.listen(5)
print("主进程")
socket2, addr2=s1.accept()
print(addr2)
socket2.send("主进程响应".encode('utf-8'))
socket2.close()
print('结束服务端主进程') # 代码示例:一主多子
import socket
import select
import sys
import struct
import os
import time if __name__ == '__main__':
pid = os.getpid()
s1 = socket.socket() # 创建 socket 对象
# host = socket.gethostname() # 获取本地主机名
host = '127.0.0.1'
port1 = 12346 # 设置端口号
# port2 = 12347
s1.bind((host, port1))
pid1 = os.fork()
# s1.listen(5)
print("我会被主子进程分别执行一次")
while True:
if pid1 == 0:
s1.listen(5)
print("子进程1")
socket1, addr1 = s1.accept()
print(addr1)
socket1.send("子进程响应1".encode('utf-8'))
socket1.close()
print('结束服务端子进程1')
elif pid1 != 0:
pid2 = os.fork()
if pid2 == 0:
s1.listen(5)
print("子进程2")
socket2, addr2 = s1.accept()
print(addr2)
socket2.send("子进程响应2".encode('utf-8'))
socket2.close()
print('结束服务端子进程2')
else:
s1.listen(5)
print("主进程")
socket2, addr2 = s1.accept()
print(addr2)
socket2.send("主进程响应".encode('utf-8'))
socket2.close()
print('结束服务端主进程') # 试想下子进程还有子进程的写法和用法

惊群现象

当连接到来时,子进程、父进程都可以 accept, 这就是著名的“惊群”问题(thundering herd problem)。

在该模型下(多个子进程同时共享监听套接字)即可实现服务器并发处理客户端的连接。这里要注意的是,计算机三次握手创建连接是在内核进程里完成的,不需要应用服务进程参数的,而服务进程仅仅要做的是调用accept将已建立的连接构建对应的连接套接字connfd(可参考 http://blog.csdn.net/ordeder/article/details/21551567)。多个服务进程同时阻塞在accept等待监听套接字已建立连接的信息,那么当内核在该监听套接字上建立一个连接,那么将同时唤起这些处于accept阻塞的服务进程,从而导致“惊群现象”的产生,唤起多余的进程将影响服务器的性能(仅有一个服务进程accept成功,其他进程被唤起后没抢到“连接”而再次进入休眠)。

应用多进程多线程模型

一直疑惑一个应用app如何才能以多进程,多线程的方式运行。对于多线程可能很好理解,我们只要在进程中启用多线程的模式即可。也就是来一个请求,我们就用函数pthread_create()启用一个线程即可。这样我们的应用就可以在单进程,多线程的模式下工作。

一个应用app通常工作在多进程,多线程的模式下,它的效率是最高的。那么我们如何才能做到多进程模式呢?经验告诉我们,如果多次启动一个进程会报错:“Address already in use!"。这是由于bind函数导致的,由于该端口号已经被监听了。

fork原理

fork时,子进程复制一份父进程的资源。然后父子进程分别执行os.fork()之后的程序

子进程中fork函数返回0,父进程中返回子进程的pid

Python的os.fork()是一个会返回两次的函数

https://www.cnblogs.com/Magic-Dev/p/11405448.html

通过linux内核的SO_REUSEPORT选项实现多个进程监听相同的端口

# reuseport.py代码

import socket
import os
#xiaorui.cc
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s.bind(('0.0.0.0', 1234))
s.listen(1) while True:
conn, addr = s.accept()
print('Connected to {}'.format(os.getpid()))
data = conn.recv(1024)
conn.send(data)
conn.send(str(os.getpid()))
conn.close() # 启动多个进程
nohup python reuseport.py &
nohup python reuseport.py &
nohup python reuseport.py & # 使用nc测试,可以得到随机的一个进程响应
echo "xiaorui" | nc localhost 1234 # 使用socat(nc的增强版)测试,可以得到随机的一个进程响应
echo "ss" | socat - tcp-connect:localhost:1234

http://xiaorui.cc/2015/12/02/使用socket-so_reuseport提高服务端性能/

https://www.jianshu.com/p/7e84a33b46e9

linux系统实现多个进程监听同一个端口的更多相关文章

  1. linux 系统下开机自动启动oracle 监听和实例 (亲测有效)

    [oracle@oracle11g ~]$ dbstartORACLE_HOME_LISTNER is not SET, unable to auto-start Oracle Net Listene ...

  2. linux: 获取监听指定端口的进程PID

    在 linux 下经常需要杀死(重启)监听某端口的进程, 因此就写了一个小脚本, 通过 ss 命令获取监听制定端口的进程 PID, 然后通过 kill 命令结束掉进程: #!/bin/sh # set ...

  3. [Linux] 多进程网络编程监听一个端口

    SO_REUSEPORT支持多个进程或者线程绑定到同一端口 每个进程可以自己创建socket.bind.listen.accept相同的地址和端口,各自是独立平等的.让多进程监听同一个端口,各个进程中 ...

  4. linux系统中,查看当前系统中,都在监听哪些端口

    需求描述: 查看当前系统中都监听着哪些的端口,用netstat命令,在此记录下 操作过程: 1.查看系统中都在监听哪些端口 [root@testvm home]# netstat -ntl Activ ...

  5. Linux中安装Oracle11g后出现监听的问题及解决办法

    软件安装: 参考文章: linux安装Oracle11G 错误如下: [oracle@iz2f570bi1k56uz admin]$ lsnrctl start LSNRCTL for Linux: ...

  6. Linux下启动Oracle服务和监听程序步骤

    Linux下启动Oracle服务和监听程序启动和关闭步骤整理如下: 1.安装oracle: 2.创建oracle系统用户: 3./home/oracle下面的.bash_profile添加几个环境变量 ...

  7. Linux下的启动oracle服务 启动监听 开放端口操作

    尝试登录oracle 使用root用户将没有sqlplus命令 [root@localhost ~]# sqlplus /nolog bash: sqlplus: 未找到命令...     [root ...

  8. 获取Windows下某进程监听的TCP/UDP端口

    1.在Windows下用CMD netstat命令可以获得当前进程监听端口号的信息,如netstat -ano可以看到IP.port.状态和监听的PID. 那么可以执行CMD这个进程得到监听的端口号信 ...

  9. Linux 使用NC命令永久监听本地端口

    感谢: 冰点阳光 Linux可以使用nc命令来测试网络端口是否正常,类似于telnet命令,但也可以用nc命令来监听本地端口,支持TCP.UDP协议,当我们测试NTP服务网络策略是否正常时,可以使用到 ...

随机推荐

  1. 浏览器在线预览pdf、txt、office文件

    //使用文件预览的原因是:TMD微信浏览器屏蔽掉文件下载链接,只好折中使用文件在线预览功能//要点:1.office文件用微软的插件打开 http://view.officeapps.live.com ...

  2. saltstack 发布 iis 站点

    Saltstack 发布 iis 站点 saltstack 主服务器配置:切换到 salt 的主目录下 : 主目录示例:/home/salt 程序集放置目录: web/web1 sls 目录: web ...

  3. Open Judge 1.4 09

    09:判断能否被3,5,7整除 总时间限制:  1000ms 内存限制:  65536kB 描述 给定一个整数,判断它能否被3,5,7整除,并输出以下信息:1.能同时被3,5,7整除(直接输出3 5 ...

  4. Django系列目录

    一:搭建自己的博客系列  搭建自己的博客(一):前期准备  搭建自己的博客(二):创建表,创建超级用户  搭建自己的博客(三):简单搭建首页和详情页 搭建自己的博客(四):优化首页和详情页 搭建自己的 ...

  5. AtCoder Grand Contest 009 题解

    传送门 为啥这场题目少一点啊-- \(A\) 易知增加的数前面肯定比后面大,那么我们倒着做,然后维护一下最小要加多少就可以了 typedef long long ll; const int N=1e5 ...

  6. opendir,readdir,closedir

     结构体dirent: struct dirent { ino_t d_ino; //inode number off_t d_off; //offset to the next diret unsi ...

  7. mac 安装 pycharm

    下载安装 链接:https://pan.baidu.com/s/19Hm6yZPL_mOTVAb5YQBZKA 密码:j73n 激活码 56ZS5PQ1RF-eyJsaWNlbnNlSWQiOiI1N ...

  8. css自定义属性和简单效果

    简介 CSS Variables,一个并不是那么新的东西,但对css来说绝对是一场革命. 之前使用变量的时候,需要借助sass.less等预处理工具来实现,现在我们可以直接使用css来声明变量. 兼容 ...

  9. SpaceClaim脚本功能(Beta功能)

    本操作仅适用ANSYS SpaceClaim 2016 打开SpaceClaim脚本编辑器的方法有两种 方法一(看截图操作):         方法二(请见后面的实例操作). 创建球体源代码: #定义 ...

  10. 使用Xpose突破安卓App禁止截屏限制

    WindowManager.LayoutParams.FLAG_SECURE标志的app,这里需要注意下支付宝.网上银行类的app不建议拦截,像支付宝里的付款码,商家拿到后,直接就能扣费,不需要用户这 ...