传输层UDP、TCP

目录

一、UDP

1.1、再谈端口号

1.2、UDP协议的格式

1.3、UDP的特点

1.4、面向数据报

1.5、UDP的缓冲区

1.6、UDP使用的注意事项

二、报文的理解

三、TCP

1.1、TCP协议的各个字段

4位首部长度

TCP可靠性的本质

32位序号和32位确认序号

16位窗口号

6位标志位

16位紧急指针

1.2、缓冲区的理解

1.3、如何理解丢包--超时重传机制

1.4、三次握手

1.5、四次挥手

1.6、滑动窗口

1.7、流量控制

1.8、拥塞控制

1.9、延迟应答

1.10、面向字节流、粘包问题

1.11、TCP异常情况


一、UDP

1.1、再谈端口号

端口号标识了要将报文传给主机上地哪一个应用程序

在TCP/IP协议中,使用{源ip、源端口号、目的ip、目的端口号、协议号}这样的五元组来标识一个通信,可以通过netstat -n来进行查看。

0~1023都是知名端口号,1024~65535是我们可以自行使用的端口号。使用命令 cat /etc/services可以看到知名端口号。

一个进程是否可以绑定多个端口号?答案是可以,只要不和其他的进程绑定的端口号冲突即可;

一个端口号是否被多个进程绑定,答案是不可以。

1.2、UDP协议的格式

观察协议格式,如何做到对UDP报文的分离?很简单,UDP是定长报文,报文最大长度是固定的,用16个比特位表示,并且报头长度固定,先拿到前八个字节,之后提取16位UDP报文长度,减去前八个字节就可以提取数据部分了;

如何分用?UDP报文中右目的端口字段,通过此字段就可以知道这个UDP报文要交给上层哪一个应用程序了,通过端口号的变更实现分用。

这是UDP的源码结构体,可以看到每一个字段都是固定大小的。

UDP在网络中不需要序列化和反序列化,直接传结构体即可,因为就算每个主机的操作系统不同,但是操作系统内核都是C语言写的,传输层是实现在内核中的,因此直接传结构体是可以的(需要保证大小端一致和内存对齐),双方都可以认识;为什么应用层不行呢?因为应用层每台主机可能使用的语言不同,直接传对方不认识,必须序列化和反序列化才行。

1.3、UDP的特点

无连接、不可靠(没有确认机制没有重传机制)、面向数据报

1.4、面向数据报

对方一次性发多少你也只能一次接受多少,不能循环分批接收。

1.5、UDP的缓冲区

UDP没有发送缓冲区只有接收缓冲区;这也是UDP是不可靠的原因之一;我们知道TCP是可靠的,它有发送缓冲区,当发送缓冲区发送数据给对方要是对方没有接收到或者对方的接收缓冲区满了,此时无法正常发送怎么办,那就需要重传,而TCP有发送缓冲区,它在发送一个报文之后不会立即将这个报文从发送缓冲区删掉,而是看是否正常发送了,对方接收到了才会删除,这就保证了可靠性。而UCP没有发送缓冲区。

至于接收缓冲区,不能保证接收到的报文和发送的报文顺序一致。

UDP是全双工的。

1.6、UDP使用的注意事项

一个UDP报文最大大小是64k,当发送的报文大于这个大小时,需要在应用层手动的分包进行发送。

二、报文的理解

如果应用层正在进行报文的解析那么会不会影响OS从网络中读取报文,为什么?

不会,应用层解析报文 = 用户态行为,内核接收报文 = 内核态独立行为,中间有内核缓冲区 做异步缓冲,应用解析快慢不影响内核收包 ,只有应用不及时调用 recv,导致缓冲区满,才会丢包。

在OS内部可能同一时间会有很多个报文,那么就需要对其进行管理(先描述再组织)

