TCP协议同样是运输层的协议,掌握TCP重点要关注这几个问题:顺序问题、丢包问题、连接维护、流量控制、拥塞控制。先解析下TCP报文段结构,相比于UDP要复杂很多。

  • 首先还是两个端口号,对应着具体的应用进程。
  • 序号指的是包的序号,为了解决包乱序问题。
  • 发出去的包应该有确认,如果接收方没有收到就应该重新发送,直到送达。确认序号解决的是丢包问题。
  • 由于TCP选项字段的原因,TCP首部长度是可变的。通常选项字段为空,所以TCP首部字段长度一般是20字节。
  • 窗口大小用于流量控制,用来指示接收方愿意接收的字节数量。
  • 选项字段用于发送方与接收方协商最大报文段长度或者在高速网络环境下用作窗口调节因子。
  • 标志字段由6个状态位组成,SYN是发起一个连接、ACK是回复、RST是重新连接、FIN是结束连接。URG表示报文段里存在着被发送端的上层实体置为“紧急” 的数据,紧急数据的最后一个字节由16b位的紧急数据指针字段指出。实际使用中,PSH、URG和紧急数据指针用不到。

所有的问题起于连接,先关注连接管理问题。TCP的连接建立分为三步,通常称为三次握手。具体的的状态是:

客户端收到服务端发送的 SYN 和 ACK 之后,发送ACK 的 ACK,之后处于 ESTABLISHED 状态,因为它一发一收成功了。服务端收到 对ACK 的 ACK 之后,处于 ESTABLISHED 状态,因为它也一发一收了。

为什么不是两次、四次或者更多次?

  比如AB要建立连接,A发起一个连接但连接请求没有响应,可能包丢了、包绕弯路了、超时了等等,A于是继续给B发包,终于B收到了请求包但A并不知道,所以A可能还会继续发。B收到包之后,知道了A存在并且要和它建立连接。如果B不想建立连接,A重试一会后放弃,连接建立失败没有问题。如果B愿意建立连接,那就会发应答包给A。同样这个应答包会和请求包出现一样的问题,那么对于B不能认为连接建立好了。

  B发送的应答包可能会发送多次,只要有一次到达A,那么A就认为连接已经建立了,因为A的消息有去有回,相当于两次握手。假如这时候连接已经建立,并且做了简单通信后,结束了连接。上面讲了A要建立连接的时候,可能会发送多个请求包。有的请求包绕了一大圈又回来了,B 会认为这也是一个正常的的请求,再次建立连接,但这个连接不会正常接发数据、也不会终结,B就一直等待。A发的消息有去有回,但B发出的消息没有回,所以两次握手肯定不行。其实三次握手中,A发给B回复的回复也会丢、绕路或者B挂了,按照这个逻辑B还要再发个确认就变成了四次握手,这样不停套娃多达几百次也可以,但这也不能保证就可靠了。TCP连接的设计原则是双发的消息都有去有回就基本可以了。

  大部分情况下,A和B建立连接后会A会马上发送数据,如果A发给B的应答丢了,A后续发送的数据到达时,B可以认为连接已经建立;又或者B挂了,那么直接报错返回B不可达信息都没问题。如果A就是不发送数据,客户端可以开启keeplive机制,发送探活包。服务端设置规定时间,超时了就主动关闭,释放资源。

  TCP把数据看成一个无结构、有序的字节流,一个报文段的序号是该报文段首字节的字节流编号。三次握手除了确保双方消息有去有回,最重要的是解决tcp包的序号问题。A、B双方互相告知对方包的起始序号。又会有个疑问,为什么一定要交换序号,不能从序号1开始发包吗?假设A给B发3个包,序号为1、2、3,但3包可能绕路了,没有正常到达B,A又重新发送。后来A掉线了,重新连上B后又从1开始,发送两个包1、2,但上次出问题的包3又回来了,发给了B,B认为这就是A要发给它的下一个包,于是出现错误。因此每个连接都要有不同的序号,序号的起始序号每4ms加一,等遇到重复的序号要4个多小时。比如3号包绕路了,就要隔4个多小时连接的起始序号才是3,这么长时间3号包已经无效了,因为IP包头里有TTL(生存时间)。

再来看四次挥手,前两次和握手连接差不多。同样将发送接收方用AB表示。当B进入CLOSED-WAIT,A进入FIN-WAIT2状态时,如果B突然挂了,那么A会一直处于这个状态,TCP本身没有对这种个状态进行处理。在Linux中可以调整 tcp_fin_timeout 参数,设置超时时间。

  如果一切正常,进行第三次挥手A收到B的主动关闭请求并发送确认后进入TIME-WAIT状态,为什么需要这个状态呢?假设A发送完确认消息后直接关闭,如果B没收到这个确认消息,那B会重发结果就是B关闭失败。还有一种情况是A的端口空出来,但B还保持原来状态不知道A的情况。如果 A 的端口被一个新的应用占用了,这个新的应用会收到上个连接中 B 发过来的包,数据接收错误。所以A要进入TIME-WAIT状态,并且TCP设置了等待时间2MSL(报文段最大生存时间),任何报文在网络上存在超过这个时间将被丢弃。协议规定 MSL 为 2 分钟,实际应用中常用的是 30秒,1 分钟和 2 分钟等。还有一种情况是超过了2MSL,B依然没有收到对FIN的ACK。这时即便A收到了B重发的FIN,A会直接发送RST,表示重新开始挥手。

参考资料:《趣谈网络协议》刘超

     《计算机网络:自顶向下方法》原书第六版 陈鸣译

