Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

如何理解TCP中「三次握手」和「四次挥手」 #2

Open
Rcong opened this issue Mar 17, 2019 · 0 comments
Open

如何理解TCP中「三次握手」和「四次挥手」 #2

Rcong opened this issue Mar 17, 2019 · 0 comments

Comments

@Rcong
Copy link
Owner

Rcong commented Mar 17, 2019

说起计算机网络知识中的「三次握手」和「四次挥手」,比较基础的印象就是SYN的请求与ACK、SYN的回传,FIN的请求断开等概念,描述起来只是浮于表面,所以补了一下这方面的知识,形成这篇手记。

先看一次http的请求过程:

  1. TCP建立连接
  2. 客户端发起请求
  3. 服务端响应
  4. 服务端断开TCP连接

持久连接TCP

HTTP的下层使用了 TCP/IP的协议,所以要了解「三次握手」和「四次挥手」细节的时候,TCP相关的知识是绕不开的。

OSI七层模型

什么是TCP协议

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。为了提供可靠性传输,实行顺序控制重发控制等机制。在计算机网络OSI模型中,他完成了传输层(第四层)的工作。

了解了这个协议之后,下面来看下这个TCP的内部结构,下文的理解都是建立在对于其中一些重要字段的含义之上的。

TCP的头部格式

TCP包头部

源端口号(16位)、目标端口号(16位)

各占用16位字节,表示发送端端口号和接收端端口号。这端口号加上IP首部中的源端IP地址和目的端IP地址就能唯一确定一个TCP的连接。

序号(Sequence Number) - 发送数据的顺序编号(32位)

占用32位字节,序号用来标识从TCP发送端向TCP接受端发送的数据字节流, 它表示在这个报文段中的第一个数据字节在数据流中的位置。

确认应答号(ack号)- 接收数据的顺序编号(32位)

表示了接收方告知发送方接收方期望收到的下一个字节序号。

首部长度(数据偏移量)(4位)

占用4位字节,表示了TCP传输的数据部分应该从TCP包的哪个位开始计算。也表示了TCP包首部长度。

保留(4位)

占用4位字节,该字段为保留,为以后扩展使用,现在未使用。

控制位(6位)

该字段中的每个比特分别表示以下通信控制含义。

  • URG: 表示紧急指针字段有效

  • PSH: 表示通过push操作发送的数据,为1的时候接收方收到数据立马上传给上层应用协议,为0的时候不是立马上传而是先缓存起来

  • RST: 复位连接,强制断开连接,用于异常中断的情况。

  • ACK: 表示接收数据序号字段有效,为1时表示数据已被接收方收到,为0时没有收到。

注:这里的ACK标志位和上文提到的确认应答号(ack号)是两个概念。

  • SYN: 用于建立连接时候同步序号使用。SYN与ACK搭配使用:当请求建立连接时,SYN=1,ACK=0;连接被响应时,SYN=1,ACK=1;

  • FIN: 为1时表示,表示不会将有数据传送,连接将会断开。双方主机交换FIN为1的TCP包,各自对对方的FIN为1的TCP包确认应答后就可以断开。

窗口(16位)

占用16位字节,用于流量控制。通知从相同TCP首部的ack号所指位置开始能够接受的数据大小。TCP不允许发送超过此处所示大小的数据。

在理解了这些头部字段的含义后,再来重新审视一下「三次握手」和「四次挥手」的过程。

TCP的三次握手

三次握手

  • 开始双方都处于关闭状态(closed),显示服务器先监听某一个端口,处于监听状态(Listen)。

  • 第一次握手:建立连接时,客户端主动发送报文段(SYN=1,seq=x)到服务器,并进入SYN_SENT状态,等待服务器确认;

  • 第二次握手:服务器收到SYN报文段,必须确认客户的报文段。此时会响应一个报文段,这个报文段的SYN=1,控制位ACK=1,ack号=x+1(对应第一次握手中的seq数+1),seq=y,然后服务器进入SYN_RECV状态。

  • 第三次握手:客户端收到服务器的SYN+ACK包后,需要响应服务器的应答应答报文段一个报文段,这个报文段的控制位ACK=1,ack号=y+1(对应第二次握手中的seq数+1),seq=x+1(对应第二次我手中的ack号),然后客户端进入建立连接(ESTABLISHED)的状态,服务端接受到这个报文段后也进入建立连接(ESTABLISHED)的状态。

这三个报文段完成连接的建立过程就是三次握手。

看完了建立连接,再来看一下断开连接。

TCP的四次挥手

当建立起TCP连接之后,客户端和服务器端传输完数据,两端就要断开TCP连接,于是就有了四次挥手。

四次挥手

  • 第一次挥手:关闭方A发送一个报文段(seq=p,FIN=1),然后进入FIN_WAIT_1状态,发送FIN标志位,表示关闭方A将不会再有数据传送,连接将会断开。
  • 第二次挥手:接收方B收到的关闭方A的FIN报文段,会响应一个方的报文段,该报文段的控制位ACK=1,ack号为p+1(对应第一次回收中的seq数p加1),然后进入CLOSED_WAIT状态。这个过程表示了接收方收到了关闭方的关闭请求。
  • 第三次挥手:接收方B发出FIN报文段(FIN=1,seq=q,ack=p+1,控制位ACK=1),然后进入LAST_ACK状态。
  • 第四次挥手:关闭方A收到接收方B的FIN报文段,会响应一个报文段该报文段的控制位ACK=1,ack号为q+1(对应第三次回收中的seq数q加1),然后关闭方A就进入TIME_WAIT状态。接收方B收到响报文段之后,就关闭连接(CLOSED),关闭方A等待2MSL后没有收到回复,则关闭方A也关闭连接进入CLOSED状态。

注:MSL是Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。

四次挥手的过程可以形象地理解为一问一答,双方都经过了这个过程就可以结束这个连接了。

小结

「三次握手」和「四次挥手」的基本过程就结束了,但是TCP协议中还有许多可以去深挖的点,有兴趣的话可以读一下《TCP-IP详解》、《图解TCP IP》,这两本书也是本篇手记的参考资料。有机会读完再和大家分享一下。

参考

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant