socket编程 REUSEADDR/REUSESOCK 参数区别
socket编程 REUSEADDR/REUSESOCK
前言
介绍一下系统调用 setsockopt 的REUSEADDR/REUSESOCK 参数区别。
众所周知,TCP连接中主动断开连接方会进入一个TIME_WAIT 状态,并连接会等待两个MSL时间才真正断开,来防止最后一个发送的ACK丢失也能重发和让数据包在网络中消散。
应用场景
对于一个服务器程序来说,它要服务大量的用户请求,服务器在接受请求进行后续的业务处理时,难免可能出现BUG导致服务器崩溃,此时并不是第一时间定位BUG,而是想办法重启服务来减少服务崩溃无法处理业务带来的损失,而此时服务端为主动断开连接,立即重启服务会发送bind错误,得等待2MSL时间后服务才能重启,setsocket 系统的 REUSEADDR/REUSESOCK 参数都可以解决此类问题,让服务立即重启。
int opt = 1; setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR/* SO_REUSEPORT也可 */, &opt, sizeof(opt));
REUSEADDR/REUSESOCK 的区别
REUSESOCK 可以认为是REUSEADDR的超集,都可以重新绑定处于TIME_WAIT状态的端口,但REUSESOCK功能更强大,REUSESOCK参数还可以重复绑定处理listen状态的端口,并实现负载均衡。
使用同样的代码,起两个简单的echoserver,绑定同一个端口
int main() { int lfd = socket(AF_INET, SOCK_STREAM, 0); int opt = 1; setsockopt(lfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)); sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = 0; addr.sin_port = htons(8080); if (-1 == bind(lfd, (sockaddr *)&addr, sizeof(addr))) { cout << "bind error!" << endl; exit(1); } listen(lfd, 8); int fd = accept(lfd, NULL, NULL); cout << "new client fd: " << fd << endl; char buf[255]; while (1) { int rd_count = read(fd, buf, sizeof(buf) - 1); if (rd_count > 0) { int sd_count = write(fd, buf, strlen(buf)); } else if (rd_count == 0) { cout << "client close socket" << endl; close(fd); exit(1); } } }
可以看到两个连接被分发到了不同的server上
上一篇:
Java架构师技术进阶路线图