会有对应的结构体存在sk_buff,就像是进程的PCB一样,其中指针指向内存的报文的各个区域,向上交付报文,这个结构体的data指针就会向下移动,向下封装报文,这个指针就会向上移动,所谓封装和解包本质上就是移动data指针再缓冲区中的指向。

三、TCP

1.1、TCP协议的各个字段

选项可有可无,选项及以上都是TCP报头,下面是有效载荷。

如何分用交付?16位端口号。

4位首部长度

如何进行报头和有效载荷的分离?首先看到4位首部长度:表示0到15,TCP的基本单位是4字节,TCP报头至少为20个字节,所以首部长度至少是4,报头最大为60字节,所以首部长度最大为15,也就是1111。通过这个进行有效载荷和报头的分离。为什么没有标识报文大小的字段呢?因为TCP是面向字节流的,发送多少不需要严格控制,不像UDP一次发送一个数据报,并且IP报文中有三部分IP报头、TCP报头、TCP有效载荷,只需要做减法即可计算出TCP有效载荷大小。

TCP可靠性的本质

在长距离通信中,A发送一个消息给B,A需要知道B知否收到,B发送应答,此时B也需要这个应答是否被A收到,A再发送,A又需要知道自己的应道知否被知道。很明显,这样一来无法保证消息是否发送的可靠。

但是在这个过程中却可以保证历史消息的可靠性,比如A发送之后,B应答,那么A就可以百分之百保证自己之前发送的消息是被正确接受了的,是可靠的(让报文不是最新的即可保证可靠性)。而最新的消息没有应答,可靠性无法保证。要保证可靠性,TCP中处于核心地位的就是确认应答机制

A收到应答,保证A->B通信的可靠性,反之是B。

32位序号和32位确认序号

实际上更加通用的通信过程往往一次会发送多个报文(假设有3个),A发送多个请求,B需要对这些请求响应,请求是带有序号的(假设是100、200、300),返回的响应带有确认序号,若是都正确响应那就是101、201、301(确认序号=序号+1)。对于某一个确认报文,成功响应,那么说明序号在这个序号之前的报文已经被成功接收了 ,例如返回了301,表示100,200,300都成功接收了,但是只返回201,说明100,200成功接受了,但是300没有。另外,发送的报文需要是按顺序来的,但是接收方接收的顺序却不一定和发送的一致,通过序号也可以保证请求报文的顺序性,解决乱序问题,提高可靠性

但是为什么既要有序号又要有确认序号呢?上面的过程通过一个序号就可以完成了呀。这里提出一个概念,捎带应答,也是就是对方接收之后返回应答的同时也可以发送自己想要发送的消息,那么此时的应答捎带着返回,而此时也需要两个序号,一是对对方请求的确认序号,二是自己发送数据的序号,方便对方发送确认序号来确认的。

TCP通信的时候传递的都是TCP报文,可以没有有效载荷,但是报头是肯定要有的。

16位窗口号

在传输数据的过程中,可能出现接收方接收缓冲区空间不足的情况,此时发送方发送报文,接收方的处理就是丢弃,直到接收缓冲区有空间了,才会正常接收;

那么这样丢弃,发送方不知道接收方是缓冲区不足,可能以为是其他情况导致的丢弃,于是发送方会进行重传,此时若接收缓冲区一直没有空余,那么就一直丢弃,发送方一直重传,那么就会浪费资源;

因此提出了一个字段,窗口号,这个字段描述的是发送方自己的接收缓冲区剩余空间大小,让对方知道此时还可不可以发,可以发多少;例如发送方发送自己的请求报文过去,接收方接收缓冲区不足,此时接收方会返回一个响应报文,这个报文的窗口号描述了自己的接收缓冲区剩余空间的大小,发送方通过此报文知道了对方的接收缓冲区信息,然后就可以自行决定要不要发了;

这个字段还可以作用于反面,返回的响应报文的窗口号描述的剩余空间很大,那么接收方知道了,会加大自己发送的速率以及报文大小(如有需要),这就是流量控制。

