【Linux 网络 (五)】Tcp/Udp协议

Linux网络编程:TCP与UDP详解 本文深入探讨了Linux网络编程中的TCP和UDP协议,包括它们的基本概念、使用方法和通信过程。文章通过示例代码、时序图和异常情况处理,帮助读者全面理解TCP和UDP在服务器编程中的应用。 阅读详情

一前言

 本篇文章将会介绍Tcp/Udp协议中的所有字段、以及确认应答、超时重发、连接管理、流量控制、拥塞控制、滑动窗口、快速重传、延迟应答、捎带应答相关面试高频考点!!

二、Udp协议

1)、Udp协议特点

 Udp是一种面向数据报,无连接、不可靠传输协议。Udp广泛应用于直播领域。

面向数据报解释:
 Udp报头中存在描述完整Udp报文长度字段(后面介绍),所以在内核将报头和有效载荷分离后,交给上层的就是一个完成报文!!并且不管应用层交给Udp多长的报文,Udp原样发送,既不才分也不合并。所以Udp面向数据报。
 
无连接解释:
 Udp协议通信只需要对端的ip和port即可通信,不需要建立连接。就好比寄快递,我只需要知道对方的地址就可以向对方邮寄东西了。
 
不可靠解释:
 首先需要明确的是,可靠和不可靠描述的是不同通信协议的特点,本身并不存在谁好谁坏!前面已经提到过Udp无连接,而Udp报文发送过程中可能会存在丢包问题。但对于Udp而言,Udp认为只要将数据交给网络层就发送成功,对于网络报文丢包问题并不做任何处理(Tcp会重传)
 虽然Udp不会做丢失重传等工作,但其实在目前的网络环境中,数据丢包的概率极小。并且Tcp为了保证可靠性,需要做大量工作(超时重发、流量控制、拥塞控制、快速重传…),也就意味着Tcp通信更复杂,速度更低。所以如果对可靠性要求不高的场景,一般选择Udp作为传输层协议。

2)、Udp协议格式

在这里插入图片描述

  • 16位UDP长度,:表示整个数据报(UDP首部+UDP数据)的最大长度。
  • 16位UDP校验和:如果校验和出错, 就会直接丢弃;

 任何协议都需要解决两个问题:报文和有效载荷分离问题,报文向上交付问题。
 
 报文和有效载荷分离问题:首先Udp报头采用固定长度,8字节。并且报头中16位UDP长度字段表示整个报文长度。所以在读取Udp报文时,只需要先读取报头(8byte),剩余就是有效载荷了。
 报文向上交付问题:报文中存在目的端口号字段,明确交给上层那个端口。

3)、Udp报文封装和解包过程

 在OS中,存在大量的Udp报文。OS需要对报文进行管理,先描述在组织!

4)、UDP的缓冲区

 Udp没有真正的发送缓冲区。数据从应用层拷到传输层后,添加报头,构建sk_buff结构体后直接向下交付,交给网络层。
 但Udp存在接收缓冲区。原因在于Udp可能会接收到大量的报文。Udp本身特点不可靠,如果对端传输层中已经存在报文,但上层没有及时取走,此时Udp可以直接接将新收到的报文丢弃或覆盖原始报文,这并不影响上层对Udp处理,但这并不合理。 Udp报文经过千里迢迢之后将报文正确发送到目标主机后,在这其中消耗了大量的资源,Udp收到报文后仅因为上层没有及时将前一个数据取走,就直接将新报文丢弃。Udp虽然不可靠,但也不能这么不可靠。所以对于Udp接收方,我们还是提供了一个接收缓冲区,暂时保存新到的报文!
 Udp接收缓冲区本质就是一个队列,将所有新到的sk_buff结构体连接到改队列下即可。

三、TCP协议

1)、TCP协议特点

 TCP全称为 “传输控制协议(Transmission Control Protocol”)。Tcp不仅控制报文传输(丢包了需要重传,网络拥塞时执行网络拥塞算法,以及流量控制等)保证可靠性,还做了大量工作来保证效率(后面介绍)
 
 TCP是一种可靠的,面向字节流的通信协议,并且在通信前需要先建立连接!

2)、TCP协议格式

在这里插入图片描述

1、4位首部长度、源端口、目的端口

任何协议都需要解决两个问题:报文和有效载荷分离问题,报文向上交付问题。
 
 报文和有效载荷分离问题:Tcp的标准报头长度为20字节,4位首部长度表示Tcp报头的总长度。所以在分解报文时,只需先读取头20字节数据,然后分析提取出4位首部长度。此时就能明确Tcp报头的长度,将报文和有效载荷分离。
 
 在Tcp报头中存在目的端口号,解决向上交付问题!

  • 4位首部长度的基本单位为4字节,所以tcp报头的长度为[20,4*15],即[20, 60]
