【Linux网络编程】传输层协议
目录
一,传输层的介绍
二,UDP协议
2-1,UDP的特点
2-2,UDP协议端格式
三,TCP协议
3-1,TCP报文格式
3-2,TCP三次握手
3-3,TCP四次挥手
3-4,滑动窗口
3-5,流量控制
3-6,紧急指针
四,TCP/UDP对比
一,传输层的介绍
传输层负责数据能够从发送端传输接收端,毫无疑问,这里需要传输层需要拿到IP地址和对应程序的端口号。IP地址就是网络中主机的地址;端口号就是应用程序的地址,它标识了一个主机上进行通信的不同的应用程序。
当网络中的不同主机进行通信时,具体流程如下图:
端口号范围划分
- 0 - 1023:知名端口号。这些端口号是分配给系统级别的服务和应用,如HTTP服务运行在80端口,HTTPS运行在443端口,SSH服务运行在22端口等,这些服务协议的端口号都是固定的。
- 1024 - 65535:操作系统动态分配的端口号。这些端口号是客户端程序的端口号,是由操作系统从这个范围动态分配的。
对于知名端口号,存储在系统文件 /etc/services 中,我们可以使用指令:cat /etc/services 查看。当我们自己写一个程序使用端口号时,一定要避开这些知名端口号。
netstat工具和pidof工具
netstat是一个用来查看网络状态的重要工具指令。
语法:netstat [选项]
功能:查看网络状态
常用选项:
-n:拒绝显示别名,能显示数字的全部转化成数字。
-l:仅列出有在 Listen(监听) 的服務状态。
-p:显示建立相关链接的程序名。
-t(tcp简写):仅显示tcp相关选项。
-u(udp简写):仅显示udp相关选项。
-a(all简写):显示所有选项内容。
pidof用于查找正在运行进程的ID(PID)。它在查看服务器的进程id时非常方便。
语法:pidof [进程名]
功能:通过进程名,查看进程id
二,UDP协议
2-1,UDP的特点
UDP是面向数据包的,即应用层交给UDP多长的报文,UDP直接一次性发送,它不做任何处理。UDP没有真正意义上的发送缓冲区,它是直接将数据交给内核, 由内核将数据传给网络层协议。UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到数据的顺序和发送数据的顺序一致, 要是缓冲区满了,再到达的UDP数据就会被丢弃。
2-2,UDP协议端格式
UDP(用户数据报协议)协议报头格式相对简单,每个UDP报文分为UDP报头和UDP数据两部分,报头在数据的前面,具体格式的说明如下:
UDP报头由4个16位长(2字节)的字段组成,总共8个字节。这些字段分别说明该报文的源端口、目的端口、报文长度和校验值。结构如下图:
源端口:
占用16位,用于标识发送端的端口号。在表示不需要接收端回复数据的情况下,源端口号可以不指定,此时其值为0。
目的端口:
占用16位,用于标识接收端的端口号。
UDP长度:
占用16位,表示UDP数据包的总大小,包括报头和数据部分。这里长度字段的单位是字节,也就是说一个UDP能传输的数据最大长度是:2^16 - 1 = 65535字节,即64KB(包含UDP报头)。若需要传输的数据过大,就需要我们自己在应用层手动的分包,多次发送,并在接收端手动拼装。
校验值:
占用16位,用于错误检查,如果接收端在校验时发现了错误,将会立即丢弃该数据报。
三,TCP协议
TCP要保证数据的可靠性传输,同时又要提高性能,所以底层结构会相当的复杂。还有,TCP虽然能保证数据的可靠传输,但还会出现丢包情况。下面来具体研究TCP协议。
3-1,TCP报文格式
TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,它是对数据的传输进行一个详细的控制。TCP报文分为报头和数据两部分,具体的格式如下:
源/目的端口号:
表示数据是从哪个进程来,到哪个进程去。
32位序号:
TCP是一种可靠的传输协议,它使用的是序号与确认序号来保证数据的可靠传输。
序号是一个32位的字段,用于标识发送端发送字节流中每一个字节的顺序编号。在连接建立时,初始序号(ISN)是随机生成的。接收端使用这个序号字段来重组数据包,确保数据按正确顺序接收。例如,发送端的ISN为1000,那么第一个数据段的序号字段值为1000,第二个数据段的序号字段值为1000加上第一个数据段的长度,依此类推。序号确保了TCP传输的有序性。
序号在TCP通信的整个过程中都起着重要作用。在TCP建立连接(三次握手)时,序号用于标识发送数据的起始位置;在数据传输过程中,序号用于确保数据的顺序传输;在连接关闭时,序号也参与确保数据传输的完整性。
32位确认序号:
确认序号也是一个32位的字段,序号用于发送端标识数据,而确认序号用于接收端确认接收的数据。在TCP通信过程中,每当接收端成功接收到一个报文段后,就会向发送端发送一个包含确认序号的确认报文段,以告诉发送端数据以成功接收,保证了数据传输的可靠性,过程具体如下。
TCP保证数据传输的可靠性是以发送与应答实现的。收到应答表示数据以收到,确认序号就是用于告诉发送端,接收端已经成功接收了哪些数据,以及接收下一个什么序号的数据,若发送方在规定的时间内没有接收到应答,那么发送方就判定接收方没有收到数据(数据也可能是阻塞在路由中或其它情况),发送方就可能进行重传报文。注意:确认序号与序号通常同时存在,即接收方在应答的同时也顺便发送数据,即捎带应答。
确认序号的数值就是接收字段最后一个字节的序号值加一,即表明了该序号之前的所有数据已经正确无误地收到,也指明了下一个期待收到的字节序号。例如,接收端收到序号为1000到1999的数据段后,发送的确认报文中确认序号字段的值应为2000,表示已成功接收到1000到1999字节,且期望下一个字节为2000。
最后要说明一下,这种应答功能是由操作系统自动完成,确认序号只有当标志位ACK标志为1时才有效。
4位TCP报头长度:
报头长度是以4字节为基本单位的,表示该TCP头部有多少个32位bit(即有多少个4字节)。TCP头部最大长度是 (2^4 - 1) * 4 = 60字节。
6位标志位:
标志位用于控制数据传输中的特定行为,哪个标志位置为1,就对应哪个标志位的特定功能。以下是这6位标志位的详细介绍:
URG:紧急指针是否有效,标识紧急指针,下面会具体说明。
ACK:确认号是否有效。该标志表示应答域有效。当进行应答时,该标志位会置为1。
PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走,将缓冲区中的数据尽快向上方交付。
RST:表示对方要求重新建立连接。TCP建立通信连接时可能会出故障,该标志表示重新开始建立TCP连接。我们把携带RST标识的称为复位报文段。 SYN:表示本报文要请求建立连接。当SYN标志置位时,表示发送端希望初始化一个连接。该标志在TCP建立连接中运用。我们把携带SYN标识的报文称为同步报文段。
FIN:该标志用于结束一个TCP连接。当FIN标志置位时,表示发送端已经发送完所有数据,并请求关闭连接。我们称携带FIN标识的为结束报文段。
16位窗口大小:
表示发送该TCP报文的接受窗口还可以接受多少字节的数据量。这个字段用于流量控制,告知发送端,接受端的缓存大小,以此控制发送端发送数据的速率。下面会详细说明。
16位校验和:
用于确保传输的数据的完整性。它用一种简单的计算方法来确保数据的可靠传输。该位置发送端进行填充,接收端进行校验。如果校验不通过,则认为数据有问题。此处的校验和包含TCP首部和TCP数据部。
16位紧急指针:
标识数据中哪部分数据是紧急数据。当运用紧急指针时,URG标志位置为1,操作系统会优先读取该报文数据。
选项:
长度不定,最大40字节,暂时先忽略。
数据部分:
TCP报文段中的数据部分是可选的。在一个连接建立和一个连接终止时,双方交换的报文段仅有TCP首部。下面所说的报文段,都是指没有数据部分的报文。
3-2,TCP三次握手
TCP通信需要先建立起连接,如TCP套接字。TCP连接是通过三次握手来建立的。
第一次握手:客户端向服务器发送一个SYN报文段。这个报文段中的SYN标志位被置为1,表示客户端希望与服务端建立连接,同时指定自己的初始序号为x。此时,客户端从CLOSED状态进入SYN_SENT状态,即从关闭状态进入请求连接状态,等待服务器的确认。
第二次握手:服务器收到客户端的SYN报文段后,知道客户端请求建立连接。于是,服务器将SYN和ACK(SYN用于向客户端发起请求建立,ACK用于确认收到客户端的SYN报文段)标志位都置为1,确认序号字段的值设置为x+1(表示对客户端初始序号的确认),并随机产生一个自己的初始序号y,然后将这个SYN+ACK报文段发送给客户端,以确认连接请求。此时,服务器从LISTEN状态(监听状态,表示该端口是开放的,在等待被连接)进入SYN_RCVD状态(收到和发送一个连接请求后等待对方对连接请求的确认状态)。
第三次握手:客户端收到服务器的SYN+ACK报文段后,客户端将标志位ACK置为1,确认序号字段的值设置为y+1(表示对服务器初始序列号的确认),并将这个ACK报文段发送给服务器。服务器成功收到后,连接成功建立,服务器从SYN_RCVD状态进入ESTABLISHED状态(连接成功状态),随后就可以开始传输数据。
最后说明下,TCP三次握手属于建立连接的过程,是由双方操作系统自动完成。最开始阶段,双方连接都是处于CLOSED连接关闭阶段,在TCP套接字中,当服务端调用listen函数使服务器处于监听状态时,服务端TCP层就从CLOSED状态变为LISTEN状态。客户端使用connect向服务端请求建立连接,即一次挥手,客户端TCP层就从CLOSED状态变为SYN_SENT状态,connect阻塞等待服务器应答;这时,服务端一旦监听到连接请求,listen函数返回,服务端TCP层从LISTEN状态变为SYN_RCVD状态,并将该连接放入内核等待队列中。这里服务端还会向客户端发送ACK确认报文和SYN请求建立连接报文,即二次挥手;客户端收到报文段(之所以叫报文段是因为这里的报文是没有数据部分的)后,会向服务端发起ACK报文段以确认连接建立请求,connect函数返回,客户端TCP层从SYN_SENT状态变为ESTABLISHED状态,即三次握手;当服务端收到确认报文段后,连接成功建立,服务器从SYN_RCVD状态进入ESTABLISHED状态,accept函数返回,通信开始。至于中间功能,都是依靠操作系统来完成。
注意:第一次握手和第二次握手都是有应答的(捎带应答),第三次握手客户端向服务端发送数据时并没有应答,这里客户端默认的是服务端成功接收建立连接,若这里的第三次握手没有成功发送到服务端,客户端就开始向服务端发送数据了,这时,服务器端就会给客户端进行应答——发送RST报文段,告诉客户端要重新进行三次握手建立连接,即连接重置。还有,TCP连接是双方共同发送一次连接请求和确认一次连接请求,理论上,这至少需要四次握手来确认,但在实际应用中,第二次和第三次握手的过程可以合并,即捎带应答,因此最终只需要三次握手。
建立连接为什么要三次握手?
如果采用一次握手,在网络状况不佳的情况下,这个连接请求没有及时到达服务器,客户端可能会连续多次发送连接请求报文,而服务器却无法区分当前收到的请求是新的还是之前因网络堵塞而过期的请求。这可能导致服务器错误地接受或拒绝连接请求。除此外,服务器中还可能存在多个客户端发送的连接,即闲置连接(连接建立好但不用),使其维护成本过大,浪费资源。还有,一次握手过于简单,没有服务器的确认步骤,很容易使服务器受到其它主机的“连接”攻击。
如果采用两次握手,那么当第二次握手服务器向客户端发送一个SYN+ACK(确认)包作为响应时,由于服务器没有收到响应,这里服务器就会默认客户端收到数据,成功建立连接,若第二次握手客户端没有收到服务端发送过来的确认报文,客户端会重新开始请求建立连接,又会使服务器存在多个闲置连接。
三次握手是建立一个可靠双向数据传输通道的最小值。首先要明白,连接的建立是通信双方共同完成的,双方都要有一次发送数据以请求建立连接和收到应答以确认连接建立,只不过三次握手这里使用的是捎带应答。三次握手可以说是通信双方连接建立的最小成本,若握手次数过多,这里不仅会导致连接建立时间过长,还会导致连接建立过于复杂,维护连接的成本过大,浪费资源。其次,三次握手还可以解决网络中延迟的重复分组问题。例如,如果客户端发送的SYN报文段,由于网络延迟而迟迟未到达服务器,客户端可能会重发SYN报文段;如果此时原始的SYN报文段到达服务器,服务器会发送ACK报文段进行确认,但客户端在收到这个ACK报文段时,由于认为自己并未请求连接(因为它已经重发了SYN报文段并收到了新的确认),所以会忽略该ACK报文段,这样,就不会因为网络延迟而导致错误的连接建立。
TCP通信过程
当三次握手建立好连接时就可以开始双方的通信了。在TCP通信过程中,数据发送可能出现丢失或阻塞在路由及应答阻塞或丢失多种情况,发送方无法确定具体情况,这里采取的策略是若在一个特定的时间内(时间由网络状况而定,因为数据阻塞与网络状况有关)发送方没有收到应答,它就会重新发送,这种行为叫做超时重传。若报文重复收到(数据阻塞在路由中的情况,并没有丢失),发送方根据序号的唯一性会进行去重;若数据重传累计到一定的次数,TCP就认为网络或对方主机出现异常,强制关闭连接。
3-3,TCP四次挥手
TCP通信完毕后断开连接需要四次挥手,用于确保通信双方都能正常结束数据传输。四次挥手与三次握手基本相似——满足双方共同的需求,即请求关闭连接和确认对方连接关闭的请求,只是因为三次握手使用捎带应答,而四次挥手是具体分步进行,具体细节如下:
第一次挥手:客户端向服务器发送一个FIN报文段(FIN标志位被置为1),表示客户端没有数据要发送给服务器了,请求关闭连接,即TCP套接字客户端开始调用close函数。此时,客户端进入FIN_WAIT_1状态,其报文段序号等于前面已经传送过来数据的最后一个字节的序号加1。
第二次挥手:服务器收到客户端的FIN报文段后,发出一个ACK报文段(ACK标志位被置为1)进行确认,表示确认客户端没有数据要发送了。此时,服务器进入CLOSE_WAIT状态。注意:此时服务器可能还有数据需要发送给客户端,所以服务器还不会立即关闭连接通道。
第三次挥手:服务器向客户端发送一个FIN报文段,表示服务器也准备好关闭连接,即TCP套接字服务端调用close函数。此时,服务器进入LAST_ACK状态,等待客户端的确认。
第四次挥手:客户端收到服务器的FIN报文段后,发送一个ACK报文段进行确认。此时,客户端进入TIME_WAIT状态,服务器收到客户端的ACK报文段后,关闭连接并进入CLOSED状态。客户端在等待一段时间后,如果没有收到服务器的重传FIN报文段,则认为连接已经正常关闭,也可以关闭连接并进入CLOSED状态,即TCP套接字中close函数成功调用释放资源返回。
TCP套接字中,当我们启动服务端、客户端时,若强行终止服务端程序,如:按下Ctrl-C键,这时我们在以绑定相同的IP地址和端口号运行服务端后,会出现 bind error:Address already in use 错误提示,这是因为虽然服务端程序终止了,但TCP协议层的连接并没有完全断开,即四次挥手没有全部完成,IP地址和端口号资源还在被占用,因此不能再次监听同样的IP地址和端口,我们可以用netstat命令进行查看。
最后说明一下,四次挥手的发起者并非固定为客户端,服务器也可以首先发起第一次挥手。TCP协议规定,主动关闭连接的一方是处于TIME_ WAIT状态,若我们使用Ctrl-C先终止了服务端,那么服务端就是主动关闭连接的一方,而挥手流程基本一致。
断开连接为什么要四次挥手?
TCP连接是可靠传输且全双工连接,即数据可以在两个方向上同时传输。因此,当一方想要关闭连接时,需要分别关闭两个方向上的数据传输通道并要告知对方本地连接要关闭(确认对方关闭通道的请求),这就是为什么需要四次挥手的原因:第一次和第二次挥手关闭客户端到服务器的数据传输通道,第三次和第四次挥手关闭服务器到客户端的数据传输通道。还有,TCP四次挥手是一个复杂但必要的过程,它确保了TCP连接的可靠终止和资源的正确释放。
TIME_WAIT状态
在客户端处于TIME_WAIT状态下,客户端会等待一段时间(注意,这段时间足以保证两个方向上的数据都被丢弃,使得原来连接的数据包在网络中都自然消失),因为这里已经是最后一次挥手,没有确认报文段(报文段不知道是否成功被对方接收),客户端不知道服务端是否成功收到ACK确认报文段关闭连接通道。这里有两种情况:1,服务端成功接收到确认报文。2,ACK报文段丢失,服务端向客户端重传FIN报文段,客户端这里仍处于TIME_WAIT状态。
注意:客户端在TIME_WAIT状态结束后,延迟的FIN报文段到达的情况根本不会存在。TIME_WAIT状态持续的一段时间通常是2MSL,即最大报文生存时间。MSL是TCP报文段在网络中能够存活的最长时间,超过这个时间,报文段将被丢弃。2MSL的时间足以保证在两个传输方向上的尚未被接收或迟到的报文段在网络中都已经消失。MSL具体的数值可通过 cat /proc/sys/net/ipv4/tcp_fin_timeout 查看,查看如下。
TIME_WAIT状态的目的
TIME_WAIT状态不仅可以确保客户端发送的最后一个ACK报文段能够到达服务器,还能够处理由于网络延迟而导致重发的ACK报文段。当进行到四次挥手客户端向服务端发送ACK确认报文段时,如果这个ACK报文段丢失了,服务器在超时后会重新发送FIN报文段。客户端在TIME_WAIT状态下会进行等待一段时间,确保收到这个重传的FIN报文段并作出响应。如果收到了之前连接的延迟报文段,这些报文段将被丢弃。
为什么TIME_WAIT状态等待的时间是2MSL?
首先,TCP具有重传机制,这里重点看第三次挥手和第四次挥手,当发送方(发送FIN报文断)未收到接收方的确认(ACK)时,会重传未确认的报文段。注意:ACK报文段发出时,发送方就已经处于TIME_WAIT状态,若报文丢失,最坏情况是经过了MSL时间,重传的FIN报文段在最坏情况下也需要经过MSL时间(由于网络延迟),因此,IME_WAIT状态等待2MSL是能够保证重传报文段一定被接收。
其次,断开连接后,网络中还可能存在之前的延迟报文,若没有等待足够的时间让这些报文从网络中消失,那么当尝试建立新的连接时,这些迟到的报文可能会被错误地当作新连接的数据进行处理,导致数据错乱,而MSL是TCP报文的最大生存时间,只有一方主机是能够处于TIME_WAIT状态,因此TIME_WAIT持续存在2MSL的话就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失。
3-4,滑动窗口
上面我们讨论了确认应答策略,对每一个发送的数据段,都要给一个ACK确认应答,收到ACK后再发送下一个数据段。这样做有一个比较大的缺点,就是性能较差,尤其是当网络状况不佳的情况下。
一发一收的方式性能较低,那么我们一次发送多条数据,就可以大大的提高性能(其实是将多个段的等待时间重叠在一起了)。TCP滑动窗口机制允许发送方在不需要等待每个数据段的确认应答的情况下连续发送多个数据段,并确保数据的有序传输,防止发送方发送数据过快导致接收方处理不过来。
下面来说明一下窗口大小。窗口大小指的是无需等待确认应答而可以继续发送数据的最大字节。上图的窗口大小就是4000个字节(四个段),发送前四个段的时候,不需要等待任何ACK,可以直接发送。
发送方的滑动窗口
滑动窗口位于缓冲区。在发送方,滑动窗口用于控制可以连续发送但尚未得到接收方确认的数据量。发送方的窗口大小取决于接收方通过TCP头部中的 “窗口大小” 字段通知的最大可接受数据量和网络情况(网络状况会影响数据的传输速率)。这个窗口会在发送方的缓冲区中移动,表示当前允许发送的数据范围。
- 窗口左边界:指向最早未被确认的数据字节。
- 窗口右边界:指向允许发送的最大序列号,即当前窗口的末尾。
当接收方确认数据后,窗口会向右滑动,允许发送更多数据。发送方的缓冲区这里可以分为三部分:滑动窗口左边的部分是已经发送并得到应答的数据,滑动窗口中的数据是可发送的部分,滑动窗口右边的数据是待发送的部分。滑动窗口向右滑动就是准备发送右边的数据。
接收方的滑动窗口
在接收方,滑动窗口用于管理接收缓冲区中的数据。接收窗口的大小取决于接收缓冲区中剩余的空间量和接收方处理数据的能力。接收方通过TCP头部的“窗口大小”字段向发送方报告其接收窗口的大小,从而控制发送方的发送速率。
- 接收窗口左边界:指向下一个期望接收的字节序号。
- 接收窗口右边界:指向接收缓冲区能够容纳的最大字节序号,即当前窗口的末尾。
当接收方成功处理并应用数据后,它会通过发送ACK(确认)报文来更新窗口大小,以便发送方发送数据。
滑动窗口的大小
滑动窗口的大小是可变的,它会根据影响因素变大变小。滑动窗口的本质其实是缓冲区中一段的空间,它通过起始的下标和结束的下标来表示窗口的大小。滑动窗口不会向左移动,窗口变大时,起始下标向右移动的速度比结束下标移动的速度满;窗口变小时,起始下标向右移动的速度比结束下标移动的速度快;窗口向右移动就是两个下标向右移动。
TCP报文格式中,窗口大小只有16位,16位数字最大表示65535,那么滑动窗口最大就是65535字节么?实际上,TCP首部选项字段中还包含了一个窗口扩大因子M,实际窗口大小是窗口字段的值左移 M 位。这里了解即可。
滑动窗口中的丢包问题
丢包问题分为发送包丢失和应答包丢失。
发送包丢失
TCP通信中,丢包问题是靠应答机制解决的,即确认序号。但要注意,确认序号表示该序号之前的所有数据被完整接收,倘若有一个比丢失报文对应的确认序号大确认号返回,那么就等于告诉发送端,该丢失的报文被完整接收,这显然是错误的。因此,这里是按丢包之前的确认序号返回的,如下图:
如上图,当某一段报文段丢失之后,发送端会一直收到 1001 这样的ACK报文段,就像是在提醒发送端 “我想要的是1001” 一样。如果发送端主机连续三次收到了同样一个 “1001” 这样的应答,就会将对应的数据 1001 - 2000 重新发送,这种机制被称为高速重发控制(也叫快重传)。这个时候接收端收到了 1001 之后,再次返回的ACK就是7001了,因为 2001 - 7000 接收端其实之前就已经收到了,它被放到了接收端操作系统内核的接收缓冲区中。还有就是操作系统内核为了维护这个滑动窗口,会开辟发送缓冲区来记录当前还有哪些数据没有应答,只有确认应答过的数据,才能从缓冲区删掉。
这里有个问题,若窗口大小不足以连续发送三次的确认报文呢?这种情况就会进行超时重传。
应答包丢失
应答包丢失其实根本不影响。若前面或中间的数据应答包丢失了,后面的确认序号就能表示应答功能,因为,确认序号表示该序号之前的数据都已被接收;若是最后一个数据的应答包丢失,发送方会进行超时重传。
3-5,流量控制
接收端处理数据的速度是有限的。如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应,因此TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制。
TCP利用滑动窗口机制来实现流量控制。滑动窗口机制中,发送方发送的数据量受到接收方窗口大小的限制,如果接收方处理数据的速度较慢,导致接收窗口变小,接收方会在确认应答中告知发送方新的窗口大小。发送方收到后,就会相应地减少发送的数据量,以适应接收方的处理能力;如果接收方处理速度较快,接收窗口变大,接收方也会通知发送方。此时,发送方可以增加发送的数据量,提高数据传输效率。
滑动窗口机制中,接收端将自己可以接收数据缓冲区的大小放入TCP首部中的 “窗口大小” 字段中,通过ACK报文通知发送端。其中,窗口大小字段越大,说明网络的吞吐量越高,接收方接收能力越强,若接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端。发送端接受到这个窗口之后,就会减慢自己的发送速度。如果接收端缓冲区满了,就会将窗口置为0,这时,发送方不再发送数据,但发送方会定期发送一个窗口探测数据段(因为窗口大小可能为0,所以报文里没有数据部分),使接收端把窗口大小告诉发送端。接收方也会主动将窗口更新的通知发送到发送方,即双方都会主动,这样的好处是可以尽快恢复正常通信。
若接收方主机的窗口大小一直为0不做处理呢?这时发送方会发送PSH标志位,用于提示接收端立即将缓冲区中的数据,将其递交给应用程序的应用层代码,而不是在缓冲区的队列中排队等待。注意:PSH只是在操作系统方面上进行调整,若应用层代码没有处理,这里就是程序员本身写的代码问题。
3-6,紧急指针
TCP报文中的紧急指针是一个特殊且重要的字段。紧急指针存在于TCP头部的选项字段中,是一个16位的正偏移量。它指向紧急数据在整个数据流中的位置。紧急指针的主要作用是在TCP连接中提供紧急数据的传输机制,当发送端需要发送一些紧急数据时,可以设置紧急指针来指示接收端,在接收到该指针之后尽快处理这些数据。
TCP头部中有一个URG标志位,用于表示紧急指针是否有效。当URG=1时,表示紧急指针有效;当URG=0时,则忽略紧急指针值,也就是说只有当URG标志置1时,接收端才会根据紧急指针的值来处理紧急数据。
最后说明下,紧急指针实际中基本不会用到,这里了解即可。
四,TCP/UDP对比
TCP是可靠连接,那么是不是TCP一定就优于UDP呢?我们先来做详细分析。
TCP优点:
提供相对的可靠数据传输。它使用序号确认机制、重传机制、滑动窗口、流量控制等来确保数据从发送端正确无误地传输到接收端。
TCP缺点:
1,TCP在数据传输前需要三次握手,结束后要四次挥手,这就导致TCP建立和断开连接需要额外的时间和资源成本。
2,由于TCP报文的复杂性,导致数据在传输过程中效率相对较低,且资源开销较大。
UDP优点:
UDP报头格式简单,无需建立连接,发送的数据包也都是独立的,使其占用资源较小,传输速度快,效率高。
UDP缺点:
UDP不能保证数据可靠性,没有提供任何保证机制,可能会导致数据丢失或错乱。
基于TCP和UDP的情况,TCP应用于可靠传输的情况,如文件传输,重要状态等场景。UDP适用于可靠性要求不高的应用场景,如视频流、语音通话、在线游戏等。
相关文章:
【Linux网络编程】传输层协议
目录 一,传输层的介绍 二,UDP协议 2-1,UDP的特点 2-2,UDP协议端格式 三,TCP协议 3-1,TCP报文格式 3-2,TCP三次握手 3-3,TCP四次挥手 3-4,滑动窗口 3-5…...
JavaScript系列(41)--状态管理实现详解
JavaScript状态管理实现详解 🔄 今天,让我们深入探讨JavaScript的状态管理实现。状态管理是现代前端应用中的核心概念,它帮助我们有效地管理和同步应用数据。 状态管理基础概念 🌟 💡 小知识:状态管理是一…...
flume和kafka整合 flume和kafka为什么一起用?
Flume和Kafka一起使用的主要原因是为了实现高效、可靠的数据采集和实时处理。12 实时流式日志处理的需求 Flume和Kafka结合使用的主要目的是为了完成实时流式的日志处理。Flume负责数据的采集和传输,而Kafka则作为消息缓存队列,能够有效地缓冲数据,防止数据堆积或丢…...
【深度学习】 自动微分
自动微分 正如上节所说,求导是几乎所有深度学习优化算法的关键步骤。 虽然求导的计算很简单,只需要一些基本的微积分。 但对于复杂的模型,手工进行更新是一件很痛苦的事情(而且经常容易出错)。 深度学习框架通过自动…...
什么是三高架构?
大家好,我是锋哥。今天分享关于【什么是三高架构?】面试题。希望对大家有帮助; 什么是三高架构? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 “三高架构”通常是指高可用性(High Availability)、高性能ÿ…...
IOS 自定义代理协议Delegate
QuestionViewCell.h文件代码,定义代理协议 protocol QuestionViewCellDelegate <NSObject>- (void)cellIsOpenDidChangeAtIndexPath:(NSIndexPath *)indexPath;endinterface QuestionViewCell : UITableViewCellproperty (nonatomic, weak) id<QuestionVi…...
【flutter版本升级】【Nativeshell适配】nativeshell需要做哪些更改
flutter 从3.13.9 升级:3.27.2 nativeshell组合库中的 1、nativeshell_build库替换为github上的最新代码 可以解决两个问题: 一个是arg("--ExtraFrontEndOptions--no-sound-null-safety") 在新版flutter中这个构建参数不支持了导致的build错误…...
C#编程:List.ForEach与foreach循环的深度对比
在C#中,List<T>.ForEach 方法和传统的 foreach 循环都用于遍历列表中的元素并对每个元素执行操作,但它们之间有一些关键的区别。 List<T>.ForEach 方法 方法签名:public void ForEach(Action<T> action)类型:…...
leetcode_2762. 不间断子数组
2762. 不间断子数组 - 力扣(LeetCode) 运用滑动窗口和multise(平衡二叉树实现) 符合条件 右窗口向右扩展 不符合条件 左窗口向左扩展 class Solution { public:long long continuousSubarrays(vector<int>& nums) {int max, min; //表示窗…...
Java学习教程,从入门到精通,JDBC创建数据库语法知识点及案例代码(99)
JDBC创建数据库语法知识点及案例代码 一、JDBC创建数据库语法 在JDBC中,创建数据库主要通过执行SQL语句来实现。其基本语法如下: CREATE DATABASE database_name;CREATE DATABASE 是固定的SQL语句关键字,用于指定创建数据库的操作。databa…...
进阶——第十六届蓝桥杯(sscanf的运用)
声明变量 char tx_buf[30];char rx_buf[30];char car_type[5];char car_num[5];char car_time[15]; int sscanf(const char *str, const char *format,...); sscanf函数功能 sscanf 函数从字符串 str 中读取数据,根据 format 所指定的格式将数据存储到后续的变量中…...
嵌入式硬件篇---ADC模拟-数字转换
文章目录 前言第一部分:STM32 ADC的主要特点1.分辨率2.多通道3.转换模式4.转换速度5.触发源6.数据对齐7.温度传感器和Vrefint通道 第二部分:STM32 ADC的工作流程:1.配置ADC2.启动ADC转换 第三部分:ADC转化1.抽样2.量化3.编码 第四…...
Spark Streaming编程基础
文章目录 1. 流式词频统计1.1 Spark Streaming编程步骤1.2 流式词频统计项目1.2.1 创建项目1.2.2 添加项目依赖1.2.3 修改源目录1.2.4 添加scala-sdk库1.2.5 创建日志属性文件 1.3 创建词频统计对象1.4 利用nc发送数据1.5 启动应用,查看结果 2. 编程模型的基本概念3…...
android wifi AsyncChannel(WifiManager和WifiP2pManager)
AynscChannel的讲解 [Android]AsyncChannel介绍-CSDN博客 WifiP2pManager里的channel的使用理解 WifiP2pManager.java public void createGroup(Channel c, ActionListener listener) {checkChannel(c);c.mAsyncChannel.sendMessage(CREATE_GROUP, WifiP2pGroup.NETWORK_ID_PE…...
生存网络与mlr3proba
在R语言中,mlr3包是一个用于机器学习的强大工具包。它提供了一种简单且灵活的方式来执行超参数调整。 生存网络是一种用于生存分析的模型,常用在医学和生物学领域。生存分析是一种统计方法,用于研究事件发生的时间和相关因素对事件发生的影响。生存网络可以用来预测个体在给…...
C#Object类型的索引,序列化和反序列化
前言 最近在编写一篇关于标准Mes接口框架的文章。其中有一个非常需要考究的内容时如果实现数据灵活和可使用性强。因为考虑数据灵活性,所以我一开始选取了Object类型作为数据类型,Object作为数据Value字段,String作为数据Key字段,…...
【动态规划】记忆化搜索
Ban or Problem - A - Codeforces 【CCPC】2022年绵阳站部分题解(ACGM)_ban or pick, whats the trick-CSDN博客 #include<iostream> using namespace std; #include<cstring> #include<algorithm> #define inf -0x3f3f3f3f #defi…...
深度学习 DAY1:RNN 神经网络及其变体网络(LSTM、GRU)
实验介绍 RNN 网络是一种基础的多层反馈神经网络,该神经网络的节点定向连接成环,其内部状态可以展示动态时序行为。相比于前馈神经网络,该网络内部具有很强的记忆性,它可以利用它内部的记忆来处理任意时序的输入序列,…...
BW复制ERP数据源跑程序激活后才可见
场景: BW提取ERP数据走ODP通道之后,数据源需要用下列程序激活加入白名单后才能被BW系统访问到; 检查: 1、RSA6检查数据源是否可正常使用,若为绿√表示可正常访问,反之,则不行。 2、白名单表ROO…...
MarsCode青训营打卡Day10(2025年1月23日)|稀土掘金-147.寻找独一无二的糖葫芦串、119.游戏队友搜索
资源引用: 147.寻找独一无二的糖葫芦串 119.游戏队友搜索 今日小记: 回乡聚会陪家人,休息一天~ 稀土掘金-147.寻找独一无二的糖葫芦串(147.寻找独一无二的糖葫芦串) 题目分析: 给定n个长度为m的字符串表…...
无人机 PX4 飞控 | PX4源码添加自定义参数方法并用QGC显示与调整
无人机 PX4 飞控 | PX4源码添加自定义参数方法并用QGC显示与调整 0 前言 之前文章添加了一个自定义的模块,本篇文章在之前的自定义模块中,添加两个自定义参数 使用QGC显示出来,并通过QGC调整参数值,代码实现参数更新 新增的参…...
【全栈】SprintBoot+vue3迷你商城-扩展:vue3项目创建及目录介绍
【全栈】SprintBootvue3迷你商城-扩展:vue3项目创建及目录介绍 往期的文章都在这里啦,大家有兴趣可以看一下 【全栈】SprintBootvue3迷你商城(1) 【全栈】SprintBootvue3迷你商城(2) 【全栈】SprintBootvu…...
Linux系统 C/C++编程基础——基于Qt的图形用户界面编程
ℹ️大家好,我是练小杰,今天周四了,距离除夕只有4天了,各位今年卫生都搞完了吗!😆 本文是接着昨天Linux 系统C/C编程的知识继续讲,基于Qt的图形用户界面编程概念及其命令,后续会不断…...
23.日常算法
1. 最小绝对差 题目来源 给你个整数数组 arr,其中每个元素都 不相同。请你找到所有具有最小绝对差的元素对,并且按升序的顺序返回。 每对元素对 [a,b] 如下: a , b 均为数组 arr 中的元素 a < b b - a 等于 arr 中任意两个元素的最小绝对…...
迅为RK3568开发板篇OpenHarmony实操HDF驱动控制LED-添加内核编译
编译内核时将该 HDF 驱动编译到镜像中,接下来编写驱动编译脚本 Makefile,代码如下所示: 加入编译体系,填加模块目录到 drivers/hdf_core/adapter/khdf/linux/Makefile 文件 更多内容可以关注:迅为RK3568开发板篇OpenHa…...
为AI聊天工具添加一个知识系统 之54 为事务处理 设计 基于DDD的一个 AI操作系统 来处理维度
本文要点 要点 Architecture程序 它被设计为一个双面神结构的控制器,它的两侧一侧编译执行另一侧 解释执行,自已则是一个 翻译器--通过提供两个不同取向之间 的 结构映射的显示器(带 图形用户接口GUI和命令行接口CLI 两种 接口)…...
Golang 中除了加锁还有哪些安全读写共享变量的方式?
Golang 中除了加锁还有哪些安全读写共享变量的方式? 在 Golang 中,除了使用 Mutex 锁来保护共享变量外,还可以通过 Channel 和 原子性操作 来实现安全读写共享变量。 1. 使用 Channel 原理 Channel 是 Golang 中用于 Goroutine 之间通信的…...
【优选算法】8----四数之和
有看过我上篇算法博客并且去做过的铁子们,对这道题的话应该就不会那么陌生了,因为这两道题 的解题思路有着异曲同工之妙~ -----------------------------------------begin------------------------------------- 题目解析: 跟三数之和就多了…...
订单状态定时处理、来单提醒和客户催单(day10)
Spring Task 介绍 Spring Task 是 Spring 框架提供的任务调度工具,可以按照约定的时间自动执行某个代码逻辑。 定位: 定时任务框架 作用: 定时自动执行某段Java代码 为什么要在 Java 程序中使用 Spring Task? 应用场景࿱…...
备赛蓝桥杯之第十五届职业院校组省赛第一题:智能停车系统
提示:本篇文章仅仅是作者自己目前在备赛蓝桥杯中,自己学习与刷题的学习笔记,写的不好,欢迎大家批评与建议 由于个别题目代码量与题目量偏大,请大家自己去蓝桥杯官网【连接高校和企业 - 蓝桥云课】去寻找原题࿰…...
【2024年华为OD机试】(C卷,100分)- 查找接口成功率最优时间段 (JavaScriptJava PythonC/C++)
一、问题描述 题目解析 题目描述 服务之间交换的接口成功率作为服务调用关键质量特性,某个时间段内的接口失败率使用一个数组表示。数组中每个元素都是单位时间内失败率数值,数组中的数值为 0~100 的整数。给定一个数值 minAverageLost,表…...
Linux进度条实现
Linux进度条实现 1.\r\n2.缓冲区3.缓冲区分类4.进度条实现 🌟🌟hello,各位读者大大们你们好呀🌟🌟 🚀🚀系列专栏:【Linux的学习】 📝📝本篇内容:\…...
Java如何实现反转义
Java如何实现反转义 前提 最近做的一个需求,是热搜词增加换一批的功能。功能做完自测后,交给了测试伙伴,但是测试第二天后就提了一个bug,出现了未知词 levis。第一眼看着像公司售卖的一个品牌-李维斯。然后再扒前人写的代码&…...
计算机网络 (57)改进“尽最大努力交付”的服务
前言 计算机网络中的“尽最大努力交付”服务是网络层的一种数据传输方式。这种服务的特点是网络层只负责尽力将数据报从源端传输到目的端,而不保证数据传输的可靠性。 一、标记与分类 为数据分组打上标记: 给不同性质的分组打上不同的标记&#x…...
Java 基于 SpringBoot 的校园外卖点餐平台微信小程序(附源码,部署,文档)
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
重构(4)
(一)添加解释性变量,使得代码更容易理解,更容易调试,也可以方便功能复用 解释性的变量 总价格为商品总价(单价*数量)-折扣(超过100个以上的打9折)邮费(原价的…...
【Arduino】语言参考功能
前言 翻译Arduino 参考处列出的常用函数。文中为了减少篇幅,达到能快速翻到查询的目标,在介绍函数中,对部分内容进行了省略,不会列出函数输入参数类型,以及使用注意事项等等,所以若是首次使用或者是调试时出…...
CMake使用CPack制作安装程序
CPack的功能很强大,笔者前面有一博文使用CMake的CPack工具打包项目介绍了一下使用CPack来打包成7z压缩文件,不仅如此,它还可以生成各平台的安装包。 CPack支持以下类型的生成器: 名称文件类型平台及说明STGZSTGZ(.sh)自解压文件…...
Flink运行时架构
一、系统架构 1)作业管理器(JobManager) JobManager是一个Flink集群中任务管理和调度的核心,是控制应用执行的主进程。也就是说,每个应用都应该被唯一的JobManager所控制执行。 JobManger又包含3个不同的组件。 &am…...
平衡二叉树(力扣110)
所谓平衡二叉树,就是每一个节点的左右子树的高度差不大于1。而一个子树的高度,就是父节点的最大高度。这道题的思路其实和二叉树的最大深度(力扣104)-CSDN博客有很大的相似之处,都需要将左右子树的高度返回给父节点,因此也是采用后…...
【玩转全栈】---基于YOLO8的图片、视频目标检测
本篇主要讲YOLO8的具体操作,想要了解YOLO的具体原理,可以去官网查询 目录 下载ultralytics库 开始检测 介绍 YOLOv8(You Only Look Once Version 8)是 YOLO 系列的最新版本,由 Ultralytics 开发并发布,是一…...
ES6+新特性,var、let 和 const 的区别
在 JavaScript 中,var、let 和 const 都用于声明变量,但它们有一些重要的区别,主要体现在 作用域、可变性和提升机制 等方面。 1. 作用域(Scope) var: var 声明的变量是 函数作用域,也就是说,它…...
汇编实验·分支程序设计
一、实验目的: 1.能够熟练的进行分支程序的编写,掌握条件语句对应的汇编语言指令的实现 2.掌握多个条件的分支语句的实现原理,理解C语言中的逻辑运算“短路”特征 二、实验内容 1.对2和3任务中的C代码在VS2022中运行,设置生成对应的汇编代码,观察生成代码的不同,着重…...
激光线扫相机无2D图像的标定方案
方案一:基于运动控制平台的标定 适用场景:若激光线扫相机安装在可控运动平台(如机械臂、平移台、旋转台)上,且平台的运动精度已知(例如通过编码器或高精度步进电机控制)。 步骤: 标…...
【Python・机器学习】多元回归模型(原理及代码)
前言 自学笔记,分享给语言学/语言教育学方向的,但对语言数据处理感兴趣但是尚未入门,却需要在论文中用到的小伙伴,欢迎大佬们补充或绕道。ps:本文最少限度涉及公式讲解(文科生小白友好体质)&am…...
ubuntu20.04安装使用direct_visual_lidar_calibration标定雷达和相机
官方链接GitHub - koide3/direct_visual_lidar_calibration: A toolbox for target-less LiDAR-camera calibration [ROS1/ROS2] 官方安装方式 Installation - direct_visual_lidar_calibration 安装依赖 sudo apt install libomp-dev libboost-all-dev libglm-dev libglfw…...
Android 自定义View时四个构造函数使用详解
该文章我们以自定义View继承TextView为例来讲解 创建自定义View命名MyTextView,并使其继承TextView 1、自定义View时第一个构造函数 // 第一个构造函数主要是在Java代码中声明一个MyTextView时所用 // 类似这种(MyTextView myTextViewnew MyTextView(this);) // 不…...
linux中关闭服务的开机自启动
引言 systemctl 是 Linux 系统中用于管理 systemd 服务的命令行工具。它可以用来启动、停止、重启服务,管理服务的开机自启动,以及查看服务的状态等。 什么是 systemd? systemd 是现代 Linux 发行版中默认的 初始化系统(init sys…...
【go语言】go的卸载与安装
一、卸载go sudo rm -rf /usr/local/go sudo apt-get remove golang sudo apt-get remove golang-go sudo apt-get autoremove wget https://dl.google.com/go/go1.19.linux-amd64.tar.gz sudo tar -xzf go1.19.linux-amd64.tar.gz -C /usr/local go env -w GOPROXY"http…...
微软Win10 RP 19045.5435(KB5050081)预览版发布!
系统之家1月20日最新报道,微软面向Release Preview频道的Windows Insider项目成员,发布了适用于Windows10 22H2版本的KB5050081更新,更新后系统版本号将升至19045.5435。本次更新增加了对GB18030-2022标准的支持,同时新版日历将为…...