详解TCP一:三次握手、四次挥手的更多相关文章

  1. 详解 TCP的三次握手四次挥手

    本文转载来自https://blog.csdn.net/qzcsu/article/details/72861891 背景描述 通过上一篇中网络模型中的IP层的介绍,我们知道网络层,可以实现两个主机之 ...

  2. 端口状态 LISTENING、ESTABLISHED、TIME_WAIT及CLOSE_WAIT详解,以及三次握手四次挥手,滑动窗口(整理转发)

    网上查了一下端口状态的资料,我下面总结了一下,自己学习学习: TCP状态转移要点 TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死 ...

  3. 详解TCP的三次握手四次断开

    本文将分别讲解经典的TCP协议建立连接(所谓的“3次握手”)和断开连接(所谓的“4次挥手”)的过程. 尽管TCP和UDP都使用相同的网络层(IP),TCP却向应用层提供与UDP完全不同的服务.TCP提 ...

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

    如果对网络工程基础不牢,建议通读<细说OSI七层协议模型及OSI参考模型中的数据封装过程?> 下面就是TCP/IP(Transmission Control Protoco/Interne ...

  5. [na]TCP的三次握手四次挥手/SYN泛洪

    1.TCP报文格式 上图中有几个字段需要重点介绍下: (1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记. (2)确认序号:Ack序号,占32位, ...

  6. 救救孩子吧,到现在还搞不懂TCP的三次握手四次挥手

    本文在个人技术博客同步发布,详情可用力戳 亦可扫描屏幕右侧二维码关注个人公众号,公众号内有个人联系方式,等你来撩...   前几天发了一个朋友圈,发现暗恋已久的女生给我点了个赞,于是我当晚辗转反侧.彻 ...

  7. TCP/IP三次握手四次挥手

    本文通过图来梳理TCP-IP协议相关知识.TCP通信过程包括三个步骤:建立TCP连接通道,传输数据,断开TCP连接通道.如图所示,给出了TCP通信过程的示意图. TCP 三次握手四次挥手 主要包括三部 ...

  8. TCP协议—三次握手四次挥手的原理<转>

    三次握手四次挥手的原理   TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接.在TCP/IP协议中,TCP 协议提供可靠的连接服务,连接是通过三次握手进行初始化的.三 ...

  9. 第6章 传输层(详解TCP的三次握手与四次挥手)

    第6章 传输层 传输层简介 传输层为网络应用程序提供了一个接口,并且能够对网络传输提供了可选的错误检测.流量控制和验证功能.TCP/IP传输层包含很多有用的协议,能够提供数据在网络传输所需的必要寻址信 ...

  10. 通俗了解TCP/IP三次握手四次挥手

    前言: tcp/ip通信机制是计算机中很重要的一个知识点,不是一句两句就能解释清楚的,需要反复推敲其中的玄妙. 通俗理解: 但是为什么一定要进行三次握手来保证连接是双工的呢,一次不行么?两次不行么?我 ...

随机推荐

  1. 使用itext asian 解决中文不显示的问题

    本人使用的itextpdf版本是5.4.3<dependency> <groupId>com.itextpdf</groupId> <artifactId&g ...

  2. Zookeeper分布式过程协同技术 - 群首选举

    Zookeeper分布式过程协同技术 - 群首选举 群首概念 群首为集群中服务器选择出来的一个服务器,并被集群认可.设置群首目的在与对客户端所发起的状态变更请求进行排序,包括:create.setDa ...

  3. Markdown-it-latex2img

    Markdown-it-latex2img LaTex plugin for markdown-it markdown parser,Server side MathJax Renderer. Bac ...

  4. 通用Mapper与分页插件的集成

    SpringBoot 是为了简化 Spring 应用的创建.运行.调试.部署等一系列问题而诞生的产物,自动装配的特性让我们可以更好的关注业务本身而不是外部的XML配置,我们只需遵循规范,引入相关的依赖 ...

  5. js写一个简单的日历

    思路:先写一个结构和样式,然后写本月的时间,之后计算上下月份的关系 <!DOCTYPE html> <html lang="en"> <head> ...

  6. 阿里云安全组规则授权对象设置为固定IP段访问

    阿里云的ESC建站需要在安全组放通一些端口才能正常访问,所以我们在开放端口的时候就直接设置了全部ip可访问,授权对象填入0.0.0.0/0,意味着允许全部ip访问或者禁止全部ip访问. 但是我们有了一 ...

  7. nth-child,nth-last-child,after,before,tab-highlight-color,first-child,last-child

    nth-child:定义第几个元素或者是奇数或者是偶数,或者满足某个数字倍数的dom的样式 如 li:nth-child(3n),结果如下,li:nth-child(2)结果如下

  8. vue页面数据强制更新渲染

        vue数据更新会出现缓存的情况,几种方式可以让数据实时渲染到页面: 1.简单粗暴的方式 this.$forceUpdate();//强制更新 2.增减元素 splice() push() 3. ...

  9. SQL注入笔记-updatexml与extractvalue

    0x1介绍 MySQL 5.1.5版本中添加了对XML文档进行查询和修改的函数 EXTRACTVALUE(XML_document, XPath_string); UPDATEXML(XML_docu ...

  10. 14.刚体组件Rigidbody

    刚体组件是物理类组件,添加有刚体组件的物体,会像现实生活中的物体一样有重力.会下落.能碰撞. 给物体添加刚体: 选中游戏物体->菜单Component->Physics->Rigid ...