TCP头部

除非有选项存在,否则TCP头部的大小通常为20字节。

  • 源端口:16位,TCP报文的源端口。源端口最初直接与发送系统的某个进程绑定在一起。
  • 目的端口:16位,TCP报文的目的端口。与源端口类似,最初与接收系统的某个进程绑定在一起。目前使用哈希的方法,允许同时开放多条链接。
  • 序列号(Sequence Number) :32位,序列号字段用于为每个TCP报文设置一个编号,从而保证TCP流量的有序性(比如,报文按照正确的发送顺序抵达)
  • 确认号(Acknowledgement Number):32位,确认号字段用于一台主机确认接收到某一特定报文。例如,我们接受到一个设置有序列号的TCP报文,如果该报文正确无误,我们将回一个ACK报文,并将其确认号设置为最初接收报文的序号。表示希望对方下一次发送报文的序列号的起始值。期望收到对方下一个报文的第一个数据字节的序号,因此,确认序号应当是上次已成功收到数据字节序号加1。不过,只有当标志位中的ACK标志为1时该确认序列号的字段才有效。主要用来解决不丢包的问题;
  • 头部长度:4位,该字段指出了TCP头部的长度,以及报文数据部分是从哪个位置开始的。该字段占用4比特位,并且以32位字为单位计算TCP头部的长度。
  • 保留:6位,保留使用
  • URG:1位,该标志位表明是否使用了紧急指针(Urgent Pointer),0代表没有,1代表使用了。
  • ACK:1位,置1表明这是一条对已接收到的报文的回复,并且包含数据。通常,发动一个确认报文是为了表明确实接收到了一个报文,并且报文不包含任何错误。如果ACK置1,那么原始的数据发送者就会检查TCP报文中的确认号。查看哪一个报文被确认接收到,然后从缓存中丢弃已接收到的报文。
  • PSH:1位,PUSH标志位是为了告知中间主机的TCP层直接把数据发送给实际用户。
  • RST:1位
  • SYN:1位,同步序列编号(Synchronize Sequence Number,SYN)用于连接初始建立阶段。在TCP连接的两个实例中被置位1:一个是打开连接的初始报文,另一个是回复SYN/ACK报文。除了这两种情况外,SYN不会被使用。
  • FIN:1位,FIN位置1表示发送当前报文的主机已没有要发送的数据。当另一端发现FIN位被置1,则回复一个FIN/ACK报文。一旦完成这两步,初始发送FIN报文的主机将不能再发送数据。然而,连接的另一端仍能够发送数据。连接的另一端仍能够继续发送数据。在完成数据发送后,它才会发送出一个FIN报文。在接收到最后返回的FIN/ACK报文后,这一端的状态才会迁移到CLOSED。
  • 窗口大小(Windows Size):16位。
  • 校验和:16位
  • 紧急指针:16位
  • 选项:可变长度

TCP三次握手

B的TCP服务进程先创建传输控制块TCB。准备接收客户进程的连接请求。然后服务器进程就处于LISTEN(收听)状态,等待客户的连接请求。如有,即作出响应。

A的TCP客户进程也是首先创建传输控制模块TCB。

第一次握手

A向B发送连接请求报文段:SYN=1,同时选择一个初始序号seq=x。此时TCP客户进程进入SYN-SENT(同步已发送)状态

第二次握手

B收到连接请求报文段后,如同意连接,则向A发送确认。在确认报文段中,SYN=1,ACK=1,确认号是ack=x+1,同时也为自己选择一个出事的序列号seq=y。这个报文段也不能携带数据,但要消耗一个序列号。此时TCP服务器进程进入SYN_RCVD(同步收到)状态

第三次握手

TCP客户端收到B的确认后,还要向B给出确认,确认报文段的ACK=1确认号为ack=y+1,表示服务端希望下一个数据报发送序号从x+1开始的字节,而自己的序列号为seq=x+1(ACK报文没有携带数据)。TCP连接已建立,A进入ESTABLISHED(已建立连接)状态。B收到A的确认后,也进入ESTABLISHED(已建立连接)状态

  • 序列号:用于标识报文,以方便对报文进行重组。有时报文会无序到达。
  • 序号并不是从 0 开始的, 而是由发送方随机选择的初始序列号 ( Initial Sequence Number, ISN )开始
  • SYN报文段(SYN=1的报文段)不能携带数据,但要消耗掉一个序列号。
  • ACK报文可以携带数据,但如果不携带数据则不消耗序列号