2、16位窗口大小

 Tcp典型的全双工协议,双方地位是对等的。在报文发送过程中,Tcp为了保证可靠性需要做流量控制!如果接收方来不及接收,就让发送端少发点。(否则Tcp收到多余报文会被丢弃,不可靠,不合理)
 
 为了实现流量控制,发送端需要知道接收端的接收能力,也就是对端接收缓冲区的剩余空间大小!而16位窗口中填写的就是接收缓冲区剩余空间大小!
 
 在tcp协议中,所有的报文都必须应答。所以客户端和服务器直接互发消息时,对端必须确认应答。而确认应答大多数就是一个最简单的标准报头,而报头中携带的16位窗口大小表示接收方的接收能力。从而实现告知对方我的接收能力!

  1. 上述所有的行为都是双方Tcp协议做的,应用层不需要关心。就像文件操作,我们直接调用write将用户数据拷贝到内核后,数据什么时候刷新落盘是由OS来决定实现的,上层用户不需要关心。
  2. Tcp流量控制和管道类似,当接收端满了后,发送端会发送阻塞。如果此时上层还在忘发送端的发送缓冲区写,导致发送缓冲区也满了,此时上层进程就会发生阻塞!
3、Tcp确认应答机制

 Tcp规定接收端必须对接收到的数据进行应答。所以我们可以每发一条消息后,等待应答。然后在发生下一条数据! 但这样串行发送,效率较低。所以实际Tcp发送报文是一次发送多个报文,然后等待应答!
4f4.png)

  • tcp为了保证可靠性,所以Tcp引入确认应答机制就可以100%明确历史最近一跳消息一定被对方收到!
  • tcp做不到100%可靠的网络通信,原因在于最近一条消失没有应答。
4、序号和确认序号

 发送方一次发送大量报文,接收方接收到的数据可能是乱序的。而乱序是不可靠的一种表现(发送http报文时,报头和有效载荷接收反了,上层处理会出异常) 所以Tcp引入32位序号,保证报文的按序到达!接收方根据接收报文中的序号进行排序即可修正!
 
 但发送方还需要对发送的大量报文进行应答。但一次发送大量报文,如何得到接收到的应答是对历史那个具体报文的确认呢? 所以Tcp引入32位确认序号(确认序号= 序号 + 1)。确认序号表示确认序号之前的报文都被对方接收到了!

为什么确认序号需要怎么规定?

 这样可以允许应答有少量丢失!!客户端一次向客户端发送大量tcp报文时,理论而言客户端需要收到所有报文的应答。但确认序号规定确认序号之前的报文全部被对方接收了。所以即使存在少量应答丢失,但后面的应答也可以对前面的所有数据进行确认!!

经典面试题:为啥序号和确认序号要分开,不能统一?

 原因在于客户端向服务器发送消息后,服务器受到必须进行应答。但服务端不仅仅只进行应答,有可能也想向客户端发送数据。而应答本质也是将Tcp报头中的ack标志位由0置1即可。所以服务端会将应答和发送数据和二为1,即捎带应答!
 所以此时的报文既是对上次历史发送报文的应答(需要确认序号),也是数据(需要序号)。所以序号和确认序号有可能会被同时使用,所以必须分开!!

5、标记位

 在tcp双方通信过程中,客户端和服务器一定会受到各种各样的tcp报文(新建报文、断开报文、发送数据报文、数据异常报文…)所以tcp报文一定要有类型,所以才用了各种标记位!!

 对于Syn、ACK、FIN使用场景如下:
在这里插入图片描述

URG标记位、16位紧急指针:

 Tcp协议为了保证可靠性,收到的数据应按序到达,也就是一个队列。但也存在一些紧急数据,需要尽快被上次处理!提前处理,也就意味着插队。Tcp不允许大量数据插队,但允许有少量数据插队,所以引入URG标记位、16位紧急指针。(16位紧急指针表示紧急数据在有效载荷中的偏移量)
 
 当接收方接收到一个报文,该报文中的URG标志位为1,此时意味着当前报文携带紧急任务数据。所以Tcp发现URG为1后,直接通过16位紧急指针就可以拿到紧急数据,然后交给上层了。(紧急数据只有1byte,然后类似错误码一样,不同值代表不同含义)

recv函数flags标记位为0,表示接收常规数据。当flag设置为MSG_OOB时,此时表示接收紧急数据。OOB表示带外数据,即常规数据之外的数据!
在这里插入图片描述
在这里插入图片描述

URG标志位使用场景:

  1. 第一种场景:有时上传数据错了,我们希望暂停或终止上传的行为时。但我们不希望直接通过退出断开连接来实现,此时就向对端推送紧急数据,让上层尽快暂停或终止上传。
  2. 第二种场景:现在又一个服务器I/O负载比较重,需要经常性对服务器进行健康监测和管理!服务器响应很慢,甚至卡住了。对于发送方而言,非常担心服务器是不是块扛不住了。此时我们可以向服务端发送紧急数据,此时服务端会优先处理并应答。此时发送方就可以得知服务器运行状况!(可以通过创建线程发送紧急数据,此时服务端也存在响应的接收方案)

PSH标记位:

 在接收方处理tcp报文时,上层http可能非常耗时,此时接收方很卡,很慢。但我们发送紧急指针后得知对端状态很好,只是数据处理比较慢。此时我们可以方式一个简单报文,并将PSH标记位置1。(该行为表示告诉对端尽快把数据进行向上交付)

  • 最典型的场景就是xshell。我们输入的所有指针都携带PSH标记位,让服务器尽快处理,给使用者带来更好的体验!

RST标记位:

我们已经知道,TCP在通信前需要先建立连接,3次握手成功!但最后一次ACK是否成功,我们无法得知(没有确认应答)如果此时该应答恰好丢失,此时服务端认为连接建立尚未完成。但客户端发送完ACK后认为连接已经建立成功。
 所以一旦客户端向服务器发送消息时,会导致双方连接建立认知不一致问题!此时服务端会发送一个简单报文,并将RST标记位置1。此时客户端收到之后就知道连接建立失败了,会将历史建立的连接释放,然后重新建立连接!!(其实客户端就是在赌最后一个报文对方接收到了,但很不幸赌失败了!!)

在这里插入图片描述

四、面向字节流解释

 tcp通信是全双工的,并且存在接收缓冲区和发送缓冲区!接收缓冲区就是一块简单内存空间,但我们可以把缓冲区理解为一个大的字符数组!此时数据从发送缓冲区按字节为单位拷到对端接收缓冲区,这就是字节概念
在这里插入图片描述
 并且接收缓冲区本质就是一个生产者消费者模型。不断有数据从对端拷贝至接收向缓冲区中生产数据,同时上层不断从接收缓冲区消费数据。一端进数据,另一端出数据,并且数据间没有界限,这不就出现了流动的概念!
在这里插入图片描述

五、超时重传机制

 主机A向主机B发送消息时,由于一些原因,在特定时间内没有收到对应应答,此时主机A认为数据丢失,会进行超时重传!!

1)、触发超时重传的两种具体原因

 但主机A没有收到数据,分为以下两者情况:

① 数据丢失:
 主机A向主机B发送消息时,由于网络拥塞的原因,报文丢失了,主机B并未受到对应报文。

在这里插入图片描述

② 确认应答丢失:
 主机A向主机B发送消息时,主机B受到了主机A发送的报文,并进行了应答。但主机A在特定时间段内受到确认应答报文。此时主机A认为向B发送数据失败,触发超时重传机制,重新向主机B发送报文!
 但此时主机B已经收到过历史报文。此时主机B会根据32位序号进行去重!也就意味着主机收到报文应答后,不能被立即丢弃,需要被暂时保存起来(滑动窗口维持:暂时保存在发送缓冲区的滑动窗口区域,收到应答后,通过窗口移动删除指定报文!)

在这里插入图片描述

2)、超时时间

 数据发送给对端后,特定时间内没有收到会触发超时重传。但网络状态是浮动的,超时时间设置为多少?超时时间太长, 会影响整体的重传效率;时间太短, 有可能会频繁发送重复的包。
 
 TCP为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超时时间。Linux中(BSD Unix和Windows也是如此), 超时以500ms为一个单位进行控制, 每次判定超时重发的超时时间都是500ms的整数倍!!如果重发一次之后, 仍然得不到应答, 等待 2 * 500ms 后再进行重传。如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.累计到一定的重传次数, TCP认为网络或者对端主机出现异常, 强制关闭连接!!

六、连接管理机制

1)链接建立和断开时,双方链接状态变化

 在正常情况下, TCP要经过三次握手建立连接, 四次挥手断开连接。
在这里插入图片描述
服务端状态转化:
[CLOSED -> LISTEN] :服务器端调用listen后进入LISTEN状态, 等待客户端连接。
[LISTEN -> SYN_RECV]:服务器接收到客户端发送的SYN报文后,发送SYN+ACK完成。
>[SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文, 就进入ESTABLISHED状态, 可以进行读写数据了
在这里插入图片描述

2)经典面试题1:为什么需要进行3次握手,4次挥手

1)三次握手的目的是为了建立连接,首先客户端会向服务器发送一个包含 SYN 的 TCP 报文,请求建立连接;而后服务器收到这个请求后会向客户端发送包含 SYN 和 ACK (确认收到) 的 TCP 报文,最后,客户端向服务器发送包含 ACK 的 TCP 报文后建立连接。
(2) 四次挥手的目的是为了断开连接,客户端会先向服务器发送一个包含 FIN (结束连接) 的 TCP 报文,服务器在给客户端发送一个包含 ACK 的 TCP 报文后。当服务器也需要断开连接时,向客户端发送 FIN报文,最后客户端再向服务器发送 ACK 后进入 TIME_WAIT 状态 。

为啥是三次握手,不是其他?挥手同理?

握手3次:
 首先握手1次或2次就将链接建立成功,存在明显bug。会导致一些单机程序,恶意向服务器挂靠链接。而创建链接是有成本的(时间成本:初始化,空间成本:申请内存)。此时会导致服务器存在大量链接,可能大量消耗服务器资源,甚至宕机!
 而链接一般都是客户端发起,服务端被动响应。3次或奇数次握手,一定是客户端先将链接建立成功,然后服务端才链接连接。也就意味着,一旦服务器连接建立成功,客户端也需要付出等量的成本,可以一定程度上减少SYN洪水问题!
 并且3次握手,能够以最小成本验证全双工通道!
 最后一点就是3次握手本质是4次握手。其中SYN+ACK本质是一次捎带应答。如果将其拆开,不管是客户端还是服务器,都以最小成本明确将想要建立连接的意愿传递给对方。既然双方都知道对端想要建立来连接了,后序动作也就每必要!

4次挥手:
 4次挥手同样是以最小成本将双发想要断开连接的意愿传递给对方。
 
那为啥不是3次挥手呢?
 首先客户端向服务器断开连接,其实更多的是向服务器表达:“我要给你发送的数据全部发送完毕”。客户端数据发完了,但服务器大概率需要对收到的数据进行处理,存在后续动作。当所有数据全部处理完成后,才和客户端真正断开所有连接!所以在业务上,两者时间一般不会重合!