6位标志位

这些标志位实际上就是一个一个比特位,它标识了发送给对方的报文是什么类型的。

首先介绍ACK、SYN、FIN标志位,要先了解一下三次握手和四次挥手:

发送方发送建立连接的请求报文,接收方发送捎带响应报文,发送方发送对此报文的响应报文:SYN是同步标志位(建立连接,握手过程中使用的标志位)、ACK是对请求报文的响应报文中的设置字段,响应报文中这个标志位一定被置为1,握手过程中接收方发送捎带响应报文中就是SYN+ACK、最后发送的是ACK(ACK在绝大多数报文中都被设置为1)

有一个这样的问题:有没有一种可能握手过程中发送的报文会出超过接收缓冲区剩余空间的大小?不会,因为握手过程中发送的报文不带有有效载荷,而TCP的缓冲区只会存方有效载荷,不会被报头大小影响,而且三次握手过程中双方也已经协商好了对方的接受能力。

四次握手,发送断开连接的报文,需要把报文中的FIN字段设置为1,这个字段表示此时发送的报文是一个结束报文,对方发送ACK确认,在发送FIN结束,发送方发送ACK确认,因为TCP是全双工的,两方都对对方有连接,因此必须要两方都断。

PSH字段:提示接收方应用程序立刻从TCP接收缓冲区将数据读走。

RST字段:对方要求重新建立连接,把RST字段为1的报文成为复位报文段。比如有这样一种情况,握手过程中,A发送SYN之后接收到SYN+ACK表示自己A->B的连接是建立成功了,但是B->A还没有,必须要A向B发送ACK,B接收到了才会确认。因此两方在三次握手过程中连接建立成功的时间不一致,那么要是A发现A->B建立成功了之后直接发送数据,而此时B->A还没有建立成功,因为这中间有一个时间差,那么B接收了就会判断出错,此时就会发送一个复位报文段,要求A重新建立连接。在通信过程中出现任何问题都可以发送这个字段报文,要求进行复位重置。

16位紧急指针

在数据传输的过程中,虽然有序号给每个报文编号,保证对方接收到报文是按照发送顺序接收的,但是实际情况中其实有很多紧急情况,要求某一个报文优先被处理,比如这个取消上传这个紧急事件,不先处理这个报文还会一直先上传前面的,后面还要删除效率很低。因此会给描述紧急报文的URG标识位设置为1,并且这个紧急数据是写在有效载荷之中的,它只占一个字节,一般是以状态码的形式给出,16位紧急指针实际上就是状态码在有效载荷之中的偏移。只有当URG为1,16位紧急指针才有效。接收方回显判断有无URG为1的字段,有则先处理。这个紧急报文也只是极少数情况,一般都是按顺序到达处理。紧急数据也叫带外数据,不是常规数据。

至此TCP协议中各个字段都介绍完了,40个字节的选项没什么好说的,16位校验和也很简答。

1.2、缓冲区的理解

实际上可以将缓冲区看作是一个一位数组,而每一个报文都有序号,因此将报文的有效载荷放入这个一维数组中就可以把序列化看作是下标来进行发送读取了。

1.3、如何理解丢包--超时重传机制

A发送数据,发送的数据丢失B没有接收到可以认为是丢包;但是A发送成功但是B发送的ACK报文A没有收到,那么A就不能武断地认为自己发送地报文丢失了,实际上是ACK还没到,但是A不知道,A会以最坏得情况处理,认为自己发送的丢失了,会进行重传。

这就是超时重传:A会先等待一段时间,之后若是还是没有ACK,A就重发;但是这个等待时间不应该是固定的,因为ACK的响应到达时间受到网络的影响,网络好,那么ACK就快,此时将等待时间设置的很长明显就不合适,因为若本来就没有ACK(ACK就是丢失了),还是会傻傻地等待,其实没用;若是网络差,那么ACK响应很慢,此时等待时间设置的很短,那么就会一直重发,实际上只需要再等一会就行了,就可以收到ACK了,此时会浪费资源;