为什么需要三次握手

教科书原话:防止失效的连接请求报文段被服务端接收,从而产生错误。

失效的连接请求:若客户端向服务端发送的连接请求丢失,客户端等待应答超时后就会再次发送连接请求,此时,上一个连接请求就是『失效的』

一个例子:

  • 在上一个TCP连接中,A向B发送的SYN报文段滞留在网络中的某处,于是A超时重传,与B建立了TCP连接,交换了数据,最后也释放了TCP连接。
  • 但滞留在网络中某处的陈旧的SYN报文段,现在又突然传送到了B,如果不使用三次握手,那么B就以为A现在请求建立TCP连接,于是就分配资源,等待A传送数据。但是A没有想与B建立TCP连接,也不会向B传送数据,B就白白浪费资源等待A发送数据。
  • 如果是三次握手,那么B收到A发送的陈旧的SYN报文段后,就向A发送SYN报文段,选择自己的序列号seq=y,并确认收到A的SYN报文段,其确认号为ack=x+1。当A收到B的SYN报文段时,从确认号中可得知不应当理睬这个SYN报文段(因为A现在并没有发送seq=x的SYN报文段)。这是A发送复位报文段,在这个报文段中,RST=1,ACK=1,其确认号ack=y+1。我们注意到,虽然A拒绝了TCP连接的建立(发送了复位报文段),但对B发送的SYN报文段还是确认收到了。
  • B收到A的RST报文段之后,知道不能建立TCP连接,就不会再等待A发送数据了。

握手的本质

同步双方的初始序列号

TCP 需要 seq 序列号来做可靠重传或接收,而避免连接复用时无法分辨出 seq 是延迟或者是旧链接的 seq,因此需要三次握手来约定确定双方的 ISN(初始 seq 序列号)

TCP 的可靠连接是靠 seq( sequence numbers 序列号)来达成,TCP 设计中一个基本设定就是,通过TCP 连接发送的每一个报文,都有一个sequence number。而因为每个报文都是有序列号的,所以都能被确认收到这些包。确认机制是累计的,所以一个对sequence number X 的确认,意味着 X 序列号之前(不包括 X) 包都是被确认接收到的。

TCP 怎么样识别之前旧链接重发的包?

需要独一无二的 ISN(初始序列号)机制。当一个新连接建立时,初始序列号( initial sequence number ISN)生成器会生成一个新的32位的 ISN。这个生成器会用一个32位长的时钟,差不多4µs 增长一次,因此 ISN 会在大约 4.55 小时循环一次(2^32位的计数器,需要2^32*4 µs才能自增完,除以1小时共有多少µs便可算出2^32*4 /(1*60*60*1000*1000)=4.772185884 )而一个段在网络中并不会比最大分段寿命(Maximum Segment Lifetime (MSL) ,默认使用2分钟)长,MSL 比4.55小时要短,所以我们可以认为 ISN 会是唯一的。

TCP A                                                TCP B
​1.  CLOSED                                               LISTEN
​
2.  SYN-SENT    --> <SEQ=100><CTL=SYN>               --> SYN-RECEIVED
​
3.  ESTABLISHED <-- <SEQ=300><ACK=101><CTL=SYN,ACK>  <-- SYN-RECEIVED
​
4.  ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK>       --> ESTABLISHED
​
5.  ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK><DATA> --> ESTABLISHED
​Basic 3-Way Handshake for Connection Synchronization

在上图

  • 第二行中, A 发送了 SEQ 100,标志位是 SYN;
  • 第三行,B 发回了 ACK 101 与 SEQ 300,标志位是 SYN 与 ACK(两个过程合并了)。注意,ACK 是101意味着,B 希望接收到 101序列号开始的数据段。
  • 第四行,A 返回了空的数据,SEQ 101, ACK 301,标志位为 ACK。至此,双方的开始 SEQ (也就是 ISN)号100与300都被确认接收到了。
  • 第五行,开始正式发送数据包,注意的是 ACK 依旧是第四行的301,因为没有需要 ACK 的 SYN 了(第四行已经 ACK 完)。

以上,4 最后这个确认的过程,是可以带上数据的。