3)经典面试题2:请你说说 TCP 三次握手四次挥手过程

TCP 三次握手过程:

  1. 调用socket, 创建文件描述符;
  2. 调用connect, 向服务器发起连接请求;
  3. connect会发出SYN段并阻塞等待服务器应答; (第一次)
  4. 服务器收到客户端的SYN, 会应答一个SYN-ACK段表示"同意建立连接"; (第二次)
  5. 客户端收到SYN-ACK后会从connect()返回, 同时应答一个ACK段; (第三次)

 初始时,客户端和服务器端都处于CLOSED状态,并且通常是由客户端发起连接建立请求,服务器则被动响应。在三次握手前,服务器就已经进入监听状态,等待客户端发起连接建立请求。
 第一次握手:客户端发起SYN报文(即SYN标记位置1),请求与服务器建立连接。同时随机生成一个起始序列号x,并将其填充到SYN报文的序列号字段中,随后进入SYN_SEND状态,等待服务器的响应。
 第二次握手:服务器收到客户端SYN报文后,如果同意建立连接,会发送ACK/SYN报文(即ACK、SYN标记位置1),并将确认序号字段被设置为x+1,同时随机生成一个数y填充到序列号字段中,完成后进入SYN_RECV状态。
 第三次握手:客户端收到服务器的SYN/ACK报文后,验证确认序号x+1,确认这是对自己SYN报文的应答,并知道服务器同意建立连接。客户端向服务器发送一个ACK报文,作为对服务器SYN/ACK报文的确认。在ACK报文中, 确认序号字段被设置为y+1,

TCP四次挥手过程:

  1. 如果客户端没有更多的请求了, 就调用close()关闭连接, 客户端会向服务器发送FIN段(第一次);
  2. 此时服务器收到FIN后, 会回应一个ACK, 同时read会返回0 (第二次);
  3. read返回之后, 服务器就知道客户端关闭了连接, 也调用close关闭连接, 这个时候服务器会向客户端发送一个FIN; (第三次)
  4. 客户端收到FIN, 再返回一个ACK给服务器; (第四次)

 首先第一次挥手:客户端向服务器发送FIN报文,请求断开连接,进入FIN_WAIT_1状态。
 第二次挥手:服务器收到连接释放请求,然后发送ACK报文进行确认应答,进入CLOSE-WAIT状态。
 第三次挥手:当服务器端数据处理并发送完毕,向客户端发送连接释放请求,进入LAST-ACK状态。
 第四次挥手:客户端收到连接释放请求,向服务器端发送确认应答报文,此时客户端进入TIME_WAIT状态,持续2倍的MSL(最长报文段寿命),若期间没有收到服务器端的数据报文,进入CLOSED状态

4)TIME_WAIT状态

 在tcp4次挥手完成后,发起连接断开请求的一方会进入TIME_WAIT状态,等待2MSL时间后才进入CLOSE状态。MSL是TCP报文的最大生存时间,是一个经验性数字。不同OS存在差异,在ubuntu下为60S.
 
在这里插入图片描述
 主动方进入TIME_WAIT状态,并将时间设为2MSL,主要目的是让两个朝向上历史报文再网络中消失,避免对新连接的影响。同时在理论上保证最后一个报文可靠到达(假设最后一个ACK丢失, 那么服务器会再重发一个FIN!

5)地址复用,bind()失败问题

 现在服务器主动断开连接后,立即重启,我们会发现bind失败,重启失败。
在这里插入图片描述
 这主要TIME_WAIT有关。服务器主动断开连接,进入TIME_WAIT状态。虽然上层进程已经退出,但连接并未真正释放,由双方操作系统维护。port和ip依旧被使用,当然bind失败啦!
在这里插入图片描述
 但此时套接字已经没有进程在使用了,已经处于回收站状态。所以我们可以通过setsockopt()接口进行地址复用!
在这里插入图片描述

6)、服务器变慢可能原因

 对于服务器上出现大量的 CLOSE_WAIT 状态, 原因就是服务器没有正确的关闭 socket, 导致四次挥手没有正确完成。此时OS中维护大量无意义连接,可能导致服务器响应变慢!
其他可能原因

七、滑动窗口

1)什么是滑动窗口

 滑动窗口就是发送缓冲区的一个区域,由两个下标进行维护,是TCP进行流量控制的具体解决方案。滑动窗口将缓冲区分为3块,滑动窗口中保存的是可以直接发送或已经发送尚未收到确认的报文,左侧区域是已经发送并且受到应答的报文,而右侧区域是没有发送的报文或者没有数据。窗机滑动本质就是下标移动,并且在整个过程中,滑动窗口一直在变化,但只会向前移动!
滑动窗口的大小由对方接收能力决定,双发接收能力在3次握手过程就已经协商好了,告知对方。并且窗口越大, 则网络的吞吐率就越高

在这里插入图片描述

在这里插入图片描述

2)如何理解滑动窗口

 滑动窗口是由两个下标维护,那这两个下标如何更新?

 首先在3次握手时,双方就已经将起始序号和缓冲区大小告知对方了。所以起始时win_start = 起始序号;win_end = win_start + min(对方缓冲区大小, 拥塞窗口大小)。( 拥塞窗口后续介绍)
 所以在[win_start, win_end]间的报文就可以发送了,或者等到连接。一旦受到报文的确认后,win_start便可以向有移动,将受到应答的报文从滑动窗口中删除!所以滑动窗口一直在变化,变大变小,甚至为0。并不断向右移动!