如何设置超时的时间(就是等待时间)呢?初始值一般是500ms,也就是第一次超时重传等待时间为这个,若是还是没有接收到,第二次等待就是2*500ms,依次累加,到一定次数会认为网络或者对端主机出现异常,直接断开连接。

可能有很多次,重传之后B的缓冲区可能存在多个相同报文有效载荷,此时通过前面提到的序列号进行去重。

1.4、三次握手

首先三次握手是什么?

三次握手就是双方在通信之前的的连接建立的过程。

怎么做?

第一次握手(SYN) 客户端发送一个带 SYN=1 的报文,告诉服务器:我要发起连接,并给一个初始序列号。

第二次握手(SYN+ACK) 服务器回复 SYN=1、ACK=1

ACK 表示 "收到你的请求";SYN 表示 "我也同意建立连接"同时服务器也给出自己的初始序列号。

此时A->的连接实际上已经建立

第三次握手(ACK) 客户端再发 ACK=1 :确认收到服务器的同意,双方正式进入已连接状态,可以传输数据,此时B->A也已经建立。

connect发起建立连接请求,accept获取已经建立好的连接,这两个本质上没有参与连接的建立过程,连接的建立是由client和server的OS自动完成的。

对应每次报文的接收还有主机状态的改变,A发送SYN,状态变为STN_SENT,B接收状态变为SYN_RCVD,发送SYN+ACK,A接收,状态变为ESTABLISHED,发送ACK,B接收状态变为ESTABLISHED。这些状态实际上就是一个一个整数,这些整数体现在哪呢?我们知道,服务端和客户端是1:n的关系,那么在同一时间就很可能出现一个服务器里面有多个连接的建立过程,那么就需要对这些连接进行管理,先描述再组织,用结构体描述,状态就是结构体内部的整数,用数据结构组织即可;所以说TCP相较于UDP是比较耗费资源的,结构体的创建耗费了时间和空间。

那么最重要的问题就是为什么要进行三次握手呢?首先握手是必然的,要建立连接嘛,所以这个问题可以这样问,为什么不是两次握手,四次五次?因为三次握手是以最快的方式验证全双工 :第一次SYN收到SYN+ACK那么A->B的连接就建立好了,此时全双工完成了一半,SYN+ACK中的SYN被A收到,A发送ACK,B收到,全双工建立完毕,这样很快就可以确定全双工是可以的,其他次数的握手要么不足以验证全双工,要么多余操作过多;其次进行三次握手的第二个原因就是三次握手以最小的成本确认了双方的通信意愿。

三次握手实际上是四次握手,只是爹日次发送报文时捎带应答了,可拆分,做了优化。举一反三,可以发现,四次挥手实际上也可以优化成为三次握手。

1.5、四次挥手

断开连接的本质是断开双方连接的共识。

一方调用close关闭自己的读写fd,这个接口调用直接发送FIN报文,此时这一方无法对TCP进行读写了,状态变为FIN_WAIT1,后序的报文发送都是由内核进行的;

另一方接收到FIN报文,会发送其响应报文,状态变为CLOSE_WAIT,此时它不一定会直接发送FIN关闭自己的文件描述符,因为它可能还有响应报文没有发送,这就是为什么四次挥手可以优化成三次,就是因为另一方需要发送剩余报文,所以不会直接捎带应答。当调用close就会发送FIN报文,此时对方收到之后发送响应报文状态变为TIME_WAIT,这一方收到应答之后TCP连接就关闭了。

close必须调用,否则会占着文件描述符,造成文件描述符资源泄露,因为内核中文件描述符的个数也是有限的,占用了就不能被重复占用。

