Python 3.8.12 UDP套接字SO_REUSEPORT未实现数据包分发问题(Linux 3.10)
问题原因及解决办法
问题原因
CentOS 7使用的3.10内核中,SO_REUSEPORT的UDP数据包分发逻辑是基于源IP地址+源端口的哈希值来选择目标套接字。你的客户端代码固定绑定了本地端口21111,每次发送的数据包源IP(127.0.0.1)和源端口(21111)完全一致,哈希结果固定,导致所有数据包都被分发到第一个启动的服务端套接字,第二个服务端自然收不到任何数据。
解决办法
方案1:客户端不固定本地端口(推荐)
修改客户端代码,去掉手动绑定本地端口的逻辑,让系统自动分配随机源端口。这样每次客户端发送的数据包源端口不同,哈希结果会变化,内核就能将数据包均衡分发到两个服务端。
修改后的echo_client.py:
import socket serverAddressPort = ("127.0.0.1", 20001) bufferSize = 1024 cnt = 0 try: # Create a UDP socket at client side UDPClientSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM) UDPClientSocket.sendto(f'Hello server: {cnt}'.encode(), serverAddressPort) cnt += 1 except Exception as e: print(f'An exception occurred {e}') print('close client, bye !') UDPClientSocket.close()
方案2:保持客户端固定端口,调整服务端绑定(可选)
如果业务必须固定客户端端口,可以尝试让服务端绑定0.0.0.0而非127.0.0.1,部分场景下能触发更均衡的分发逻辑,但效果不如方案1稳定。
修改服务端的绑定代码:
UDPServerSocket.bind(("0.0.0.0", localPort))
补充说明
Linux 3.10内核的SO_REUSEPORT属于早期实现,后续内核版本(如4.1+)对UDP的负载均衡逻辑做了优化,支持更灵活的分发策略。如果条件允许,升级内核到更高版本也能解决此问题。
内容的提问来源于stack exchange,提问作者Victor Windy
相关产品推荐
相关产品推荐