在这里插入图片描述

3)、快重传机制

 位于滑动窗口中的报文都是可以发送或已经发送尚未受到应答的报文。而tcp在实际过程中,也是一次发送多个报文。但发送的报文可能丢失。
 
 ①:如果ACK丢失,由于确认序号定义是确认序号之前的报文已经全部被接收了。所以tcp允许存在少量报文丢失,后续应答会对该报文进行确认!
在这里插入图片描述
 ②:如果是报文数据包直接丢失,此时后续所有报文确认应答会全部一样。此时客户端收到发送端主机连续三次相同确认序号时,就知道确认序号的后一个报文丢失了。此时客户端会触发快重传机制,补发丢失报文!!这种机制被称为 "高速重发控制“(”快重传机制“)
在这里插入图片描述

4)、其他问题

报文丢失怎么办?

 报文丢失分为:最左侧丢失、中间丢失和对右侧丢失。
 首先最左侧报文丢失分为:数据包丢失和ACK丢失。对于数据包丢失,可以通过块重传机制进行部分;对于ACK丢失,后序报文确认序号会对该报文进行确认。
 而中间丢失和对右侧丢失,我们可以等丢失报文左侧所有报文全应答后,滑动窗口左边界向右移动,最终转化为最左侧报文丢失问题!

超时重传 VS 快重传

 首先快重传是有条件的,只有连续收到3个以上的相同序号的报文时,才会触发。快重传是提高效率的重传策略;而超时重传是兜底的。两者相互配合,相互补充!

为啥发送报文时只发送一个报文,而是分为多个发送

 首先数据链路层的能够传输的最大帧是存在限制的(MTU),和底层硬件相关。就像公交车一样,为啥上下车不一起上,而需要排队,本质就是门的大小固定。当数据链路层发送的报文超过MTU后,报文无法发送,直接被丢弃。
 如果发送过大的报文,可能会占用网络带宽较长时间,导致其他数据包的延迟增加,甚至引发网络拥塞。并且虽然组合为一个报文发送,一旦报文丢失,重传代价太大。

八、流量控制

 流量控制是tcp通过滑动窗口来控制发送端数据发送速度的一种机制, 其主要目的是防止发送端发送数据过快,导致接收端缓冲区溢出,从而引发丢包、重传等一系列连锁反应。
 接收端每次应答时,会将自身缓冲区的大小填充到报文的16位窗口大小中,从而将自身的接收能力告知发送端。此时发送端根据窗口的大小来控制发送数据的速度。如果窗口大,此时网络的吞吐量就越大;如果窗口较小,此时发送数据的速度就变慢。如果窗口为0,此时发送端会停止发送数据。并且发送端会定期询问接收端窗口大小,或者接收端接收缓冲区有空间了会主动发送报文告知发送端,以及时更新窗口大小!

在这里插入图片描述

九、拥塞控制

 TCP的拥塞控制主要是调节拥塞窗口来影响滑动窗口大小,因为滑动窗口大小=min(拥塞窗口, 对方接收缓冲区大小)。网络状态是浮动的,可能当前的网络状态就已经比较拥堵. 在不清楚当前网络状态下, 贸然发送大量的数据,是很有可能引起雪上加霜的。所以tcp引入慢启动机制。(拥塞窗口一直在变化,因为网络一直在变化,一直探测)
 发送开始的时候, 定义拥塞窗口大小为1。每次收到一个ACK应答, 拥塞窗口加1。每次发送数据包的时候, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较小的值作为实际发送的窗口。

 “慢启动” 只是指初使时慢, 但是增长速度非常快,指数级别增长。同时引入一个叫做慢启动的阈值,当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增长.当TCP开始启动的时候, 慢启动阈值等于窗口最大值;在每次超时重发的时候, 慢启动阈值会变成原来的一半, 同时拥塞窗口置回1。
少量的丢包, 我们仅仅是触发超时重传; 大量的丢包, 我们就认为网络拥塞; 当TCP通信开始后, 网络吞吐量会逐渐上升; 随着网络发生拥堵, 吞吐量会立刻下降; 拥塞控制, 归根结底是TCP协议想尽可能快的把数据传输给对方, 但是又要避免给网络造成太大压力的折中方案。开始时试探网络情况,如果接收到响应表明网络缓过来了,安装指数级增长尽快恢复。
在这里插入图片描述

十、延迟应答、捎带应答

延迟应答:

 如果接收数据的主机立刻返回ACK应答, 这时候返回的窗口可能比较小。但如果每次ACK前,我们先等一段时间,此时上层就有可能将数据取走,从而更新一个更大的窗口大小。此时发送端就可以更新更大的滑动窗口,并发发送更多的数据,从而提高效率!
 延迟应答机制有两种:数量限制: 每隔N个包就应答一次;时间限制: 超过最大延迟时间就应答一次。具体的数量和超时时间, 依操作系统不同也有差异; 一般超时时间取200ms。