三次握手的原则设计是防止旧复用链接的初始化导致问题,为了解决此问题,我们设计了reset这个特别的控制信号来处理。

如果接收中的 TCP 在一个未同步状态如 SYN-SENT, SYN-RECEIVED,它会返回 reset 给对方。

如果 TCP 是同步状态中如(ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT),他会终止此连接并通知用户。

TCP A                                                TCP B
​1.  CLOSED                                               LISTEN
​2.  SYN-SENT    --> <SEQ=100><CTL=SYN>               ...
​3.  (duplicate) ... <SEQ=90><CTL=SYN>               --> SYN-RECEIVED
​4.  SYN-SENT    <-- <SEQ=300><ACK=91><CTL=SYN,ACK>  <-- SYN-RECEIVED
​5.  SYN-SENT    --> <SEQ=91><CTL=RST>               --> LISTEN​6.              ... <SEQ=100><CTL=SYN>               --> SYN-RECEIVED
​7.  SYN-SENT    <-- <SEQ=400><ACK=101><CTL=SYN,ACK>  <-- SYN-RECEIVED
​8.  ESTABLISHED --> <SEQ=101><ACK=401><CTL=ACK>      --> ESTABLISHED
​Recovery from Old Duplicate SYN

这是 复用连接时,旧在途包发往新连接中的例子。

  • 3中,一个旧的重复的 SYN到达 B
  • 4中, B分别不出是否旧的,照样子正常回包。
  • 5中,A检测到 B 返回的ACK不正确,所以返回 RST(reset)
  • 6中,B接收到 RST(reset)信号,于是变成 LISTEN 状态。
  • 7中,新连接正常的 SYN终于到达了,三次握手正常进行。

这种是简化的情况,但是可以看出 TCP 是如何处理复用旧链接的包到达的。

作者:山尽
链接:https://www.zhihu.com/question/24853633/answer/573627478

TCP四次挥手

TCP是全双工的,在四次挥手中,前两次挥手用于断开一个方向的连接,后两次挥手用于断开另一个方向上的连接。

第一次挥手

若A认为数据发送完成,则它需要向B发送连接释放请求。该请求只有报文头,头中携带的主要参数为:

FIN=1,seq=u。此时A将进入FIN_WAIT-1状态。

  • FIN=1,表示该报文段是一个连接释放请求。
  • seq=u,u-1是A向B发送的最后一个字节的序号

第二次挥手

B收到连接释放请求后,会通知相应的应用程序,告诉它A向B这个方向的连接已经释放。此时B进入CLOSE_WAIT状态,并向A发送连接释放的应答,其报文包含:ACK=1,seq=v,ack=u+1。

  • ACK=1,除TCP连接请求报文段以外,TCP通信过程中的所有数据报的ACK都为1,表示应答。
  • seq=v,v-1是B向A发送的最后一个字节的序号。
  • ack=u+1表示希望收到从第u+1个字节开始的报文段,并且已经成功接收了前u个字节。

A收到应答后,进入FIN_WAIT-2状态,等待B发送连接释放请求。

第二次挥手完成后,A到B方向的连接已经释放,B不会在接收数据,A也不会再发送数据。但B到A方向的连接仍然存在,B可以继续向A发送数据。

第三次挥手

当B向A发完所有数据后,向A发送连接释放请求,请求头:FIN=1,ACK=1,seq=w,ack=u+1。B进入LAST_ACK状态。

第四次挥手

A收到释放请求后,向B发送确认应答,此时A进入TIME_WAIT状态。该状态会持续2MSL时间,若该状态内没有B的重发请求的话,就进入CLOSED状态,撤销TCB。当B收到确认应答后,也便进入CLOSED状态,撤销TCB。

