SO_REUSEADDR

一个服务bind了某个端口,其他的服务再bind就会报错。如果想要多个套接字绑定到同一个端口上,就需要要到端口复用了。端口复用允许在一个应用程序可以把 n 个套接字绑在一个端口上而不出错。同时,这 n 个套接字发送信息都正常,没有问题。但是,这些套接字并不是所有都能读取信息,只有最后一个套接字会正常接收数据

端口复用最常用的用途应该是防止服务器重启时之前绑定的端口还未释放或者程序突然退出而系统没有释放端口。这种情况下如果设定了端口复用,则新启动的服务器进程可以直接绑定端口。如果没有设定端口复用,绑定会失败,提示ADDR已经在使用中。

通常端口被释放后,要经过TIME_WAIT状态才能继续使用,通过设置SO_REUSEADDR后,端口释放了立即就可以被再次使用。

// sockfd_one, sockfd_two都要设置端口复用
// 在sockfd_one绑定bind之前,设置其端口复用
int opt = 1;
setsockopt( sockfd_one, SOL_SOCKET,SO_REUSEADDR, (const void *)&opt, sizeof(opt) );
err_log = bind(sockfd_one, (struct sockaddr*)&my_addr, sizeof(my_addr));
 
// 在sockfd_two绑定bind之前,设置其端口复用
opt = 1;
setsockopt( sockfd_two, SOL_SOCKET,SO_REUSEADDR,(const void *)&opt, sizeof(opt) );
err_log = bind(sockfd_two, (struct sockaddr*)&my_addr, sizeof(my_addr));

SO_REUSEPORT

在SO_REUSEPORT没有出现之前,多线程编程一般有两种获取到来的请求。

  1. 指派一条线程专门进行accept,获取socket后分派给worker线程。这种方法使得进行accept的线程成为了单点,容易成为性能的瓶颈。

    • dispatcher负责接收连接,然后分发给work进程
  2. 多个线程同时进行accept。这种方法的问题是每一个线程accept成功的概率不均匀,导致负载不均衡。

参考:

1,socket 端口复用 SO_REUSEPORT 与 SO_REUSEADDR - schips - 博客园 (cnblogs.com)