TCP通过三次握手建立连接 通过四次挥手结束连接
这是TCP/IP一书中使用tcpdump得到的结果
下面这个图片比较容易观看:
可以看出为什么建立连接是三次而结束是四次呢?
因为,报文段2将SYN和ACK合并起来发送。这样可以减少发送的报文个数,否则20字节的TCP首部和20字节的IP首部只发送一个字节的数据过于浪费。在TCP的交互数据流中会用到Nagle解决类似的问题。
终止连接是ACK与FIN无法合并,一方发送FIN代表自己不会再发送数据了,但连接的另一端可能还要发送数据(TCP的半关闭),所以无法合并。
TCP的状态变迁图:
值得注意的是TIME_WAIT状态,这个状态的产生有以下两点原因:
1、可靠地实现全双工的终止(防止对FIN的ACK需要重传)
2、允许老的分节在网络中消逝
由于TIME_WAIT的时间一般是2MSL(最长分节生命期),足以使这个连接的所有分节都消失在网络中,防止使用同样的IP+port建立的TCP连接收到上一个连接的数据
一般当程序属于TIME_WAIT时,它所占用的端口不允许被其它程序绑定,除非指定端口可重用
平静时间:当主机崩溃重启后的MSL秒内不能建立TCP连接。这段时间被称为平静时间。因为,如果直接重建连接成功,故障前从这个连接发出但是迟到的报文,会被错误的认为是新连接的报文。
FIN_WAIT_2:如果连接的一端向另外一端发送FIN并收到ACK将会处于FIN_WAIT_2状态。此时,若另一端并未关闭socket连接那么这个状态将会一直维持下去。虽然下面的实现违反协议的规定,但是很多系统采用了下述方法 :进入FIN_WAIT_2时会设置一个定时器如果连接空闲10分75秒,TCP将会被关闭。
TCP呼入请求队列(linux):
使用bind函数绑定指定的IP和端口,并用listen监听。
还记得listen的第二个参数吗,最多可以有多少个排队的连接。
因此,TCP做出的行为如下:
1、等待请求的一端有一个固定长度的队列,用以存储已完成三次握手但还没有交给应用层的连接。TCP接受一个连接并放入队列,应用层接受一个连接将其从队列取出(accept函数)。
2、应用层指定一个积压值(listen 参数)。
3、当一个请求到来(SYN)时,TCP使用算法判断是否接受连接(实际情况比较复杂,并不仅仅根据队列是否用空位)
4、如果接受,进行三次握手
5、如果不接受,将不理会SYN,客户稍后将会重发SYN(超时重发)