TIME_WAIT状态是什么?首先系统会根据此连接历史发送的报文在网络中的时间统计出一个最大网络中报文的最大生存时间MSL,这个TIME_WAIT就是在接收到FIN之后等待2*MSL个时间,这个状态是最开始发起断开连接请求的一方才会有。为什么要等待?因为可能有残余的报文留存在网络中,要等待对方接收到丢弃这个报文才行,报文有四元组,在等待的时候这个发送端口无法重新绑定,这也是为什么之前的代码断开连接之后立即重新绑定会出错的原因,也正是因为这样,才保证了安全性,因为重新绑定的端口一定不是这个等待的端口,这样就不会出现历史残余报文被新建立起的连接的对方收到;有一种方法可以直接强制重新绑定这个等待端口,setsocket(),此时怎么办呢?对面看你收到历史报文呀,其实也不用担心,在三次握手中双方已经知道了对方报文序号的范围,新建立的连接根据序号判断这个报文是否正确,历史残余报文很可能和新建立连接的序号范围不一样,这样已经可以很大程度上避免错误了;其实TIME_WAIT还有一个好处,就是对方发送FIN我发送ACK之后,对方可能接收不到,此时对方会超时重传,这个等待时间给了对方机会超时重传,这样断开连接的成功性更大。

1.6、滑动窗口

之前说过,实际上TCP发送报文不是发一次响应一次,而是一次性发送多个报文,响应多个。那么发送报文的最大值应该由什么控制呢,不可能无限发送吧。

滑动窗口,这个东西是在发送缓冲区之内的,它有两个指针start和end,其中维护的就是滑动窗口的大小,滑动窗口将发送缓冲区分为了三部分,start前面是已发送已确认的,这一部分报文已经无效,可以覆盖,之前说的删除已发送已确认的报文其实不需要真正删除,覆盖即可,滑动窗口内的就是一次性可以直接发的,end之后的就是待发送的。滑动窗口宏观上是向后移动的

滑动窗口的大小由什么控制?对方应答中会有16为窗口号,衡量了对方的接收能力,这个就是滑动窗口的大小,一次性发送的必须让对方有接收能力,至于start就是响应报文的确认序号,这样就保证滑动窗口前面的都是已发送已确认的。滑动窗口就是流量控制的具体实现。

滑动窗口一定不会向左移动,可以变大(对方应用层一次读很多,返回的响应报文窗口号变大)、可以变小(写入很多,但是对方没怎么读)、可以不变(写入之后读取返回的窗口号大小恰好和上一次一样)

报文丢失了怎么办?假设是滑动窗口最左侧的报文丢失,若是请求报文正常被接受响应报文丢失,滑动窗口正常工作(因为响应报文一定会有更大的确认序号,那么就可以判断之前的报文都正常发送并且被接受了,这是确认序号的特性),若是请求报文丢失(假设是1001~2000),那么返回的报文确认序号一定是1001,此时需要重传;

并且同一个窗口内的请求报文的响应报文应该都是1001,这种情况收到连续三个以上重复应答,会进行快重传,重新发送窗口内的报文。

若是中间请求报文丢失,那么响应报文来到之后,新的滑动窗口最左侧就是原本滑动窗口中间的报文,此时和最左侧报文丢失的情况一样;

最右侧丢失同样如此。

快重传VS超时重传:快重传是提高效率的,超时重传是兜底的,一般而言,先触发的是快重传,只有ACK超过超时等待时间之后才会触发超时重传。重传的报文都是在滑动窗口内的,也就是说快重传和超时重传底层的支持都有滑动窗口(TCP的请求报文没有响应会将请求报文保存在滑动窗口内部)。

由此可以总结滑动窗口的一个特性:滑动窗口不能跳跃,这个跳跃指的是序号,必须要发送序号连续的请求,接收确认序号连续的响应。

1.7、流量控制

