1、TCP状态转换
1.1、一般来说,同一个IP(INADDR_ANY),同一个端口SERV_PORT,
只能被成功的bind()一次,若再次bind()就会失败,并且提示:Address alread in use
1.2、查看命令:netstat 显示网络相关信息
-a 显示所有选项
-n 能显示成数字的能容全部显示成数字
-p 显示端口这对应程序名
用法:netstat -anp | grep -E ‘State|9000’
1.3、连接关闭之后,nestat显示有TIME_WAIT状态的连接
TIME_WAIT状态是主动关闭连接的一方才会有。
如果服务器把客户端关闭,有TIME_WAIT状态的连接的时候,
绑定该端口的进程不能重启,bind失败。
1.4、TCP状态转换图,要牢记
LISTEN,SYN_SEND,SYN_RECV,ESTABLISHED,CLOSING
FIN_WAIT_1,CLOSE_WAIT,FIN_WAIT_2,LAST_ASK,TIME_WAIT,CLOSED
客户端:CLOSED->SYN_SEND->ESTABLISHED
服务端:CLOSED->LISTEM->SYN_RCVD->ESTABLISHED
谁主动close连接,谁交汇发动一个FIN标志位置位的数据包给对端。
当服务器主动关闭连接:
服务器:ESTABLISHED->FIN_WAIT1->FIN_WAIT2->TIME_WAIT->CLOSED
客户端:ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
CLOSING是一个同步关闭的状态。
2、TIME_WAIT状态
具有TIME_WAIT状态的TCP连接,服务器退出并重新执行会失败。
2MSL大概是1到4分钟之间。2个数据包最长生命周期。
细说TIME_WAIT:
引入的原因【并且处于1-4分钟】
1)可靠地实现TCP全双工连接的终止
如果最后一个ack丢失,被动关闭端会重发FIN数据包。
如果TIME_WAIT状态不存在,主动关闭端会发一个RST连接复位包。
没有结束正常的4次回收,有可能造成数据包丢失
2)允许老的重复的TCP数据包再网络中消逝。
加入没有TIME_WAIT状态,在最后一个ACK包发送的过程中,
建立一个新的一样连接是可以的,
然后ACK包或者数据包到达了新的客户端,影响新的连接的数据完整性。
2.1、RST标志
对于每一个TCP连接,操作系统是要开辟出来一个收缓冲区,
一个发缓冲区来处理数据的。当我们close一个TCP连接时,
如果发送缓冲区有数据,
那么操作系统会很优雅的把发送缓冲区里的数据发送完毕,
然后再发fin包表示连接关闭。
所以,FIN是个优雅的关闭标志,表示正常的TCP连接关闭。
反观RST标志:出现这个标志一般都表示异常关闭:如果发生异常,
一般都表示会导致丢失一些数据包。
如果将来用setsockopt(SO_LINGER)选项要是开启,
那么close后抓到的包有可能不是FIN包,就是RST包,
此时发送缓冲区的数据就会被丢弃。
所以,RST是异常的关闭,如果你这样关闭连接,
主动关闭的一方也不会进入TIME_WAIT状态。
3、SO_REUSEADDR选项
setsockopt函数一般用在socket创建之后,bind之前。
为了解决TIME_WAIT出现的时候bind失败的问题,
SO_REUSEADDR,为第三个参数,
作用是,即使出现TIME_WAIT状态,也可以重新启动服务。
SO_REUSEADDR的能力
1、SO_REUSEADDR允许启动一个监听服务器并捆绑其端口,
即使以前建立的将端口用作他们的本地端口的连接仍旧存在。
包括TIME_WAIT状态存在。
2、允许同一个端口上启动同一个服务器的多个实例,
只要每个实例捆绑一个不同的本地IP地址即可。
3、允许单个进程捆绑同一个端口到多个套接字,
只要每次捆绑指定不同的本地IP地址。
4、允许完全重复的绑定,,当一个IP地址和端口已经绑定到某个套接字,
如果传输协议支持,
那么同样的IP地址和端口还可以绑定到另一个套接字上,
一般来说本特性仅支持UDP套接字,TCP不支持
* 所有TCP服务器都应该知道本套接字选项,
以防止当套接字处于TIME_WAIT时bind失败。
3.1、两个进程,绑定同一个IP和端口
bind失败,因为只支持UDP
3.2、TIME_WAIT状态时的bind绑定
可以。
代码回顾:
网友评论