你的浏览器不支持canvas

Enjoy life!

TCP

Date: Author: JM

本文章采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。

其他链接:

以下部分内容参考于:http://www.jianshu.com/p/ef892323e68f

一、TCP是什么

TCPTransimission Control Protocol,传输控制协议。

它是一种 面向连接的可靠的基于IP的 传输协议。

TCP在IP报文的协议号是6

二、TCP报文格式

2.1 TCP报文图片示例

  • 中文版

relationship-map

  • 英文版

relationship-map

2.2 TCP报文的具体内容

  1. 16位源端口号(Source Port):

    16位的源端口中包含初始化通信的端口。源端口和源IP地址的作用是标识报文的返回地址。

  2. 16位目的端口号(Destination Port):

    16位的目的端口域定义传输的目的。这个端口指明报文接收计算机上的应用程序地址接口。

  3. 32位序号(Sequence Number):

    32位的序列号由接收端计算机使用,重新分段的报文成最初形式。当SYN出现,序列码实际上是初始序列码(Initial Sequence Number,ISN),而第一个数据字节是ISN+1。这个序列号(序列码)可用来补偿传输中的不一致。

  4. 32位确认序号(Acknowledgment Number):

    32位的序列号由接收端计算机使用,重组分段的报文成最初形式。如果设置了ACK控制位,这个值表示一个准备接收的包的序列码。

  5. 4位首部长度(Offset):

    4位包括TCP头大小,指示何处数据开始。

  6. 保留(6位)(Reserved):

    6位值域,这些位必须是0。为了将来定义新的用途而保留。

  7. 标志(TCP Flags):

    6位标志域。表示为:紧急标志、有意义的应答标志、推、重置连接标志、同步序列号标志、完成发送数据标志。按照顺序排列是:URG、ACK、PSH、RST、SYN、FIN。

  8. 16位窗口大小(Window):

    用来表示想收到的每个TCP数据段的大小。TCP的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收的字节。窗口大小是一个16字节字段,因而窗口大小最大为65535字节。

  9. 16位校验和(Checksum):

    16位TCP头。源机器基于数据内容计算一个数值,收信息机要与源机器数值 结果完全一样,从而证明数据的有效性。检验和覆盖了整个的TCP报文段:这是一个强制性的字段,一定是由发送端计算和存储,并由接收端进行验证的。

  10. 16位紧急指针(Urgent Pointer):

    指向后面是优先数据的字节,在URG标志设置了时才有效。如果URG标志没有被设置,紧急域作为填充。加快处理标示为紧急的数据段。

  11. 选项(TCP Choices):

    长度不定,但长度必须为1个字节。如果没有选项就表示这个1字节的域等于0。

  12. 数据(Data):

    该TCP协议包负载的数据。

2.3 TCP Flags:主要操控TCP的状态机

  1. URG

    此标志表示TCP包的紧急指针域(后面马上就要说到)有效,用来保证TCP连接不被中断,并且督促中间层设备要尽快处理这些数据; 【紧急标志。紧急标志为”1”表明该位有效。】

  2. ACK

    此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1, 为1的时候表示应答域有效,反之为0;

    【确认标志。表明确认编号栏有效。大多数情况下该标志位是置位的。TCP报头内的确认编号栏内包含的确认编号(w+1)为下一个预期的序列编号,同时提示远端系统已经成功接收所有数据。】

  3. PSH

    这个标志位表示Push操作。所谓Push操作就是指在数据包到达接收端以后,立即传送给应用程序, 而不是在缓冲区中排队;

  4. RST

    这个标志表示连接复位请求。用来复位那些产生错误的连接,也被用来拒绝错误和非法的数据包;

  5. SYN

    表示同步序号,用来建立连接。

    SYN标志位和ACK标志位搭配使用,当连接请求的时候,SYN=1, ACK=0;连接被响应的时候,SYN=1,ACK=1; 这个标志的数据包经常被用来进行端口扫描

    扫描者发送 一个只有SYN的数据包,如果对方主机响应了一个数据包回来 ,就表明这台主机存在这个端口;但是由于这种扫描方式只是进行TCP三次握手的第一次握手,因此这种扫描的成功表示被扫描的机器不很安全,一台安全的主机将会强制要求一个连接严格的进行TCP的三次握手。

  6. FIN

    表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送FIN标志 位的TCP数据包后,连接将被断开。这个标志的数据包也经常被用于进行端口扫描。

三、TCP的三次握手与四次挥手

  • TCP的三次握手与四次挥手完整过程图例

relationship-map

3.1 三次握手

3.1.1 三次握手是什么

三次握手,Three-Way Handshake,即建立TCP连接。而且建立一个TCP连接需要客户端和服务端总共发送3个包以确认连接的建立。

  • 三次握手图例

relationship-map

3.1.2 三次握手过程解析

  1. 第一次握手:

    客户端将标志 SYN设置为1,随机产生一个值 seq = J,并将该数据包发送给服务器,此时,客户端进入 SYN_SENT状态,等待服务器的确认。

  2. 第二次握手:

    服务器收到数据包后,由标志 SYN = 1知道客户端的请求,并建立连接。此时,服务器将标识 SYNACK 都设置为1,ack = J + 1;且随机产生一个值 seq = K,并将该数据包发送给客户端以确认连接请求。服务器也进入了SYN_RCVD状态。

  3. 第三次握手:

    客户端收到确认后,检测 ack 是否为 J + 1ACK 是否为1,如果正确,则将标识位 ACK 设置为1,ack = K + 1,并将该数据包发送给服务器,服务器检查 ack 是否为 K + 1ACK 是否为1,如果正确,则连接建立成功,客户端和服务器都进入 ESTABLISHED 状态,完成三次握手。

