美文网首页
重用套接字选项

重用套接字选项

作者: taj3991 | 来源:发表于2019-12-27 17:05 被阅读0次

我们知道,一个 TCP 连接是通过四元组(源地址、源端口、目的地址、目的端口)来唯一确定的,如果每次 Telnet 客户端使用的本地端口都不同,就不会和已有的四元组冲突,也就不会有 TIME_WAIT 的新旧连接化身冲突的问题。

事实上,即使在很小的概率下,客户端 Telnet 使用了相同的端口,从而造成了新连接和旧连接的四元组相同,在现代 Linux 操作系统下,也不会有什么大的问题,原因是现代 Linux 操作系统对此进行了一些优化。

第一种优化是新连接 SYN 告知的初始序列号,一定比 TIME_WAIT 老连接的末序列号大,这样通过序列号就可以区别出新老连接。

第二种优化是开启了 tcp_timestamps,使得新连接的时间戳比老连接的时间戳大,这样通过时间戳也可以区别出新老连接。

在这样的优化之下,一个 TIME_WAIT 的 TCP 连接可以忽略掉旧连接,重新被新的连接所使用。

这就是重用套接字选项,通过给套接字配置可重用属性,告诉操作系统内核,这样的 TCP 连接完全可以复用 TIME_WAIT 状态的连接。代码片段已经放在文章中了:


int on = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

SO_REUSEADDR 套接字选项,允许启动绑定在一个端口,即使之前存在一个和该端口一样的连接。前面的例子已经表明,在默认情况下,服务器端历经创建 socket、bind 和 listen 重启时,如果试图绑定到一个现有连接上的端口,bind 操作会失败,但是如果我们在创建 socket 和 bind 之间,使用上面的代码片段设置 SO_REUSEADDR 套接字选项,情况就会不同。

SO_REUSEADDR 套接字选项还有一个作用,那就是本机服务器如果有多个地址,可以在不同地址上使用相同的端口提供服务。

比如,一台服务器有 192.168.1.101 和 10.10.2.102 连个地址,我们可以在这台机器上启动三个不同的 HTTP 服务,第一个以本地通配地址 ANY 和端口 80 启动;第二个以 192.168.101 和端口 80 启动;第三个以 10.10.2.102 和端口 80 启动。

这样目的地址为 192.168.101,目的端口为 80 的连接请求会被发往第二个服务;目的地址为 10.10.2.102,目的端口为 80 的连接请求会被发往第三个服务;目的端口为 80 的所有其他连接请求被发往第一个服务。

我们必须给这三个服务设置 SO_REUSEADDR 套接字选项,否则第二个和第三个服务调用 bind 绑定到 80 端口时会出错。

最佳实践

这里的最佳实践可以总结成一句话: 服务器端程序,都应该设置 SO_REUSEADDR 套接字选项,以便服务端程序可以在极短时间内复用同一个端口启动。

有些人可能觉得这不是安全的。其实,单独重用一个套接字不会有任何问题。我在前面已经讲过,TCP 连接是通过四元组唯一区分的,只要客户端不使用相同的源端口,连接服务器是没有问题的,即使使用了相同的端口,根据序列号或者时间戳,也是可以区分出新旧连接的。

而且,TCP 的机制绝对不允许在相同的地址和端口上绑定不同的服务器,即使我们设置 SO_REUSEADDR 套接字选项,也不可能在 ANY 通配符地址下和端口 9527 上重复启动两个服务器实例。如果我们启动第二个服务器实例,不出所料会得到 Address already in use 的报错,即使当前还没有任何一条有效 TCP 连接产生。

tcp_tw_reuse 和SO_REUSEADDR

这两个东西一点关系也没有。

tcp_tw_reuse 是内核选项,主要用在连接的发起方。TIME_WAIT 状态的连接创建时间超过 1 秒后,新的连接才可以被复用,注意,这里是连接的发起方;

SO_REUSEADDR 是用户态的选项,SO_REUSEADDR 选项用来告诉操作系统内核,如果端口已被占用,但是 TCP 连接状态位于 TIME_WAIT ,可以重用端口。如果端口忙,而 TCP 处于其他状态,重用端口时依旧得到“Address already in use”的错误信息。注意,这里一般都是连接的服务方。

总结

今天我们分析了“Address already in use”产生的原因和解决方法。你只要记住一句话,在所有 TCP 服务器程序中,调用 bind 之前请设置 SO_REUSEADDR 套接字选项。这不会产生危害,相反,它会帮助我们在很快时间内重启服务端程序,而这一点恰恰是很多场景所需要的。

原文

https://time.geekbang.org/column/article/131670

相关文章

  • 重用套接字选项

    我们知道,一个 TCP 连接是通过四元组(源地址、源端口、目的地址、目的端口)来唯一确定的,如果每次 Telnet...

  • APUE读书笔记-16网络通信(9)

    6、套接字选项 套接字机制提供了两个套接字选项接口来控制套接字的行为。一个接口用来设置选项,另外一个接口用来允许我...

  • 套接字选项

    有几个函数可以设置影响套接字的选项 getsockopt 和 setsockopt函数 fcntl 函数把套接字设...

  • TCP与UDP挖掘机(二)套接字选项

    上回主要梳理了TCP和UDP的相关知识点,这一篇主要梳理一些套接字选项,以作备忘。 套接字选项 用于IP层的套接字...

  • 套接字(Socket)编程(三) 套接字可选项

    套接字具有多种特性,这些特性可通过可选项更改,本篇文章将介绍更改套接字可选项的方法,并以此为基础进一步观察套接字内...

  • 广播的发送与接收

    广播的发送 流程 创建socket 设置套接字选项(在默认情况下,UDP套接字文件不允许发送广播,需要设置套接字文...

  • Socket SO_RCVTIMEO, SO_SNDTIMEO

    SO_RCVTIMEO, SO_SNDTIMEO介绍 套接字选项SO_RCVTIMEO: 用来设置socket接收...

  • TCP/IP详解卷一 ——tcp

    套接字选项SO_RESUEADDR 即使端口处于2MSL状态,使用该选项,仍然能够在该端口建立连接。服务器常会设置...

  • ss:一个统计网络和套接字信息的命令行工具

    ss简介 ss命令可以用来统计套接字信息,它支持PACKET套接字、TCP套接字、UDP套接字、DCCP套接字、R...

  • Windows API - Socket - SetSocket

    可以通过调用Socket对象的SetSocketOption方法设置套接字的各种选项,它有3种重载的形式: 参数一...

网友评论

      本文标题:重用套接字选项

      本文链接:https://www.haomeiwen.com/subject/xwvdoctx.html