目录
提问:
- 用来解决什么问题?
- 如何使用?
用来解决什么问题?
- 避免当TCP服务器重启时,尝试将套接字绑定到当前已经同TCP结点相关联的端口上时出现的EADDRINUSE(地址已使用)错误。这个问题会在下面两种情况中出现:
a 之前连接到客户端的服务器要么通过close(),要么因为崩溃(被信号杀死)而执行了主动关闭。这使得TCP结点将处于TIME_WAIT状态,直到2倍的MSL超时过期为止(不同系统下,不一样。ubuntu 总时长是 1分钟)。
b 之前,服务器先创建一个子进程来处理客户端的连接。稍后,服务器终止,而子进程继续服务客户端,因而使得维护的TCP结点使用了服务器的知名端口号。
尽管如此,针对上述两种情况,默认情况下大多数TCP实现会阻止新的监听套接字绑定到服务器知名端口上。 - 一个已连接的TCP套接字是由一个4元组来唯一标识的。形式如下:
{ local-IP-address, local-port, foreign-IP-address, foreign-port}
TCP规范要求这样一个4元组是唯一的,也就是说只有一个对应的连接可以存在。
而大多数实现(包括Linux)都强制施加了一个更为严格的约束:如果主机上有任何可匹配到本地端口的TCP连接,则本地端口不能被重用(对bind()的调用)。
如何使用?
- 启用SO_REUSEADDR套接字选项可以解放这个限制,使得更接近TCP需求。默认情况下该选项值为0,表示被关闭。我们可以在绑定套接字之前为该选项设定一个非零值来启用它。下面是栗子^_^:
#include <fun.c> //头文件在之前的博客中有
int main()
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == fd)
{
perror("socket");
}
int optval = 1;
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1)
perror("setsockopt");
if(bind(fd, &addr, addrlen) == -1)
perror("bind");
if(listen(fd, 10) == -1)
perror("listen");
return 0;
}
参考资料
- linux/UNIX系统编程手册 (下册)