在这里插入图片描述
捎带应答:

 在延迟应答的基础上,客户端和服务器一般是一收一发。但如果服务端对客户端报文进行应答时,也想进行数据发送。此时服务端只需将数据报文的ACK标记位置1,即两个报文合并为一个进行发送。我们将其称为捎带应答。

十一、粘包问题

 由于tcp面向字节流,当上层通过套接字tcp读取报文时,多读或少读一个完整报文时,并且上层还不做任何处理。此时该报文不完整或超量读取,我们将这种问题称为数据粘包问题!!
 
 虽然站在传输层角度,报文时一个一个过来的,然后按序号将数据放到缓冲区中。但站在应用层角度,如果用户不做任何处理,看到的只是一串连续的字节数据,并不清楚数据间的界限。此时读取数据时,就可能会产生数据粘包问题。
 
 要解决数据粘包问题,只需要明确报文间的界限即可。我们可以在报头前添加描述自身报文长度的字段,并将该字段和实际报文间通过换行隔开。此时接收方上层收到数据后,就可以先读取到换行符提取报文长度。然后按指定长度即可将完整报文提取出来!!(通过一些特殊字符来标识报文间边界、定长报文、报头 + 自描述字段)

  • 自定义协议,只需要解决序列化和反序列化问题,以及数据粘包问题才能成功!

十二、TCP异常情况

  1. 进程终止: Tcp连接本质就是文件。进程异常终止或退出,被打开的连接文件会由双方操作系统自动关闭!
  2. 机器重启:和进程终止情况相同。当我们机器重启时,电脑本身会询问我们是否关闭。如果确定,此时OS会先关闭所有线程后才重启!
  3. 机器断电/网线断开:首先tcp内部存在保活机制,假设服务器会向对方发送询问报文,如果都没响应,此时服务器会将连接断开!但tcp内部保活机制间隔时间一般几分钟或几小时,所以保活机制在应用层实现——心跳机制。  所以机器断电后有保活机制维护;但如果机器立马上线,没有触发保活机制。此时服务端向客户端发送消息后,客户端以及将该连接断开,此时客户端会返回RST报文,重新建立连接。  如果是客户端向服务器发送消息,浏览器一般都会自动识别到我们掉线了。重新向对端发送数据时,会新建连接。而对端会通过保活机制将老链接断开!

十三、面试题:请你说说 TCP 如何实现可靠传输

 可靠传输就是通过TCP连接传送的数据是没有差错、不会丢失、不重复并且按序到达的。TCP是通过序列号、检验和、确认应答信号、重发机制、连接管理、窗口控制、流量控制、拥塞控制一起保证TCP传输的可靠性的

校验和:目的是检测数据在传输过程中的任何变化。
序列号:保证数据按序到达。
确认应答:确保历史最近一条消息被对方收到。
超时重发:超时数据可能丢失,进行补发。
连接管理:确报全双工通道畅通。
流量控制:根据实际网络和对端情况,调整报发送速度。在保证速度前提下,防止数据大量丢包,和网络拥塞问题。通过滑动窗口实现。
拥塞控制:根据网络情况,当网络拥塞时,减少数据的发送。