完成三次握手后,客户端和服务器之间就可以开始传输数据。

3.2 四次挥手

  • 四次挥手图例

relationship-map

3.2.1 四次挥手是什么

四次挥手,Four-Way Wavehand,即终止TCP连接。而且断开一个TCP连接,需要客户端和服务端总共发送4个包,才能确认连接断开。

3.2.2 四次挥手过程解析

  1. 第一次挥手:

    客户端发送一个 FIN,用来关闭客户端到服务器的数据传送,客户端进入 FIN_WAIT_1 的状态。

  2. 第二次挥手

    服务器收到 FIN 后,会发送一个 ACK 给客户端,确认序号为收到序号 + 1(与 SYN 相同,一个 FIN 占用一个序号)。此时,服务器端进入 CLOSE_WAIT 状态。

  3. 第三次挥手

    服务器发送一个 FIN,用来关闭服务器到客户端的数据传送,服务器进入 LAST_ACK 状态。

  4. 第四次挥手

    客户端收到 FIN 后进入 TIME_WAIT 状态,接着客户端发送一个 ACK 给服务器,确认号为收到序号 + 1;此时服务器进入 CLOSED 状态,完成四次挥手。

3.3 SYN攻击

  • 在三次握手过程中,Server 发送 SYN-ACK 之后,收到 ClientACK 之前的 TCP连接 称为 半连接(half-open connect),此时 Server 处于 SYN_RCVD 状态,当收到 ACK 后,Server 转入 ESTABLISHED 状态。

  • SYN攻击 就是 Client 在短时间内伪造大量不存在的 IP地址 ,并向 Server 不断地发送 SYN包Server 回复确认包,并等待 Client 的确认,由于源地址是不存在的,因此,Server 需要不断重发直至超时,这些伪造的 SYN 包将产时间占用未连接队列,导致正常的 SYN请求 因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。

  • SYN攻击 时一种典型的 DDOS 攻击,检测SYN攻击的方式非常简单,即当 Server 上有大量半连接状态且源IP地址是随机的,则可以断定遭到 SYN 攻击了,使用如下命令可以让之现行:

#netstat -nap | grep SYN_RECV

3.4 为什么要三次握手?

  • 提一个问题:为什么非要三次呢?怎么觉得两次就可以完成了。那TCP为什么非要进行三次连接呢?
  • 已失效的连接请求报文段突然又传送到了服务端,会出现问题。
  • “已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。 但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。
  • 假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。 这样,server的很多资源就白白浪费掉了。
  • 采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。

简单理解:

因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。

3.5 为什么要四次分手?

  • TCP 是全双工模式,这就意味着,当 Client 发出 FIN 报文段时,只是表示 Client 已经没有数据要发送了,Client 告诉 Server, 它的数据已经全部发送完毕了;

  • 但是,这个时候 Client 还是可以接受来自 Server 的数据;当 Server 返回 ACK 报文 段时,表示它已经知道 Client 没有数据发送了,但是 Server 还是可以发送数据到 Client 的;

  • Server 也发送了 FIN 报文段时,这个时候就表示 Server 也没有数据要发送了,就会告诉 Client ,我也没有数据要发送了,之后彼此 就会愉快的中断这次 TCP 连接。

如果要正确的理解四次分手的原理,就需要了解四次分手过程中的状态变化。

  • FIN_WAIT_1

    其实 FIN_WAIT_1FIN_WAIT_2 状态的真正含义都是表示等待对方的FIN报文。

    而这两种状态的区别是:FIN_WAIT_1 状态实际上是当 SOCKETESTABLISHED 状态时, 它想主动关闭连接,向对方发送了 FIN 报文,此时该 SOCKET 即进入到 FIN_WAIT_1 状态。而当对方回应 ACK 报 文后,则进入到 FIN_WAIT_2 状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应 ACK 报文,所以 FIN_WAIT_1 状态一般是比较难见到的,而 FIN_WAIT_2 状态还有时常常可以用 netstat 看到。 (主动方)

  • FIN_WAIT_2

    实际上 FIN_WAIT_2 状态下的 SOCKET ,表示半连接,也即 有一方要求 close 连接,但另外还告诉对方,我暂时还有点数据需要传送给你( ACK 信息),稍后再关闭连接。 (主动方)

  • CLOSE_WAIT

    表示在等待关闭。

    当对方 close 一个 SOCKET 后发送 FIN 报文给自己,系统毫无疑问地会回应一个 ACK 报文给对方,此时则进入到 CLOSE_WAIT 状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close 这个 SOCKET,发送 FIN 报文给对方,也即关闭连接。所以你在 CLOSE_WAIT 状态下,需要完成的事情是等待你去关闭连接。(被动方)

  • LAST_ACK

    这个状态还是比较容易好理解的,它是被动关闭一方在发送 FIN 报文后,最后等待对方的 ACK 报文。当收到ACK报文后,就可以进入到 CLOSED 可用状态了。(被动方)

  • CLOSED

    表示连接中断。

简单理解:

关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送,但未必所有的数据都全部发送给对方,所以你未必会马上关闭SOCKET,也即你可能还需要发送一些数据给对方,之后再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。


对于本文内容有问题或建议的小伙伴,欢迎在文章底部留言交流讨论。