这篇文章将总结TCP首部及连接的相关知识。
TCP(Transmission Control Protocol)提供一种面向连接的、可靠的字节流服务。TCP连接是全双工的,即数据在两个方向上能够同时传递。
TCP Header
TCP报文由首部和数据组成,数据部分是可选的。TCP报文被封装在IP数据报中,结构如下图所示:
TCP Header由固定部分(Basic)和选项部分(Options)组成,其中固定部分的大小为20 bytes。TCP Header最大为60 bytes。
TCP Header的结构如下图所示:
挑几个重要的说:
- Sequence Number(序号,Seq):用来标识从TCP发送端到接收端发送的数据字节流,它表示这个报文段中的第一个数据字节,也用于解决packet乱序问题
- Acknowledgment Number(确认序号):包含发送确认的一端所期望收到的下一个序列号
- CWR:阻塞窗口减小(Congestion Window Reduced),通常是发送端减小了其发包速率
- ECE:ECN Echo
- URG:紧急指针(Urgent Pointer)有效
- PSH:该标志置位时,接收端不将该数据进行队列处理,而是尽可能快将数据转由应用处理
- ACK:确认序号(Acknowledgment Number)有效
- RST:重置连接(通常由于连接错误)
- SYN:同步序号(Sequence Number),用来发起一个连接
- FIN:发送端完成发送任务
- Window Size:滑动窗口大小,用于流量控制
TCP连接的建立和终止
三次握手
TCP three-way handshake(三次握手)的过程:
- 第一次握手(SYN):客户端首先发送一个SYN包到服务器,初始序号Seq=ISN(client)=a。客户端进入SYN_SENT状态。
- 第二次握手(SYN + ACK):服务端收到客户端发来的SYN包后,需要确认客户端的SYN包,将确认序号ACK设为客户端的ISN加1(ACK=a+1)作为确认,同时发回包含服务器的初始序号Seq=ISN(server)=b,即SYN+ACK包。服务端进入SYN_RECV状态。
- 第三次握手(ACK):客户端收到服务端发来的SYN+ACK包后,将确认序号设为服务端的ISN加1作为确认,向服务端发送确认包(ACK=b+1)。此包发送完毕,客户端与服务端进入ESTABLISHED状态,完成三次握手,建立连接。
【思考】为什么需要三次握手而不是两次握手?
四次挥手
由于TCP连接是全双工的,因此每个方向的连接必须单独地进行关闭,于是TCP连接的断开需要进行“四次挥手”(两端分别进行FIN+ACK和ACK两次挥手)。
TCP连接断开的过程:
- 客户端发起请求,向服务端发送一个FIN(Seq=c, ACK=d),用来关闭从客户端到服务端的传输。客户端的状态变为FIN_WAIT_1。此时客户端仍然可以接收数据。如果这之前发出的数据中存在没有ACK的,客户端仍然会重发这些数据。
- 服务端收到客户端的FIN包,然后向客户端发回一个ACK包(ACK=c+1)作为确认。
- 同时,服务端向客户端发送一个FIN(Seq=d, ACK=c+1),用来关闭从服务端到客户端的传输。服务端的状态变为LAST_ACK。
- 客户端收到服务端的FIN包,然后向服务端发回一个ACK包(ACK=d+1)作为确认。四次挥手结束,连接断开(CLOSED)。
注意:TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSED状态,原因:
- TIME_WAIT确保有足够的时间让对端收到了ACK(如果被动关闭的那方没有收到Ack,就会触发被动端重发Fin,一来一去正好2个MSL)
- 有足够的时间让这个连接不会跟后面的连接混在一起(部分路由器会缓存数据包导致连接重用)
总结
用下面两幅图总结TCP连接的建立与终止:
最后来一张TCP状态转换图,可以很好地概括整个TCP连接的建立和终止的过程及状态的变化。图来自 TCP/IP Illustrated, Volume 1 : The Protocols(2nd Edition) 。
Reference
- TCP/IP Illustrated, Volume 1 : The Protocols(2nd Edition), Kevin.R.Fall