这两天看APUE为一个简单的问题特别恼火,该问题起源于两个套接字选项就是SO_REUSEADDR和SO_REUSEPORT其实在看的过程中问学长了,学长解释的也比较清楚,就是自己悟性不好,一时半会没理解。自己在网上找了几篇优秀的博客看了,受益颇多!
先从套接字选项SO_REUSEADDR说起,当一个没有设置该选项的服务器与客户端建立连接后。然后中断服务器,此时要是马上建立连接的话肯定会出现套接字绑定错误的现象。像图中我亲自运行的样子!真的坑了!
这个epoll服务器和客户端是我之前写的可以可在这里找到,也可以自己测试运行,看下真相。我运行时故意把那个套接字选项去了,然后连接了一个客户端就将服务器程序ctrl+c了。服务器端口是8000没错,可以看出断开连接后,服务端套接字还处于time_wait2,相信看了TCP断开连接四次挥手的人都知道这是服务端在等客户端发送确认断开连接的数据所维持的状态!因此原服务器IP和端口还处于绑定状态,对于TCP肯定不允许相同的IP和端口的多个服务器进行捆绑!所以导致错误的出现,但是等待过上大概两分钟后就可以绑定成功了。
一般来说,不要主动将服务器挂掉,因为这是比较浪费资源的,当很多客户端和服务器进行连接后,主动挂掉,就会让很多绑定好的ip和端口进入到time_wait状态,一段时间无法再次连接
嗯,设置上这个地址复用的SO_REUSEADDR选项
再次运行服务器,连接客户端后,再挂掉服务器,然后再重启服务器后,在系统中查看Tcp连接情况,就会如下所示。系统允许绑定相同的端口了。为什么?观察发现,ip 由localhost 变为0.0.0.0了,在服务器中,0.0.0.0指的是本机上的所有IPV4地址,如果一个主机有两个IP地址,192.168.1.1 和 10.1.2.1,并且该主机上的一个服务监听的地址是0.0.0.0,那么通过两个ip地址都能够访问该服务。
前面解释的差不多了,那么对于套接字选项作用在unp中是这样解释的:
1.SO_REUSEADDR允许启动一个监听服务器并捆绑其众所周知的端口,即使以前建立的将该端口用作他们的本地端口的连接仍存在。
这种条件下通常是这样碰到的:
a)启动一个监听服务器
b)连接请求到达
c)监听服务器终止
d)重启监听服务器
2.允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可。
3.SO_REUSEADDR 允许单个进程捆绑同一端口到多个套接字上,只要每次捆绑指定不同的本地IP地址即可。
4.SO_REUSEADDR允许完全重复的捆绑:当一个IP地址和端口号已绑定到某个套接字上时,如果传输协议支持,同样的IP地址和端口还可以捆绑到另一个套接字上。一般来说本特性仅支持UDP套接字。
这里就利用的是他的第二点特性!
那么我们进一步探究一下他为什么会在服务器关闭后还有fin_wait和time_wait呢?
fin_wait状态是断开连接过程中,服务器向客户端发送fin 包,进入fin_wait1状态,然后客户端关闭连接后并回复ack进入closed_wait状态,服务器端收到ack后维持fin_wait2状态!
而time_wait 状态就是客户端在给服务端发送fin 的状态,只要客户端没收到服务器端的再次确认的数据ack包,原端口和IP就维持绑定,大概就两分钟的时间,这一步的作用保证了当前建立的连接不会对之后建立的新连接造成不可预知的影响,当时间过去后,连接中的一些数据会自动消失在网络中。这也证明了TCP确实是比较可靠的传输层协议!而我们设置的SO_REUSEADDR自己对于其理解就是,服务器在断开连接后,允许在time_wait存在的情况下,给服务器分配一个其他的本机IP,而不是使用原有IP
,再绑定相同的端口,实现TCP的成功连接。
emmmm,这部分知识总结就到这里,我的表达能力确实不是很好,不,是很不好!要是还有疑问的话,我推荐上几篇相关博客!他们讲的确实很不错,很清楚。