图片来源 https://juejin.im/post/5b29d2c4e51d4558b80b1d8c
  • FIN_WAIT_1 :FIN_WAIT_1 和FIN_WAIT_2 两种状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是: FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了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()主动要求关闭连接。注意:FIN_WAIT_2 是没有超时的(不像TIME_WAIT 状态),这种状态下如果对方不关闭(不配合完成4次挥手过程),那这个 FIN_WAIT_2 状态将一直保持到系统重启,越来越多的FIN_WAIT_2 状态会导致内核crash。

  • TIME_WAIT :表示收到了对方的FIN报文,并发送出了ACK报文。 TIME_WAIT状态下的TCP连接会等待2*MSL(Max Segment Lifetime,最大分段生存期,指一个TCP报文在Internet上的最长生存时间。每个具体的TCP协议实现都必须选择一个确定的MSL值,RFC 1122建议是2分钟,但BSD传统实现采用了30秒,Linux可以cat /proc/sys/net/ipv4/tcp_fin_timeout看到本机的这个值),然后即可回到CLOSED 可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。

  • CLOSING :这种状态在实际情况中应该很少见,属于一种比较罕见的例外状态。正常情况下,当一方发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING 状态表示一方发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?那就是当双方几乎在同时close()一个SOCKET的话,就出现了双方同时发送FIN报文的情况,这是就会出现CLOSING 状态,表示双方都正在关闭SOCKET连接。

  • CLOSE_WAIT :当对方close()一个SOCKET后发送FIN报文给自己,你的系统毫无疑问地将会回应一个ACK报文给对方,此时TCP连接则进入到CLOSE_WAIT状态。接下来呢,你需要检查自己是否还有数据要发送给对方,如果没有的话,那你也就可以close()这个SOCKET并发送FIN报文给对方,即关闭自己到对方这个方向的连接。有数据的话则看程序的策略,继续发送或丢弃。简单地说,当你处于CLOSE_WAIT 状态下,需要完成的事情是等待你去关闭连接。

  • LAST_ACK :当被动关闭的一方在发送FIN报文后,等待对方的ACK报文的时候,就处于LAST_ACK 状态。当收到对方的ACK报文后,也就可以进入到CLOSED 可用状态了。

为什么需要四次挥手

因为TCP是一个全双工协议,必须单独拆除每一条信道。4次挥手的目的是终止数据传输,并回收资源,此时两个端点两个方向的序列号已经没有了任何关系,必须等待两方向都没有数据传输时才能拆除虚链路,不像初始化时那么简单,发现SYN标志就初始化一个序列号并确认SYN的序列号。因此必须单独分别在一个方向上终止该方向的数据传输

TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

为什么要等待2MSL

MSL:报文段最大生存时间,它是任何报文段被丢弃前在网络内的最长时间。
原因有二:

  1. 为了保证A发送的最后一个确认报文段能够到达B。这个确认报文段可能会丢失,如果B收不到这个确认报文段,其会重传第三次“挥手”发送的FIN+ACK报文,而A则会在2MSL时间内收到这个重传的报文段,每次A收到这个重传报文段后,就会重启2MSL计时器。这样可以保证A和B都能正常关闭连接。

  2. 为了防止已失效的报文段出现在下一次连接中。A经过2MSL时间后,可以保证在本次连接中传输的报文段都在网络中消失,这样一来就能保证在后面的连接中不会出现旧的连接产生的报文段了。

第一点:如果主机1直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致主机2没有收到主机1最后回复的ACK。那么主机2就会在超时之后继续发送FIN,此时由于主机1已经CLOSED了,就找不到与重发的FIN对应的连接。所以,主机1不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。
第二点:如果主机1直接CLOSED,然后又再向主机2发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达主机2,由于新连接和老连接的端口号是一样的,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。

为什么不是1MSL

2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

参考连接:

再深谈TCP/IP三步握手&四步挥手原理及衍生问题—长文解剖IP

tcp为什么要三次握手

TCP 为什么是三次握手,而不是两次或四次?

关于 TCP/IP,必知必会的十个问题