在三次握手的时候,双方都知道了对方的接受能力,因此后序正式发送带有数据的报文,不会造成因为对方接受能力不足的大量丢包问题;

三次握手前两次不能携带数据,但是第三次可以携带数据,第三次是A发送ACK报文,前两次握手A请求获得ACK应答,A已经确认了对方能收到,也就是全双工A->B连接建立完毕,那么第三次A其实可以直接发送捎带应答了;

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

当对方接受能力为0的时候,会返回一个应答报文,接收方通过此报文的确认序号以及窗口字段大小更新自己的滑动窗口大小,变为0,此时接收方就不会发送数据了。此后,还是要通信,但是A不知道对方能否接受,因此会定期发送一个窗口探测报文,当对方接收缓冲区不为0,A收到ACK就知道自己可以发送数据了,若是窗口探测结果一直是0,那么A在某些情况下需要立即发送数据,这个探测报文会带上PSH,要求对方TCP上层立即取走数据,要是还是不能发送,网络可能直接断开连接。

TCP窗口字段16bit,也就是窗口最大大小是65535byte,实际上还是可以增大的,选项字段有一个字段是窗口扩大因子M,实际的窗口大小是窗口字段左移M位。

1.8、拥塞控制

当大量丢包的时候可能就不是报文的问题了而是网络的问题,比如发1000个报文,丢失了998个,那么此时发送方就判定这是网络拥塞。

此时可以立即重发丢失报文吗?不行,因为此时重发大概率网络还没好,不仅不能成功发送,还会加剧网络拥塞,而且对方服务器可能在这个时间段不止为你一个客户端提供服务,此时重发,大量客户端大量报文都会拥塞住。所以这不是解决方法。

此时采用拥塞控制方法:

在出现拥塞的时候,客户端按照2^n这样的指数增长方式发送报文(个数),一次是1、2、4、8、16......,指数增长开始相对较慢,因此这个阶段称为慢开始,后面会急剧上升;

为什么会采用这种方法?开始慢慢发,获取应答,实际上是在探测网络是否恢复,若是每次发送的报文都有应答,那么可以判定网络恢复了;后面发送报文个数急剧上升,是因为此时形成了共识,网络不拥堵了,此时要尽快恢复通信过程。

但是之前说过,发送报文个数是由滑动窗口决定的呀,为什么现在会是1、2、4......这样的呢?首先为了支持拥塞控制算法,定义了一个整形值,拥塞窗口,这个拥塞窗口实际上描述的就是网络拥塞状况,比这个值小,说明不拥塞,反之网络是拥塞的,并且这个值是一个变化的值,因为网络状况一直在变,拥塞窗口也要变化。

实际上滑动窗口不仅仅等于对方的接受能力,而是min(对方的接受能力,拥塞窗口),取i较小的值,即考虑了网络情况,也考虑了对方能不能接收。

但是在拥塞控制的时候,不可能说拥塞窗口的值或者说发送报文的个数不能一直指数增长,这样不合理。但是也要变化,因为拥塞窗口衡量的就是网络拥塞情况,所以在指数增长达到了一个阈值ssthresh之后,会变为线性增长,为什么是线性增长呢?这是为了更准确地探测 网络地状况(线性增长很慢,且不会漏掉每一个值),这个过程叫做加法增大 ,当达到了网络拥塞的值,就会重新回答慢开始阶段,重复过程,这个急剧下降过程称为乘法减小,此后的ssthresh的值就是上一次最大拥塞窗口值的一半。

发送报文的个数不一定是拥塞窗口的大小,因为还需要考虑对方的接收能力,也就是不会随着拥塞窗口值增大,发送报文个数增大,那么为什么加法增大触碰到网络上限之后会立即慢开始了,按照上句话分析,此时发送报文个数不一定达到了网络上限啊?是因为此时不仅仅只有一个客户端发送报文,会同时存在多个客户端,那么此时探测到网络上限就必须慢开始。

