草庐IT

【Javaweb】TCP原理(三次握手四次挥手)

-孤单又灿烂的神- 2023-06-02 原文

目录

一、TCP协议

二、TCP原理

1,确认应答机制

2,超时重传机制

3,连接管理机制

4,滑动窗口

5,流量控制

6,拥塞控制

7,延迟应答

8,捎带应答

9,粘包问题


一、TCP协议

TCP,即Transmission Control Protocol,传输控制协议。人如其名,要对数据的传输进行一个详细的 控制。

TCP协议段格式

源/目的端口号:表示数据是从哪个进程来,到哪个进程去;

序列号:在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一 次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。

确认应答号:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决不丢包的问题。

6位标志位:

URG:紧急指针是否有效

ACK:确认号是否有效,该位为 1 时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的 SYN 包之外该位必须设置为 1 。

PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走

RST:对方要求重新建立连接;我们把携带RST标识的称为复位报文段,该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接。

SYN:请求建立连接;我们把携带SYN标识的称为同步报文段,该位为 1 时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。

FIN:通知对方,本端要关闭了,我们称携带FIN标识的为结束报文段,该位为 1 时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时, 通信双方的主机之间就可以相互交换 FIN 位为 1 的 TCP 段。

二、TCP原理

TCP对数据传输提供的管控机制,主要体现在两个方面:安全和效率。 这些机制和多线程的设计原则类似:保证数据传输安全的前提下,尽可能的提高传输效率。

1,确认应答机制

2,超时重传机制

因此主机B会收到很多重复数据。那么TCP协议需要能够识别出那些包是重复的包,并且把重复的丢弃掉。这时候我们可以利用前面提到的序列号,就可以很容易做到去重的效果。

这时候我们可以利用前面提到的序列号,就可以很容易做到去重的效果。

        最理想的情况下,找到一个最小的时间,保证 "确认应答一定能在这个时间内返回"。

        但是这个时间的长短,随着网络环境的不同,是有差异的。

        如果超时时间设的太长,会影响整体的重传效率;

        如果超时时间设的太短,有可能会频繁发送重复的包;

TCP为了保证无论在任何环境下都能比较高性能的通信,因此会动态计算这个最大超时时间。

        Linux中(BSD Unix和Windows也是如此),超时以500ms为一个单位进行控制,每次判定 超时重发的超时时间都是500ms的整数倍。

        如果重发一次之后,仍然得不到应答,等待 2*500ms 后再进行重传。

        如果仍然得不到应答,等待 4*500ms 进行重传。依次类推,以指数形式递增。

        累计到一定的重传次数,TCP认为网络或者对端主机出现异常,强制关闭连接。

3,连接管理机制

SYN同步报文段,尝试和对方建立连接,JavaSocket API中,客户端new Socket内核就会发起这样的SYN请求

SYN这个标志位为1,表示是一个同步报文段

我能听见(ACK),你能听见我吗(SYN)

 建立连接的过程,相当于通信双方各自给对方发送SYN,再各自给对方发送ACK中间的ACK和SYN和二为一,于是最后就是“三次握手”

能否只有两次握手

服务端状态转化:

[CLOSED -> LISTEN] 服务器端调用listen后进入LISTEN状态,等待客户端连接;

[LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段),就将该连接放入内核等待队 列中,并向客户端发送SYN确认报文。

[SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文,就进入ESTABLISHED状 态,可以进行读写数据了。

[ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用close),服务器会收到结束 报文段,服务器返回确认报文段并进入CLOSE_WAIT;

[CLOSE_WAIT -> LAST_ACK] 进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之 前的数据);当服务器真正调用close关闭连接时,会向客户端发送FIN,此时服务器进入 LAST_ACK状态,等待最后一个ACK到来(这个ACK是客户端确认收到了FIN)

[LAST_ACK -> CLOSED] 服务器收到了对FIN的ACK,彻底关闭连接。

客户端状态转化:

[CLOSED -> SYN_SENT] 客户端调用connect,发送同步报文段;

[SYN_SENT -> ESTABLISHED] connect调用成功,则进入ESTABLISHED状态,开始读写数据;

[ESTABLISHED -> FIN_WAIT_1] 客户端主动调用close时,向服务器发送结束报文段,同时 进入FIN_WAIT_1;

[FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认,则进入 FIN_WAIT_2,开始等待服务器的结束报文段;

[FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段,进入TIME_WAIT,并发 出LAST_ACK;

[TIME_WAIT -> CLOSED] 客户端要等待一个2MSL(Max Segment Life,报文最大生存时 间)的时间,才会进入CLOSED状态。

重要的转状态:

1,LISTEN:服务器启动完毕,随时可以有客户端来连接

2,ESTABLISHED:建立连接成功,随时传输消息

服务器调用new ServerSocket就会绑定端口号,并且进入LISTEN状态

客户端调用new Socket,就会尝试和服务器建立连接并触发三次握手

三次握手不能只握两次,如果没有最后一个ACK,此时主机B是无法知道自己发送能力和对方接受能力是否正常

三次握手,握手四次可以但没必要,中间的SYN和ACK是同一时刻触发的

3,CLOSE_WAIT:四次挥手挥手一半剩下的两次就不挥手了(接收方没调用close方法,就会导致四次挥手只挥手两次,从而没有正确关闭连接)。

4,TIME_WAIT:谁主动断开连接,谁进入TIME_WAIT状态,此时主机已经完成四次挥手过程,但是仍然不能立即释放,要等TIME_WAIT状态保持一定时间之后释放

三次握手和四次挥手过程出现丢包就会触发超时重传

4,滑动窗口

没有滑动窗口的机制下,传输N份数据,就需要等待N次应答时间,总的传输时间:N份数据传输时间+N份应答时间。

滑动窗口的实质就是批量传输数据,总的传输时间:N份数据传输时间重叠成1份时间。

窗口:不等待ACK的情况下,批量发送的最大数据量,就叫“窗口大小”

滑动:形象的比喻,窗口的范围就是表示当前哪些数据在等待ACK,随着一个ACK到达,就立刻发送下一个数据,等待的数据包范围就在逐渐滑动

窗口的大小不变,当发送方收到2001的ACK,就意味着1001-2000的数据对方已经收到,此时立刻传输5001-6001的数据,此时等待的ACK数据包序号就是2001、3001、4001、5001.

ACK丢了

1001这个ACK丢了,2001这个ACK没丢,就认为1-1000这个数据也是顺利到达的,1001丢了就丢了,无所谓,2001能够包含1001ACK中的信息。

数据包就直接丢了

如果数据报丢了,例如1001-2000丢了,然后2001-3000,3001-4000等后面的这几个数据都顺利到达,此时主机B反馈的ACK的确认的序号始终是1001,如果主机A发现连续几个ACK都是1001,主机A就知道1001这个数据报丢失,就会重传1001

当主机B收到1001这个数据的时候,由于刚才到达2001-7000这些数据前面都已经收到了,接下俩ACK就从7001开始,重传只是重传丢失的数据,其他数据不需要额外重传

5,流量控制

接收端处理数据的速度是有限的。如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应。 因此TCP支持根据接收端的处理能力,来决定发送端的发送速度。这个机制就叫做流量控制(Flow Control);

接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 "窗口大小" 字段,通过ACK端通知 发送端;

窗口大小字段越大,说明网络的吞吐量越高;

接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端;

发送端接受到这个窗口之后,就会减慢自己的发送速度;

如果接收端缓冲区满了,就会将窗口置为0;这时发送方不再发送数据,但是需要定期发送 一个窗口探测数据段,使接收端把窗口大小告诉发送端。

流量控制本质上,是根据接受方的处理能力来制约发送方的发送效率

根据接受缓冲区的剩余空间大小,来制约发送方的滑动窗口

通过TCP报头中的“窗口大小字段”来反映给发送方

6,拥塞控制

虽然TCP有了滑动窗口这个大杀器,能够高效可靠的发送大量的数据。但是如果在刚开始阶段就发送大 量的数据,仍然可能引发问题。 因为网络上有很多的计算机,可能当前的网络状态就已经比较拥堵。在不清楚当前网络状态下,贸然发送大量的数据,是很有可能引起雪上加霜的。 TCP引入 慢启动机制,先发少量的数据,探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传 输数据;

拥塞控制由于不好衡量传输路径的拥堵情况,只能通过反复试探的方式,逐渐试探出应该要用多大的窗口

1,通过一个较小的窗口大小开始试探

2,如果没有发生拥堵(没有丢包)就指数方式扩大拥塞窗口

3,达到一定阈值后,线性增加窗口大小

4,一直到出现丢包,窗口回到初始值,调整阈值为出现丢包的窗口大小的一半

7,延迟应答

如果接收数据的主机立刻返回ACK应答,这时候返回的窗口可能比较小。

假设接收端缓冲区为1M。一次收到了500K的数据;如果立刻应答,返回的窗口就是500K;

但实际上可能处理端处理的速度很快,10ms之内就把500K数据从缓冲区消费掉了;

在这种情况下,接收端处理还远没有达到自己的极限,即使窗口再放大一些,也能处理过来;

如果接收端稍微等一会再应答,比如等待200ms再应答,那么这个时候返回的窗口大小就是 1M;

窗口越大,网络吞吐量就越大,传输效率就越高。我们的目标是在保证网络不拥塞的情况 下尽量提高传输效率;

8,捎带应答

在延时应答的基础上,进一步提高程序运行效率而引入的机制

 客户端和服务器之间的通信模式一般都是Requet-Response模式,“一问一答”

主机B要给主机A返回两个数据,严格的说,这两个数据的传输时机是不一样的

Req发送内核收到数据,就会立刻返回ACK,Resp返回应用程序代码,执行完Resp把响应写回客户端,才发送的响应

由于存在延时应答,ACK的传输时机有延时,延时的时间足够让英语程序完成响应计算,应用程序

返回Resp的时候发现刚才的ACK还没发,就在Resp的基础上,顺便捎带一个ACK的值

9,粘包问题

首先要明确,粘包问题中的 "包" ,是指的应用层的数据包。 在TCP的协议头中,没有如同UDP一样的 "报文长度" 这样的字段,但是有一个序号这样的字 段。 站在传输层的角度,TCP是一个一个报文过来的。按照序号排好序放在缓冲区中。 站在应用层的角度,看到的只是一串连续的字节数据。 那么应用程序看到了这么一连串的字节数据,就不知道从哪个部分开始到哪个部分,是一个 完整的应用层数据包。

那么如何避免粘包问题呢?归根结底就是一句话,明确两个包之间的边界。

对于定长的包,保证每次都按固定大小读取即可;例如上面的Request结构,是固定大小 的,那么就从缓冲区从头开始按sizeof(Request)依次读取即可; 对于变长的包,可以在包头的位置,约定一个包总长度的字段,从而就知道了包的结束位 置; 对于变长的包,还可以在包和包之间使用明确的分隔符(应用层协议,是程序猿自己来定 的,只要保证分隔符不和正文冲突即可)

有关【Javaweb】TCP原理(三次握手四次挥手)的更多相关文章

  1. 【Unity游戏破解】外挂原理分析 - 2

    文章目录认识unity打包目录结构游戏逆向流程Unity游戏攻击面可被攻击原因mono的打包建议方案锁血飞天无限金币攻击力翻倍以上统称内存挂透视自瞄压枪瞬移内购破解Unity游戏防御开发时注意数据安全接入第三方反作弊系统外挂检测思路狠人自爆实战查看目录结构用il2cppdumper例子2-森林whoishe后记认识unity打包目录结构dll一般很大,因为里面是所有的游戏功能编译成的二进制码游戏逆向流程开发人员代码被编译打包到GameAssembly.dll中使用il2ppDumper工具,并借助游戏名_Data\il2cpp_data\Metadata\global-metadata.dat

  2. 计算机网络笔记:TCP三次握手和四次挥手过程 - 2

    TCP是面向连接的协议,连接的建立和释放是每一次面向连接的通信中必不可少的过程。TCP连接的管理就是使连接的建立和释放都能正常地进行。三次握手TCP连接的建立—三次握手建立TCP连接①若主机A中运行了一个客户进程,当它需要主机B的服务时,就发起TCP连接请求,并在所发送的分段中用SYN=1表示连接请求,并产生一个随机发送序号x,如果连接成功,A将以x作为其发送序号的初始值:seq=x。主机B收到A的连接请求报文,就完成了第一次握手。客户端发送SYN=1表示连接请求客户端发送一个随机发送序号x,如果连接成功,A将以x作为其发送序号的初始值:seq=x②主机B如果同意建立连接,则向主机A发送确认报

  3. Slowloris DoS攻击的原理与简单实现 - 2

    前言    Slowloris攻击是我在李华峰老师的书——《MetasploitWeb 渗透测试实战》里面看的,感觉既简单又使用,现在这种攻击是很容易被防护的啦。不过我也不敢真刀实战的去试,只是拿个靶机玩玩罢了。         废话还是写在结语里面吧。(划掉)结语可以不看(划掉)Slowloris攻击的原理        Slowloris是一种资源消耗类DoS攻击,它利用部分HTTP请求进行操作。也叫做慢速攻击,这里的慢速并不是说发动攻击慢,而是访问一条链接的速度慢。Slowloris攻击的功能是打开与目标Web服务器的连接,然后尽可能长时间的保持这些连接打开。如果由多台电脑同时发起Slo

  4. [蓝桥杯单片机]学习笔记——串口通信的基本原理与应用 - 2

    目录一、原理部分1、什么是串行通信(1)并行通信与串行通信(2)串行通信的制式(3)串行通信的主要方式  2、配置串口(1)SCON和PCON:串行口1的控制寄存器(2)SBUF:串行口数据缓冲寄存器 (3)AUXR:辅助寄存器​编辑(4)ES、PS:与串行口1中断相关的寄存器(5)波特率设置  3、串口框架编写二、程序案例一、原理部分1、什么是串行通信(1)并行通信与串行通信微控制器与外部设备的数据通信,根据连线结构和传送方式的不同,可以分为两种:并行通信和串行通信。并行通信:数据的各位同时发送与接收,每个数据位使用一条导线,这种方式传输快,但是需要多条导线进行信号传输。串行通信:数据一位一

  5. ruby - # Ruby 中识别方法约定的基本原理/历史是什么? - 2

    例如,我一直看到称为String#split的方法,但从未见过String.split,这似乎更合乎逻辑。或者甚至可能是String::split,因为您可以认为#split位于String的命名空间中。当假定/隐含类(#split)时,我什至单独看到了该方法。我知道这是ri中识别方法的方式。哪个先出现?例如,这是为了区分方法和字段吗?我还听说这有助于区分实例方法和类方法。但这从哪里开始呢? 最佳答案 不同之处在于您如何访问这些方法。类方法使用::分隔符来表示消息可以发送到类/模块对象,而实例方法使用#分隔符表示消息可以发送到实例对

  6. H264压缩原理 - 2

    1、为什么压缩的原始数据一般采用YUV格式(1)利用人对图片感觉的生理特性,对于亮度信息比较敏感,对于色度信息不太敏感,所以视频编码是将Y分量和UV分量分开来编码,并且可以减少UV分量.2、视频压缩原理(1)空间冗余:图像相邻像素之间的相关性,比如一帧图片被划分成多个16x16的块之后,相邻的块之间有很多明显的相似性。(2)时间冗余:时间相差较近的两张图片变化较小。(3)视觉冗余:我们的眼睛对某些细节不太敏感,对图像中的高频信息的敏感度小于低频信息,可以去除一些高频信息。(4)编码冗余:一幅图片中不同像素出现的概率是不同的,对于出现次数较多的像素,用少的位数来编码,对于出现次数较少的像素,用多

  7. Python——程序的运行原理 - 2

    Python程序运行原理Python是一种脚本语言,编辑完成的程序,也称源代码,可以直接运行。从计算机的角度看,Python程序的运行过程包含两个步骤:解释器将源代码翻译成字节码(即中间码),然后由虚拟机解释执行。Python程序文件的扩展名通常为.py。在执行时,首先由Python解释器将.py文件中的源代码翻译成中间码,这个中间码是一个扩展名为.pyc的文件,再由Python虚拟机(PythonVirtualMachine,PVM)逐条将中间码翻译成机器指令执行。需要说明的是,pyc文件保存在Python安装目录的pycache文件夹下,如果Python无法在用户的计算机上写人字节码,字节

  8. ruby - yarn 未初始化常量 Socket::SOL_TCP - 2

    我在这里尝试使用yarn,遇到了一个可能与ruby​​相关的问题。在执行任何yarn命令,我收到错误.../.rvm/gems/ruby-2.3.0/gems/yarn-0.1.1/lib/yarn/server.rb:14:in':uninitializedconstantSocket::SOL_TCP(NameError)错误堆栈:$yarn.../.rvm/gems/ruby-2.3.0/gems/yarn-0.1.1/lib/yarn/server.rb:14:in':uninitializedconstantSocket::SOL_TCP(NameError)Didyoume

  9. ruby - 你如何使用 Ruby 找到空闲的 TCP 服务器端口? - 2

    我正在尝试创建一个使用一次的HTTP服务器来处理单个回调,并且需要帮助在Ruby中找到一个空闲的TCP端口。这是我正在做的事情的框架:require'socket't=STDIN.readport=8081whiles=TCPServer.new('127.0.0.1',port).acceptputss.getss.print"HTTP/1.1200/OK\rContent-type:text/plain\r\n\r\n"+ts.closeexitend(它回显标准输入到第一个连接然后死掉。)如何自动找到空闲端口进行监听?这似乎是在远程服务器上启Action业然后使用唯一作业ID回调

  10. mysql - Rails 数据库连接池的工作原理 - 2

    我正在学习Rails数据库连接池概念。在Rails应用程序中,我将池大小定义为5。我对连接池大小的理解如下。当服务器启动时,rails会自动创建n个在database.yml文件中定义的连接。在我的例子中,它将创建5个连接,因为池大小为5。在每个http请求上,如果需要访问数据库,rails将使用连接池中的可用连接来处理请求。但我的问题是,如果我一次达到1000个请求,那么大部分请求将无法访问数据库连接,因为我的连接池大小只有5个。我上面对rails连接池的理解对吗??谢谢, 最佳答案 目的:数据库连接不是线程安全的;所以Activ

随机推荐