TCP的三次握手和四次挥手相关推荐

  1. 一文搞懂TCP的三次握手和四次挥手

    目录 1.三次握手 2.四次挥手 3.11种状态名词解析 TCP的三次握手和四次挥手实质就是TCP通信的连接和断开. 三次握手:为了对每次发送的数据量进行跟踪与协商,确保数据段的发送和接收同步,根据所 ...

  2. 为什么有TCP 的三次握手 和 四次挥手

    由于我们的设备上的通信程序很直接,所以当时没有仔细想过TCP的三次握手和四次挥手这个问题,有的时候自己写的时候 会忘掉这个问题,就是为什么会有三次握手的过程和4次挥手的过程 简单来说就一句话 &quo ...

  3. TCP的三次握手和四次挥手的过程?

    TCP的三次握手和四次挥手的过程? 如下2幅图 如下2幅图

  4. c++TCP的三次握手和四次挥手

    该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105043395 T ...

  5. 了解TCP的三次握手和四次挥手

    了解TCP的三次握手和四次挥手 一.    TCP/IP OSI参考模型 了解TCP的三次握手和四次挥手,我们首先从TCP/IP OSI参考模型说起. OSI(Open System Intercon ...

  6. TCP连接三次握手和四次挥手

    摘要: 本文主要介绍TCP连接三次握手和四次挥手的机制. 1.三次握手 (1)三次握手的详述 首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资源.Clie ...

  7. TCP的三次握手和四次挥手及常见面试题

    一.前言 今天上掘金查看热门文章,发现一篇好文 ★前端 100 问:能搞懂 80% 的请把简历给我 ★ ,此文包含100个前端面试问题,仔细阅读完所有题目后,顿感身中数刀无法呼吸,留下了没有技术的泪水 ...

  8. 【运维面试】面试官问到tcp/ip三次握手,四次挥手,这么回答就对了

    我之前面试过很多运维人员,每次都绕不开tcp/ip三次握手,四次挥手: 面试者的回答也是八仙过海各显神通 有讲故事的,有画图的,有把自己讲晕了的: 那这个该怎么回答呢? 我总结下来可以这么来说: 三次 ...

  9. TCP和UDP区别以及TCP的三次握手和四次挥手

    TCP和UDP的概念 TCP: 传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的.可靠的.基于字节流的传输层通信协议 UDP: Internet 协议 ...

  10. 【重难点】【计算机网络 02】TCP 和 UDP 的区别、TCP 的三次握手和四次挥手、HTTP 和 HTTPS、HTTP 各版本之间的区别、HTTP 如何实现长连接

    [重难点][计算机网络 02]TCP 和 UDP 的区别.TCP 的三次握手和四次挥手.HTTP 和 HTTPS.HTTP 各版本之间的区别.HTTP 如何实现长连接 文章目录 [重难点][计算机网络 ...

最新文章

  1. 前沿地带:从量子计算到量子互联网
  2. html/css 的基础知识
  3. 从医院到家,再重返SAP成都研究院
  4. SAP CRM 中间件Request download里,遇到/SAPPSPRO/S_MAT_ENHANC_COMM 错误的解决办法
  5. Android之BaseAdapter—convertView回收机制与动态控件响应
  6. ★LeetCode(704)——二分查找(JavaScript)
  7. scp实现mac与linux服务器之间文件传输
  8. [转载] 跟着吴恩达学机器学习(Machine Learning) on Coursera 第一天
  9. Codeforces 781B. Innokenty and a Football League
  10. MATLAB 求一个矩阵的最大值极其所在位置
  11. deeplab v3 ppt_「秋叶PPT」被这件事难倒的张雨绮,撕开了千万职场人最羞愧的一面...
  12. clover windows安装_记一次使用AMD安装macOS Catalina的经历
  13. 原生js获取cookie
  14. excel index 函数
  15. Apache(阿帕奇)Web服务器的安装和使用
  16. u盘复制到计算机的文档打不开怎么办,U盘文件复制到别的电脑打不开怎么办
  17. 日期插件(默认显示当前日期)---年月
  18. 如何一行代码安装ROS|2022最新版|一行代码安装ROS2|一行代码解决rosdep|一行代码配置多ROS环境
  19. 腾讯视频QLV文件格式转换MP4格式
  20. 六大计算机应用领域,人工智能领域六大分类

热门文章

  1. 用计算机好还是自己算好作文,计算机考试后感优秀作文
  2. 精品基于Uniapp+SSM实现的作业管理app
  3. uniapp——uni-admin后台管理系统(使用uniCloud免费云服务器)
  4. 静图怎样合成gif动图?仅需三步在线制作GIF动图
  5. 《Go语言精进之路,从新手到高手的编程思想、方法和技巧1》读书笔记和分享
  6. IOS微信后台运行时候倒计时暂停问题
  7. 「维基解密」:西游记死亡人数
  8. 理解“万事万物皆对象”
  9. Codeforces Round #817 (Div. 4)
  10. Cerebral Cortex:初为人父者竟然出现纵向灰质皮层体积减少?两个国际样本提供了这样的证据...