提高性能:滑动窗口、快速重传、延迟应答、捎带应答
定时器(超时重传定时器, 保活定时器, TIME_WAIT定时器

十四、TCP/UDP对比

  • TCP面向字节流、有连接、可靠通信协议。主要用于可靠传输的情况, 应用于文件传输, 重要状态更新等场景
  • UDP面向数据报,无连接、不可靠通信协议。UDP的优点是快,节省了大量的网络资源;缺点是不可靠不稳定,网络不好的时候很容易造成数据丢失。主要用于对高速传输和实时性要求较高的通信领域,广泛应用于直播领域。

十五、用UDP实现可靠传输

 在应用层将UDP进行封装,比如提供确认序列号,保证数据拼接时候的正确排序;提供超时重传机制,能避免数据报丢失的问题。将TCP传输层功能,如确认机制、重传功能、流量控制、拥塞控制等功能实现在了应用层。

十六、listen 的第二个参数

ROS 2 Humble + Gazebo Fortress 搭建AGV小车仿真环境(保姆级避坑指南) 本文详细介绍了如何使用ROS 2 Humble和Gazebo Fortress搭建AGV小车仿真环境,包括环境准备、URDF模型构建、ROS 2控制集成、传感器配置等关键步骤。特别针对Gazebo Fortress版本差异提供了保姆级避坑指南,帮助开发者快速解决常见问题并优化性能。 阅读详情

相关推荐

波分复用-Zblock仿真

Z-BLOCK是一种用于光通信模块的光学元件,其核心结构是在玻璃块一侧贴有4个特定波长滤光片,另一侧镀有反射膜和增透膜。光信号在内部呈现Z字形反射路径,实现波长分离。文章以可见光LED为例,在ZEMAX中演示了非序列模式下的建模过程,重点介绍了滤光片和膜层的参数设置方法。需要注意的是,入射角度需根据玻璃折射率、通道高度和厚度精确计算,否则可能导致光泄漏。该建模方法同样适用于光通信中的光纤激光器系统。

Zhaxibamao的博客 1743

【Linux】UDP、TCP协议

在TCP/IP协议中, 用 "源IP", "源端口号", "目的IP", "目的端口号", "协议号" 这样一个五元组来标识一个通信(可以通过netstat -n查看);IP+端口号,用来表明互联网中的唯一一台主机上的唯一一个进程。

Edward_Asia的博客 1538

三维点云孔洞修复(附Python代码和公共点云数据集链接)

(1)物体自身缺失(2)物体自身形状复杂,很多凹凸面不够规则甚至存在空腔,空腔内部无法被三维激光扫描仪扫描到(3)物体部分区域对激光扫描不敏感,未被扫描上(4)扫描仪的扫描稳定性。

yanghl1215的博客 6948

Linux【网络基础】之UDP&TCP协议

Linux【网络基础】之UDP&TCP协议

m0_59292239的博客 1631

第一天(点亮led灯+led灯闪烁)——Arduino uno R3 学习之旅

发光二极管(Light Emitting Diode,简称LED)是一种能够将电能转化为光能的固态的半导体器件。长脚为阳极短脚为阴极电流必须从长脚流入从短脚流出方可点亮LED##杜邦线杜邦线:是导线中的一种,杜邦线端部有两种接头形式:带针的一种称为公头,带孔的一种称为母头,如下图所示:说明:与电源相连接时,一般采用红色杜邦线,与地连接时采用黑色杜邦线。

qwsbcjendb的博客 1126

Apple Pay不能添加卡,不一定是卡的问题,有可能是设备的问题

Apple Pay不能添加卡,不一定是卡的问题,有可能是设备的问题。

wyxtx的博客 3431

Linux网络-UDP/TCP协议详解

本章主要讲解传输层协议UDP及TCP相关的内容。

qq_20312079的博客 2373

【第六届起重机创意大赛国一作品——资料分享】

文章目录前言一、比赛内容分析二、确定方案与作品模型1.方案简图2.作品模型三、电控部分控制思路单片机选择与资源分配拓展板的设计接线与走线代码分享总结

qq_19308801的博客 7781

Linux网络编程:UDP协议和TCP协议

本文对UDP协议和TCP协议进行了详细

weixin_43908419的博客 685

《跨界杂谈》华为印象(五):高度集权的矩阵式架构

高度集权的矩阵式架构 “高度集权的矩阵式架构”不是官方术语。是笔者的一位同事非常经典的总结。解释这个句话还是有点困难的,笔者入职华为三年也没彻底搞明白,在这里只能尝试性的解释一下。 矩阵 我们先看一下“矩阵”。华为有两套部门职能体系,华为内部术语,叫实线部门和虚线部门。由实线与虚线部门交叉构成矩阵。大部分(但不是所有)华为员工都由两个部门(两个领导)进行管理。对员工而言,所谓的实线部

《云计算架构技术与实践》 2994

openlayers:实现在连续更改时间维度时如何平滑地重新加载层 (附完整源码)

openlayers:实现在连续更改时间维度时如何平滑地重新加载层 (附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 345

【Linux网络】网络基础:传输层UDP/TCP协议(一)

传输层协议,特别是用户数据报协议(UDP)和传输控制协议(TCP),是网络通信中最为基础也最为重要的部分。它们不仅决定了数据的传输方式,还影响着数据的可靠性、顺序性和实时性。对于想要深入了解互联网运行机制、掌握网络通信技术的朋友们来说,学习UDP/TCP协议无疑是必经之路。

EterNity_TiMe_的计算机学习之路 6709

【YoloV8改进策略】上采样改进|EUCB,轻量高效的上采样模块|即插即用

YOLOv8作为当前最先进的实时目标检测与实例分割模型之一,其在速度与精度之间取得了出色的平衡。然而,在资源受限的边缘设备或对实时性要求极高的应用场景中,YOLOv8的计算开销,尤其是在特征金字塔网络(FPN)和路径聚合网络(PAN)中用于特征融合的上采样操作,仍然是一个瓶颈。YOLOv8的颈部(Neck)结构中广泛使用nn.Upsample进行上采样,该操作虽然简单,但缺乏对特征内容的感知能力,且后续通常需要标准卷积来修复因插值带来的伪影,这增加了不必要的计算负担。

m0_47867638的博客 747

【Linux网络】Linux网络编程套接字,UDP与TCP

在当今这个信息技术日新月异的时代,网络编程已成为连接世界、构建各类互联网应用不可或缺的一部分。而Linux,作为开源操作系统的典范,其强大的网络功能和灵活性,为开发者们提供了一个广阔而深入的实践平台。在众多网络编程技术中,套接字(Socket)编程无疑是核心与基石,它不仅支撑着Web服务、即时通讯、在线游戏等日常应用,还是实现分布式系统、云计算服务的关键技术之一。

EterNity_TiMe_的计算机学习之路 5619

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

【探索Linux】P.27(网络编程套接字 —— UDP协议介绍 | TCP协议介绍 | UDP 和 TCP 的异同)

用户数据报协议(UDP,User Datagram Protocol)是一个简单的面向数据报的传输层协议,它在互联网协议族中与传输控制协议(TCP)并列,为应用程序提供了一种非常基础的服务:将应用程序数据报从一台主机发送到另一台主机。然而,与TCP不同的是,UDP不提供可靠性保证,也不实现数据包的顺序控制、重发机制或是拥塞控制。这种设计选择使得UDP在某些场景下比TCP更高效、更适用。

Yawesh的博客 3863

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

基于TCP或UDP的应用层协议有哪些?——Linux网络编程

一、基于TCP的应用层协议有:SMTP、TELNET、HTTP、FTP 基于UDP的应用层协议:DNS、TFTP(简单文件传输协议)、RIP(路由选择协议)、DHCP、BOOTP(是DHCP的前身)、IGMP(Internet组管理协议) ...

博雅勇士的博客 5万+

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Windows下的TCP/UDP网络调试工具-NetAssist以及Linux下的nc网络调试工具

Windows下的TCP/UDP网络调试工具-NetAssist以及Linux下的nc网络调试工具一、Windows下的网络调试工具-NetAssist1.TCP服务端和客户端测试2.UDP服务端和客户端测试Linux下的网络调试命令工具-`nc`什么是ncnc的作用在CentOS7中安装`nc`命令工具参考资料 一、Windows下的网络调试工具-NetAssist 由于在Windows下经常使用NetAssist.exe这款网络调试工具进行TCP、UDP的服务端、客户端的监听,对于需要编写各种通信协议的

ccf19881030的专栏 4万+

【网络通信与信息安全】之深入解析TCP与UDP传输协议

一、什么是 socket ? Socket 的英文原义是“孔”或“插座”。在编程中,Socket 被称做套接字,是网络通信中的一种约定。Socket 编程的应用无处不在,我们平时用的 QQ、微信、浏览器等程序,都与 Socket 编程有关。 那么我们平时使用浏览器查资料,这个过程的技术原理是怎样的呢?如下所示: 使用浏览器,有两个重要的名词:服务端与客户端,Socket 编程的目的就是如何实现这两端之间的通信。 ...

╰つ栺尖篴夢ゞ 2万+

C/C++ Linux Socket网络编程 TCP 与 UDP

详细介绍Linux环境C/C++如何使用socket通信,TCP与UDP;

cpp_learner的博客 1万+

【Linux 网络编程】Tcp/Udp协议(上)

本文对比分析了UDP和TCP两种传输层协议的特性。

2301_80349538的博客 2845

【Linux网络编程】传输层协议TCP,UDP

客户端调用connect发起三次握手,向服务器发起建立连接的请求。而服务器端通过listen将自己设置为监听状态。本质上,connect是发起三次握手,但是不参与三次握手的。服务器端通过accept获取底层建立好的连接,也不参与三次握手。

2401_82677021的博客 1925

【Linux网络】————socket和udp协议

字符串转in_addr的函数:in_addr转字符串的函数:其中inet_pton和inet_ntop不仅可以转换IPv4的in_addr,还可以转换IPv6的in6_addr,因此函数接口是void*addrptr1.一个冷知识:屏蔽力是一个人最顶级的能力,任何消耗你的人和事,多看一眼都是你的不对。2.你不用变得很外向,内向挺好的,但需要你发言的时候,一定要勇敢。正所谓:君子可内敛不可懦弱,面不公可起而论之。3.成年人的世界,只筛选,不教育。

bhbcdxb123的博客 1944

【网络】TCP与UDP协议使用指南,Socket编程实现Echo服务

本文介绍了TCP和UDP协议的核心特点及网络编程基础。主要内容包括: TCP与UDP协议对比 TCP是面向连接、可靠传输的字节流协议 UDP是无连接、不可靠传输的数据报协议 网络字节序规范 网络传输统一使用大端模式 提供htonl/htons等函数进行主机序和网络序转换 Socket编程核心接口 创建socket和绑定IP端口的基本方法 UDP使用recvfrom/sendto进行数据收发 TCP通过listen/accept/connect建立连接 连接建立后可使用read/write通信

记录我一步步的学习历程,期待无限进步,向星举目! 2443

【Linux网络】传输层协议UDP与TCP

UDP和TCP是两种主要的网络传输协议。 UDP是一种无连接的协议,它不保证数据包的顺序或可靠性。它通过发送数据包而不进行任何确认来实现快速传输,适合对实时性要求高的应用,如视频流和在线游戏。UDP的头部开销小,只有8个字节,这有助于减少延迟。 TCP是一种面向连接的协议,它确保数据包的顺序和可靠性。在数据传输前,TCP会建立一个连接,并通过确认和重传机制来保证数据的完整性。TCP适合需要可靠传输的应用,如网页浏览和文件传输。TCP的头部开销较大,通常是20个字节,这可能会增加一些延迟。

why 1673

Linux C/C++之TCP / UDP通信

Linux/C语言实现TCP/UDP普通通信以及文件传输(最详细的步骤)

ShiXiAoLaNga的博客 6604

Linux基础-socket详解、TCP/UDP

所谓socket通常也称作 “套接字”,用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过 “套接字” 向网络发出请求或者应答网络请求。Socket 是计算机网络编程中一个重要的概念,它是在应用层和传输层之间提供的一种抽象接口,用于实现应用程序之间的数据交换。Socket 允许程序员使用一种通用的接口来访问底层传输协议,如 TCP 和 UDP,以便进行网络通信。Socket 是一种编程接口,它提供了一种标准化的方式来创建网络连接,并允许应用程序在网络上发送和接收数据。

weixin_37553721的博客 6092
上一篇: 【Linux 网络 (三)】:https协议加密解密分析 —— 秘钥协商
下一篇: Mysql:数据库
小白debug~
小白debug~ 新星创作者: C/C++技术领域 新星创作者: C/C++技术领域
博客等级 码龄4年 3510粉丝 128原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白debug~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值