SO_REUSEPORT可以在Unix域套接字上使用吗?

10 投票
2 回答
4139 浏览
提问于 2025-04-18 07:00

Linux内核版本3.9及以上允许通过设置SO_REUSEPORT来实现进程之间共享套接字,并且可以在内核中进行负载均衡。你可以查看这个链接了解更多信息:http://lwn.net/Articles/542629/

那么,这个功能如何应用于AF_UNIX类型的套接字呢?

看起来这个功能只适用于TCP,而不适用于Unix域套接字。

下面是一个Python测试程序:

import os
import socket

if not hasattr(socket, 'SO_REUSEPORT'):
   socket.SO_REUSEPORT = 15

if True:
   # using TCP sockets
   # works. test with: "echo data | nc localhost 8888"
   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
   s.bind(('', 8888))
else:
   # using Unix domain sockets
   # does NOT work. test with: "echo data | nc -U /tmp/socket1"
   s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
   s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
   try:
      os.unlink("/tmp/socket1")
   except:
      pass
   s.bind("/tmp/socket1")

s.listen(1)
while True:
   conn, addr = s.accept()
   print('Connected to {}'.format(os.getpid()))
   data = conn.recv(1024)
   conn.send(data)
   conn.close()

启动两个实例,然后多次运行以下命令进行测试:

  • echo data | nc localhost 8888 用于TCP
  • echo data | nc -U /tmp/socket1 用于Unix域套接字

在使用TCP时,连接过来的客户端会被均匀分配到两个服务器上。而在使用Unix域套接字时,所有连接过来的客户端都会连接到最后启动的服务器。

2 个回答

2

有一个小补丁,增加了对 UNIX 套接字中 SO_REUSEPORT 的支持,但被拒绝了。这个补丁其实并没有实现多个套接字之间的负载均衡,它只是让 bind() 不会因为套接字文件已经存在而失败。

从用户的角度来看,这种用法被认为是

一种非常奇怪的边缘情况

所以仍然有可能会有其他补丁被接受,这些补丁会通过 SO_REUSEPORT 实现 UNIX 套接字的负载均衡。

9

这个特定的内核补丁在这里有详细说明:

http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c617f398edd4db2b8567a28e899a88f8f574798d

从补丁影响的文件列表中可以看到,这个补丁只对 net/ipv4net/ipv6 的套接字有影响。Unix 域套接字是在 net/unix 中实现的。所以,答案是:不,SO_REUSEPORT 不适用于 AF_UNIX 类型的套接字。

撰写回答