这种拥塞控制是一种很精妙的设计方法,考虑了TCP的可靠性(应对网络拥塞)和效率(拥塞窗口的变化)

1.9、延迟应答

这个是提高TCP效率的一种方法。

正常来说,假设接收方接收缓冲区剩余大小为64kb,发送方发送10kb报文,接收缓冲区变为54kb,此时应答报文窗口字段就是54,决定了发送方的滑动窗口大小(拥塞窗口远大于此值时);但是若是这样设计,在接收方接收之后不立即应答,而是等待一段时间,让上层取走一部分数据,假设是20kb,此时接收缓冲区剩余空间大小为74kb,那么对方滑动窗口大小就是74,那么下一次发送就可以发送更多的报文,这就是延迟应答,提高发送效率。

两种方法:1、数量限制:每接收N个包才应答因此;2、时间限制:每隔Nms应答一次。这样也不会影响确认序号,因为应答的是更大的确认序号,前面的都正常接收了,确认序号也支持了延迟应答。

1.10、面向字节流、粘包问题

随便写随便读

面向字节流是优点,也会造成粘包问题。粘包问题首先是站在应用层的角度的问题,就是不知道每一个报文从那一部分开始到那一部分结束,可能误判出现上一个数据包粘着下一个数据包的问题,TCP的角度没有这种问题,TCP有序号,只管发送和接收数据按照序号顺序即可。而应用层看到的是一个连续的字符串,为了解决这问题可以在应用层定制协议,之前就写过这样的代码,发送时应用层就按照约定序列化,接受时按照同样的约定反序列化,这样就可以解决粘包问题,明确每一个报文的完整性,HTTP就是一个很好的协议。

UDP没有粘包问题,UDP面向数据报,发送和接收的都是一个完整的报文,上层要么不读,要么读就读完整的一个报文,有很明确的界限。

1.11、TCP异常情况

进程直接终止,那么TCP连接怎么办?进程终止文件描述符对应文件关闭(引用计数为1),但是不影响内核关闭连接,会正常发送FIN报文进行四次挥手;

机器重启:和进程直接终止情况相同,这也是为什么当电脑打开很多应用,直接关闭电脑会比开机之后立即关闭慢,因为要进行大量的断开连接过程;

机器掉电/网线断开:A网线断开,此时A发送数据发现异常会关闭自己A->B的连接,但是B不知道,此时若是重新连上网线,B发送报文给A,A发现A->B连接未建立,会发送reset报文重新建立连接;不过TCP有自己的保活机制,这里的体现就是B会定时向A发送报文,查看A是否能正常通信,若是不能,B会自己断开连接;也就是未及时断开的连接总是会正常的释放,这是TCP可靠性的体现之一。

相关推荐
必胜刻1 天前
Gin + WebSocket 连接池
websocket·网络协议·gin
(Charon)1 天前
【C++/Qt】C++/Qt 实现 TCP Server:支持启动监听、消息收发、日志保存
c++·qt·tcp/ip
X7x51 天前
网络基石:深入浅出路由交换技术,构建高效通信世界
网络·网络协议·交换技术
551只玄猫1 天前
【计算机网络 实验报告5】IP层协议分析
网络·网络协议·计算机网络·课程设计·ip·实验报告
Shingmc31 天前
【Linux】Socket编程UDP
网络·udp
思麟呀1 天前
数据链路层和物理层
网络·网络协议·http·智能路由器
春蕾夏荷_7282977251 天前
libhv vs2019 udp简单的实例
网络·udp·libhv·结构体
小苗卷不动1 天前
UDP服务端收发流程
linux·c++·udp
Jmmtmingrui1 天前
《趣谈网络协议》学习笔记 -- 第24讲
网络协议
孙同学_1 天前
【Linux篇】详解TCP/UDP传输层协议:全面拆解三次握手、四次挥手及可靠性机制
linux·tcp/ip·udp