当前位置: 首页 > news >正文

网络协议常见问题

网络协议常见问题

  • OSI(Open Systems Interconnection)模型
    • OSI 封装
  • TCP/IP协议栈
    • IP数据报的报头
    • TCP头格式
    • UDP头格式
    • TCP (3-way shake)三次握手建立连接:
    • 为什么三次握手才可以初始化 Socket、序列号和窗口大小并建立 TCP 连接。
    • 每次建立TCP连接时,初始化的序列号都要求不一样
    • TCP四次挥手断开
    • TCP连接中,客户端和服务器之间操作
    • TCP如何实现可靠传输
    • TCP 流量控制、拥塞控制
    • TCP和UDP的区别
    • TCP粘包问题
    • TCP重置技术
    • TCP Socket编程
    • IP地址及端口问题
    • IP层会分片,为什么TCP层还需要MSS呢
    • HTTP3放弃TCP:
    • NAPT(Network Address Port Transfer , 网络地址端口转换 )工作原理。
    • 常用网络命令
    • 常用协议
  • 墙裂推荐网络学习参考

OSI(Open Systems Interconnection)模型

在这里插入图片描述

  • 应用层
    应用层最接近终端用户。大多数应用程序都位于这一层。我们从后端服务器请求数据,无需了解数据传输的具体细节。这一层的协议包括 HTTP、SMTP、FTP、DNS 等。
  • 表现层
    这一层处理数据编码、加密和压缩,为应用层准备数据。例如,HTTPS 利用 TLS(Transport Layer Security)实现客户端与服务器之间的安全通信。
  • 会话层
    该层用于打开和关闭两个设备之间的通信。如果数据量较大,会话层就会设置检查点,避免从头开始重新发送。
  • 传输层
    该层处理两个设备之间的端到端的通信。它在发送方将数据分解成段,然后在接收方重新组装。这一层有流量控制,以防止拥塞。这一层的主要协议是 TCP 和 UDP。
  • 网络层
    这一层实现不同网络之间的数据传输。它进一步将网段或数据报分解成更小的数据包,并使用 IP 地址找到通往最终目的地的最佳路由。
  • 数据链路层
    这一层允许在同一网络的设备之间传输数据。数据包被分解成帧,这些帧被限制在局域网内。
  • 物理层
    这一层通过电缆和交换机发送比特流,因此与设备之间的物理连接密切相关。

与OSI模型相比,TCP/IP 模型只有4层。在讨论网络协议的层次时,必须明确上下文。

OSI 封装

在这里插入图片描述
每一层都使用报头来处理指令,而不需要解封上一层的数据。

  • 步骤 1:
    当设备 A 使用 HTTP 通过网络向设备 B 发送数据时,最初会在应用层添加一个 HTTP 报头。
  • 步骤 2:
    在数据中添加 TCP 或 UDP 报头。它在传输层被封装成 TCP 段。报头包含源端口、目的端口和序列号。
  • 步骤 3:
    然后在网络层用 IP 报头对这些段落进行封装。IP 报头包含源 IP 地址和目的 IP 地址。
  • 步骤 4:
    在数据链路层为 IP 数据报添加 MAC 报头,其中包含源 MAC 地址和目的 MAC 地址。
  • 步骤 5:
    封装帧被发送到物理层,并作为比特流在网络上发送。
  • 步骤 6-10:
    设备 B 从网络接收到比特流后,会启动去封装过程,这与封装过程相反。报头逐层去除,直到设备 B 可以访问原始数据。

TCP/IP协议栈

TCP/IP协议栈是一组用于网络通信的协议,它包括物理层、数据链路层、网络层、传输层和应用层。每个层次的协议都提供了不同的功能,例如,网络层协议IP负责将数据包从一个主机传输到另一个主机,而传输层协议TCP提供可靠的数据传输。

IP数据报的报头

在这里插入图片描述
IP数据报的报头包含以下字段:

  • 版本(Version):指定IP协议的版本,通常为IPv4或IPv6。
  • 首部长度(Header Length):指定IP报头的长度,以32位字(4字节)为单位。
  • 服务类型(Type of Service):用于指定数据报的服务质量要求,如优先级、延迟、吞吐量等。
  • 总长度(Total Length):指定整个IP数据报的长度,包括报头和数据部分。
  • 标识(Identification):用于唯一标识一个IP数据报,通常由发送方设置,接收方用于重组分片。
  • 标志(Flags):包含3个标志位,分别是DF(Don’t Fragment,不分片)、MF(More Fragments,更多分片)、和保留位。
  • 分片偏移(Fragment Offset):用于指示当前分片相对于原始数据报的偏移量,以8字节为单位。
  • 生存时间(Time to Live):指定数据报在网络中可以经过的最大路由器跳数,每经过一个路由器,该值减1,为0时数据报被丢弃。
  • 协议(Protocol):指定IP数据报中承载的上层协议,如TCP、UDP、ICMP等。
  • 头部校验和(Header Checksum):用于检验IP报头的完整性,接收方使用该字段来验证报头是否正确。
  • 源IP地址(Source IP Address):指定发送方的IP地址。
  • 目标IP地址(Destination IP Address):指定接收方的IP地址。

TCP头格式

在这里插入图片描述

  • 序列号:在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。
  • 确认应答号:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题。
  • 控制位:
    • ACK:该位为 1 时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的 SYN 包之外该位必须设置为 1 。
    • RST:该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接。
    • SYN:该位为 1 时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。
    • FIN:该位为 1 时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换 FIN 位为 1 的 TCP 段。

IP 层是“不可靠”的,它不保证网络包的交付、不保证网络包的按序交付、也不保证网络包中的数据的完整性。源地址和目的地址的字段(32 位)是在 IP 头部中。

TCP 是一个工作在传输层的可靠数据传输的服务,它能确保接收端接收的网络包是无损坏、无间隔、非冗余和按序的。总之,TCP 是面向连接的、可靠的、基于字节流的传输层通信协议

  • 面向连接:一定是「一对一」才能连接,不能像 UDP 协议可以一个主机同时向多个主机发送消息,也就是一对多是无法做到的;
  • 可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端;
  • 字节流:用户消息通过 TCP 协议传输时,消息可能会被操作系统「分组」成多个的 TCP 报文,如果接收方的程序如果不知道「消息的边界」,是无法读出一个有效的用户消息的。并且 TCP 报文是「有序的」,当「前一个」TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理,同时对「重复」的 TCP 报文会自动丢弃。

建立一个 TCP 连接是需要客户端与服务端达成上述三个信息的共识

  • Socket:由 IP 地址和端口号组成
  • 序列号:用来解决乱序问题等
  • 窗口大小:用来做流量控制

TCP 四元组可以唯一的确定一个连接

  • 源地址
  • 源端口
  • 目的地址
  • 目的端口

UDP头格式

UDP 不提供复杂的控制机制,利用 IP 提供面向「无连接」的通信服务。UDP 协议头部只有 8 个字节(64 位),UDP 的头部格式如下:
在这里插入图片描述

  • 目标和源端口:主要是告诉UDP协议应该把报文发给哪个进程。
  • 包长度:该字段保存了UDP首部的长度跟数据的长度之和。
  • 校验和:校验和是为了提供可靠的UDP首部和数据而设计,防止收到在网络传输中受损的UDP包。

TCP (3-way shake)三次握手建立连接:

在这里插入图片描述

  • 一开始,客户端和服务端都处于CLOSE状态。先是服务端主动监听某个端口,处于LISTEN状态.
    在这里插入图片描述
  • 客户端会随机初始化序号(client_isn),将此序号置于 TCP 首部的 “序列号” 字段中,同时把 SYN 标志位置为 1,表示 SYN 报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于 SYN-SENT 状态
    在这里插入图片描述
  • 服务端收到客户端的 SYN 报文后,首先服务端也随机初始化自己的序号(server_isn),将此序号填入 TCP 首部的 “序列号” 字段中,其次把 TCP 首部的 “确认应答号” 字段填入 client_isn + 1, 接着把 SYN 和 ACK 标志位置为 1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 SYN-RCVD 状态
    在这里插入图片描述
  • 客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部 ACK 标志位置为 1 ,其次 “确认应答号” 字段填入 server_isn + 1 ,最后把报文发送给服务端这次报文可以携带客户到服务端的数据,之后客户端处于 ESTABLISHED 状态服务端收到客户端的应答报文后,也进入 ESTABLISHED 状态

为什么三次握手才可以初始化 Socket、序列号和窗口大小并建立 TCP 连接。

  1. 首先是为了防止旧的重复连接初始化造成混乱(避免历史连接)。
    考虑一个场景,客户端先发送了 SYN(seq = 90)报文,然后客户端宕机了,而且这个 SYN 报文还被网络阻塞了,服务端并没有收到,接着客户端重启后,又重新向服务端建立连接,发送了 SYN(seq = 100)报文(注意!不是重传 SYN,重传的 SYN 的序列号是一样的)。
    在这里插入图片描述
    客户端连续发送多次 SYN(都是同一个四元组)建立连接的报文,在网络拥堵情况下:

    • 一个 “旧 SYN 报文(seq = 90)”比 “最新的 SYN(seq = 100)” 报文早到达了服务端,那么此时服务端就会回一个 SYN + ACK 报文给客户端,此报文中的确认号是 91(90+1)。
    • 客户端收到后,发现自己期望收到的确认号应该是 100 + 1,而不是 90 + 1,于是就会回 RST 报文
    • 服务端收到 RST 报文后,就会释放连接
    • 后面 “最新的 SYN ” 抵达了服务端后,客户端与服务端就可以正常的完成三次握手了。

    上述中的 “旧 SYN 报文” 称为历史连接,TCP 使用三次握手建立连接的最主要原因就是防止 “历史连接" 初始化了连接。

    如服务端收到客户端报文的顺序是:“旧 SYN 报文” ->“新 SYN 报文”,此时会发生什么:

    • 当服务端第一次收到 SYN 报文,也就是收到 “旧 SYN 报文” 时,就会回复 SYN + ACK 报文给客户端,此报文中的确认号是 91(90+1)。
    • 然后这时再收到 “新 SYN 报文” 时,就会回 Challenge Ack报文给客户端,这个 ack 报文并不是确认收到 “新 SYN 报文” 的,而是上一次的 ack 确认号,也就是91(90+1)。所以客户端收到此 ACK 报文时,发现自己期望收到的确认号应该是 101,而不是 91,于是就会回 RST 报文。

    在两次握手的情况下,服务端没有中间状态给客户端来阻止历史连接,导致服务端可能建立一个历史连接,造成资源浪费。

  2. 其次为了同步双方初始序列号
    TCP协议的通信双方, 都必须维护一个 “序列号” , 序列号是可靠传输的一个关键因素,作用:

    • 接收方可以去除重复的数据;
    • 接收方可以根据数据包的序列号按序接收;
    • 可以标识发送出去的数据包中, 哪些是已经被对方收到的(通过 ACK 报文中的序列号知道);

    可见,序列号在TCP连接中占据着非常重要的作用,所以当客户端发送携带 “初始序列号” 的 SYN 报文的时候,需要服务端回一个 ACK 应答报文,表示客户端的 SYN 报文已被服务端成功接收,那当服务端发送 “初始序列号” 给客户端的时候,依然也要得到客户端的应答回应。这样一来一回,才能确保双方的初始序列号能被可靠的同步。

  3. 避免资源浪费
    如果只有 “两次握手”,当客户端发生的 SYN 报文在网络中阻塞,客户端没有接收到 ACK 报文,就会重新发送 SYN ,由于没有第三次握手,服务端不清楚客户端是否收到了自己回复的 ACK 报文,所以服务端每收到一个 SYN 就只能先主动建立一个连接
    如果客户端发送的 SYN 报文在网络中阻塞了,重复发送多次 SYN 报文,那么服务端在收到请求后就会建立多个冗余的无效链接,造成不必要的资源浪费。

每次建立TCP连接时,初始化的序列号都要求不一样

主要原因有两个方面:

  • 主要是为了防止历史报文被下一个相同四元组的连接接收。
  • 其次为了安全性,防止黑客伪造的相同序列号的TCP报文被对方接收。

接收历史相同四元组的过程如下:

  • 客户端和服务端建立一个TCP连接,在客户端发送数据包被网络阻塞了,然后超时重传了这个数据包,而此时服务端设备断电重启了,之前与客户端建立的连接就消失了,于是在收到客户端的数据包的时候就会发送RST报文。
  • 紧接着,客户端又与服务端建立了与上一个连接相同四元组的连接;
  • 在新连接建立完成后,上一个连接中被网络阻塞的数据包正好抵达了服务端,刚好该数据包的序列号正好是在服务端的接收窗口内,所以该数据包会被服务端正常接收,就会造成数据错乱。

初始序列号ISN是如何随机产生的?

  • 起始ISN是基于时钟的,每4微秒+1,转一圈要4.55个小时。

大量SYN包发送给服务端服务端会怎样

可能会导致TCP半连接队列满,如TCP半连接队列满了,后续再在收到SYN报文就会丢弃,导致客户端无法和服务端建立连接。避免SYN攻击方式,可以有以下四种方法:

  • 调大netdev_max_backlog;
  • 增大TCP半连接队列;
  • 开启tcp_syncookies;
  • 减少SYN+ACK重传次数

TCP四次挥手断开

在这里插入图片描述

  1. 客户端主动调用关闭连接的函数,于是就会发送 FIN 报文,这个 FIN 报文代表客户端不会再发送数据了,进入 FIN_WAIT_1 状态
  2. 服务端收到了 FIN 报文,然后马上回复一个 ACK 确认报文,此时服务端进入 CLOSE_WAIT 状态。在收到 FIN 报文的时候,TCP 协议栈会为 FIN 包插入一个文件结束符 EOF 到接收缓冲区中,服务端应用程序可以通过 read 调用来感知这个 FIN 包,这个 EOF 会被放在已排队等候的其他已接收的数据之后,所以必须要得继续 read 接收缓冲区已接收的数据;
  3. 接着,当服务端在 read 数据的时候,最后自然就会读到 EOF,接着 read() 就会返回 0,这时服务端应用程序如果有数据要发送的话,就发完数据后才调用关闭连接的函数,如果服务端应用程序没有数据要发送的话,可以直接调用关闭连接的函数,这时服务端就会发一个 FIN 包,这个 FIN 报文代表服务端不会再发送数据了,之后处于 LAST_ACK 状态
  4. 客户端接收到服务端的 FIN 包,并发送 ACK 确认包给服务端,此时客户端将进入 TIME_WAIT 状态;
  5. 服务端收到 ACK 确认包后,就进入了最后的 CLOSE 状态
  6. 客户端经过 2MSL 时间之后,也进入 CLOSE 状态;

每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手。

  • 第二次挥手丢失
    客户端会触发超时重传 FIN 报文,达到最大的重传次数,再等待一段时间,客户端就会断开连接。
  • 第三次挥手丢失
    服务端重传第三次挥手报文达到最大值,再等待一段时间,服务端就会断开连接。客户端如tcp_fin_timeout 时间内还是没能收到服务端的第三次挥手(FIN 报文),那么客户端就会断开连接。
  • 第四次挥手丢失
    当客户端收到服务端的第三次挥手的 FIN 报文后,就会回 ACK 报文,也就是第四次挥手,此时客户端连接进入 TIME_WAIT 状态。持续 2MSL 后才会进入关闭状态。

为什么 TIME_WAIT 等待的时间是 2MSL(MSL 是 Maximum Segment Lifetime,报文最大生存时间)

  1. 防止历史连接中的数据,被后面相同四元组的连接错误的接收
    为了防止历史连接中的数据,被后面相同四元组的连接错误的接收,因此 TCP 设计了 TIME_WAIT 状态,状态会持续 2MSL 时长,这个时间足以让两个方向上的数据包都被丢弃,使得原来连接的数据包在网络中都自然消失,再出现的数据包一定都是新建立连接所产生的。

  2. 保证 “被动关闭连接” 的一方,能被正确的关闭
    TIME-WAIT 作用是等待足够的时间以确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。

    如果客户端(主动关闭方)最后一次 ACK 报文(第四次挥手)在网络中丢失了,那么按照 TCP 可靠性原则,服务端(被动关闭方)会重发 FIN 报文。

    假设客户端没有 TIME_WAIT 状态,而是在发完最后一次回 ACK 报文就直接进入 CLOSE 状态,如果该 ACK 报文丢失了,服务端则重传的 FIN 报文,而这时客户端已经进入到关闭状态了,在收到服务端重传的 FIN 报文后,就会回 RST 报文。服务端收到这个 RST 并将其解释为一个错误(Connection reset by peer),这对于一个可靠的协议来说不是一个优雅的终止方式。

当存在大量close_wait的连接时怎么处理

  • CLOSE_WAIT 状态是(被动关闭方)才会有的状态,而且如果(被动关闭方)没有调用 close 函数关闭连接,那么就无法发出 FIN 报文,从而无法使得 CLOSE_WAIT 状态的连接转变为 LAST_ACK 状态。

    所以,当服务端出现大量 CLOSE_WAIT 状态的连接的时候,说明服务端的程序没有调用 close 函数关闭连接。

大量TIME_WAIT什么原因

  • TIME_WAIT 状态是主动关闭连接方才会出现的状态,所以如果服务器出现大量的 TIME_WAIT 状态的 TCP 连接,就是说明服务器主动断开了很多 TCP 连接。

TCP连接中,客户端和服务器之间操作

  • 握手阶段:客户端向服务器发送SYN包(同步包),请求建立连接。服务器收到SYN包后,向客户端发送SYN+ACK包(同步确认包),表示可以建立连接。客户端收到SYN+ACK包后,再向服务器发送ACK包(确认包),表示连接建立成功。
  • 数据传输阶段:连接建立成功后,客户端和服务器之间可以进行数据的传输。客户端向服务器发送数据包,服务器接收数据包并进行处理,然后向客户端发送响应包。客户端收到响应包后,可以再次向服务器发送数据包,以此类推。
  • 断开连接阶段:当客户端或服务器不再需要连接时,可以发送FIN包(结束包)来请求断开连接。对方收到FIN包后,也发送FIN包进行响应,表示同意断开连接。当两端都收到对方的FIN包后,连接才真正关闭。

TCP如何实现可靠传输

  1. 序列号与确认应答:TCP将每个发送的数据包进行编号(序列号),接收方通过发送确认应答(ACK)来告知发送方已成功接收到数据。如果发送方在一定时间内未收到确认应答,会进行超时重传。
  2. 数据校验:TCP使用校验和来验证数据在传输过程中是否发生了损坏。接收方会计算校验和并与发送方发送的校验和进行比较,如果不一致,则说明数据包发生了损坏,需要重新发送。
  3. 滑动窗口控制:TCP使用滑动窗口机制来控制发送方和接收方之间的数据流量。发送方根据接收方的处理能力和网络状况来调整发送的数据量,接收方则通过窗口大小来告知发送方可以接收的数据量。
  4. 重传机制:如果发送方未收到确认应答或接收方检测到数据错误,TCP会进行重传。发送方会根据超时时间或接收方的冗余确认来触发重传,以确保数据的可靠传输。
  5. 拥塞控制:TCP使用拥塞控制算法来避免网络拥塞。通过动态调整发送速率和窗口大小,TCP可以根据网络的拥塞程度来进行适当的调整,以提高网络的利用率和稳定性。

TCP 流量控制、拥塞控制

发送方发数据给接收方,要考虑接收方处理能力,如果接收方对方处理不过来,那么就会导致触发重发机制,从而导致网络流量的无端的浪费。为了解决这种现象发生,
TCP 提供一种机制可以让(发送方)根据(接收方)的实际接收能力控制发送的数据量,这就是所谓的流量控制

在网络出现拥堵时,如果继续发送大量数据包,可能会导致数据包时延、丢失等,这时 TCP 就会重传数据,但重传就会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,这个情况就会进入恶性循环。当网络发送拥塞时,TCP会自我牺牲,降低发送的数据量。于是,就有了拥塞控制,目的就是避免(发送方)的数据填满整个网络。

TCP传输协议中,流量控制是使用**滑动窗口(Sliding Window)**来实现的。滑动窗口是一种基于数据流的、动态调整的、可变大小的窗口,它通过协商双方的接收窗口和发送窗口大小,控制数据的传输速率。

在TCP协议中,每个数据包都有一个序号,接收方通过序号来确认是否收到了正确的数据包。发送方将数据分成若干个数据段,每个数据段的大小不超过发送窗口的大小,然后将这些数据段发送给接收方。接收方会确认已经收到的数据,同时告诉发送方自己的接收窗口大小。发送方根据接收方的窗口大小,动态调整自己的发送窗口大小,从而控制数据的传输速率

滑动窗口的大小是可以动态调整的,它可以根据网络状况和双方的能力来自适应地调整,从而实现流量控制的功能。如果接收方的接收窗口变小,发送方会相应地减小自己的发送窗口,以避免过多的数据堆积在网络中导致拥塞。如果接收方 的接收窗口变大,发送方会相应地增加自己的发送窗口,以提高数据传输速率。

TCP和UDP的区别

  1. 连接。TCP 是面向连接的传输层协议,传输数据前先要建立连接。UDP是不需要连接,即刻传输数据。TCP建立和释放连接需要进行三次握手和四次挥手。UDP无需进行三次握手和四次挥手。说明UDP比TCP实时性更强。
  2. 首部开销。TCP 首部长度较长,会有一定的开销,首部在没有使用(选项)字段时是 20 个字节,如果使用了(选项)字段则会变长的。UDP 首部只有 8 个字节,并且是固定不变的,开销较小。
  3. 服务对象。TCP 是一对一的两点服务,即一条连接只有两个端点。UDP 支持一对一、一对多、多对多的交互通信
  4. 可靠性。TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按序到达。UDP 是尽最大努力交付,不保证可靠交付数据。但是我们可以基于 UDP 传输协议实现一个可靠的传输协议,比如 QUIC 协议。
  5. 拥塞控制、流量控制。TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率。
  6. 传输方式。TCP 是流式传输,没有边界,但保证顺序和可靠。UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序。
  7. 分片不同。TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完数据,接着再传给传输层。
  8. 应用场景不同。
    TCP是面向连接,能保证数据的可靠性交付,因此经常用于:FTP文件传输;HTTP/HTTPS(网页)、电子邮件、远程登录连接;
    UDP面向无连接,随时发送数据,再加上UDP本身的处理既简单又高效,因此经常用于包总量较少的通信,如DNS、SNMP等、视频、音频等多媒体通信、广播通信。

为什么UDP头部没有 “首部长度” 字段,而TCP头部有 “首部长度” 字段

  • TCP有可变长的 “选项” 字段,而UDP头部长度则是不会变化的,无需多一个字段去记录UDP的首部长度。

为什么UDP头部有 “包长度” 字段,而TCP头部则没有 “包长度” 字段

  • TCP的负载数据长度, 可以根据IP总长度、IP首部长度(IP首部格式是已知的)、TCP首部长度求得TCP数据的长度。

TCP粘包问题

TCP的粘包问题是指当发送方将多个数据包连续发送到接收方时,接收方可能将它们看作单个大的数据包。这种问题可能会导致数据丢失或数据不完整。为了避免TCP的粘包问题,可以使用一些技术,如消息边界标记、消息长度标记和消息头标记。

  1. 固定长度的消息
    这种是最简单方法,即每个用户消息都是固定长度的,比如规定一个消息的长度是 64 个字节,当接收方接满 64 个字节,就认为这个内容是一个完整且有效的消息。
    但是这种方式灵活性不高,实际中很少用。
  2. 特殊字符作为边界
    我们可以在两个用户消息之间插入一个特殊的字符串,这样接收方在接收数据时,读到了这个特殊字符,就把认为已经读完一个完整的消息。
  3. 自定义消息结构
    我们可以自定义一个消息结构,由包头和数据组成,其中包头包是固定大小的,而且包头里有一个字段来说明紧随其后的数据有多大。

UDP的粘包问题是指当发送方将多个数据包连续发送到接收方时,接收方可能将它们看作单个大的数据包。这种问题可能会导致数据丢失或数据不完整。UDP协议本身并没有提供解决粘包问题的机制,因此应用程序需要自己解决这个问题。解决粘包问题的方法包括使用消息边界标记、消息长度标记和消息头标记等。

TCP重置技术

“伪造RST报文来关闭TCP连接” 的方式叫做TCP重置攻击,伪造RST报文时,要保证伪造的RST报文的序列号能被对方接受。

  • tcpkill工具是在双方进行TCP通信时,拿到对方下一次期望收到的序列号,然后将序列号填充到伪造的RST报文,并将其发送给对方,达到关闭TCP连接的效果。

    tcpkill工具属于被动获取,就是在双方进行TCP通信的时候,才能获取到正确的序列号,很显然这种方式无法关闭非活跃的TCP连接,只能用于关闭活跃的TCP连接。因为如果这条TCP连接一直没有任何数据传输,则就永远获取不到正确的序列号。

  • killcx工具是主动发送一个SYN报文,对方收到后会回复一个携带了正确序列号和确认号的ACK报文,这个ACK被称之为ChallengeACK,这时就可以拿到对方下一次期望收到的序列号,然后将序列号填充到伪造的RST报文,并将其发送给对方,达到关闭TCP连接的效果。

    killcx工具则是属于主动获取,它是主动发送一个SYN报文,通过对方回复的ChallengeACK来获取正确的序列号,所以这种方式无论TCP连接是否活跃,都可以关闭。

TCP Socket编程

在这里插入图片描述

  • 服务端和客户端初始化socket,得到文件描述符;
  • 服务端调用bind,将socket绑定在指定的IP地址和端口;
  • 服务端调用listen,进行监听;
  • 服务端调用accept,等待客户端连接;
  • 客户端调用connect,向服务端的地址和端口发起连接请求;
  • 服务端accept返回用于传输的socket的文件描述符;
  • 客户端调用write写入数据;服务端调用read读取数据;
  • 客户端断开连接时,会调用close,那么服务端read读取数据的时候,就会读取到了EOF,待处理完数据后,服务端调用close,表示连接关闭。

连接的主要实现步骤:

  • 服务器端:socker()建立套接字,绑定(bind)并监听(listen),用accept()
    等待客户端连接。
  • 客户端:socker()建立套接字,连接(connect)服务器,连接上后使用send()和recv(
    ),在套接字上写读数据,直至数据交换完毕,close socket()关闭套接字。
  • 服务器端:accept()发现有客户端连接,建立一个新的套接字,自身重新开始等待连
    接。该新产生的套接字使用send()和recv()写读数据,直至数据交换完毕,closesock
    et()关闭套接字。

IP地址及端口问题

  1. 客户端连接一个不存在的IP地址会怎样

    • 目标IP地址和客户端的IP地址是同一个局域网(网络号相同)的情况。
      • 客户端无法发出SYN报文,主要卡在数据链路层。
      • 因为目标地址不存在IP地址,客户端的内核在发arp请求的时候,广播询问这个目标IP地址是谁的,由于网络中不存在该目标IP地址,所以没有设备应答客户端的arp请求。
      • 由于客户端无法拿到目标设备的MAC,这样就没办法组装MAC头的信息,所以SYN报文无法发送出去。
    • 目标IP地址和客户端的IP地址不在同一个局域网(网络号不同)情况。
      • 客户端会先将SYN报文发给路由器,然后路由器会继续转发。
      • 由于目标IP地址是不存在的,该SYN报文会在网络中消亡,因此客户端是不会收到对SYN报文的确认报文的,接着客户端会触发超时重传,重传SYN报文,直到重传的次数达到最大次数后,客户端的连接就会被释放。
  2. 客户端连接一个存在的IP地址但是端口不存在,会怎样

    客户端连接的目标IP地址是存在的,那么SYN报文就能正确的抵达到目标设备。目标设备收到SYN报文后,发现端口号并没有被进程监听,这时候目标设备的内核就会回RST报文。

  3. 一个IP的服务端监听了一个端口,它的TCP的最大连接数是多少?

    服务端通常固定在某个本地端口上监听,等待客户端的连接请求。因此,客户端IP和端口是可变的,其理论值计算公式如下:客户端IP数 * 客户端端口数。

    服务端最大并发TCP连接数远不能达到理论上限,会受以下因素影响:

    • 文件描述符限制,每个TCP连接都是一个文件,如果文件描述符被占满了,会发生Too many open files。Linux对可打开的文件描述符的数量分别作了三个方面的限制:
      系统级:当前系统可打开的最大数量,通过 cat /proc/sys/fs/file-max 查看;
      用户级:指定用户可打开的最大数量,通过 cat /etc/security/limits.conf 查看;
      进程级:单个进程可打开的最大数量,通过 cat /proc/sys/fs/nr_open 查看;
    • 内存限制,每个TCP连接都要占用一定内存,操作系统的内存是有限的,如果内存资源被占满后,会发生OOM。
  4. TCP和UDP可以使用同一个端口吗

    在数据链路层中,通过MAC地址来寻找局域网中的主机。
    在网际层中,通过IP地址来寻找网络中互连的主机或路由器。
    在传输层中,需要通过端口进行寻址,来识别同一计算机中同时通信的不同应用程序。
    所以,传输层的「端口号」的作用,是为了区分同一个主机上不同应用程序的数据包。

    传输层有两个传输协议分别是TCP和UDP,在内核中是两个完全独立的软件模块。
    当主机收到数据包后,可以在IP包头的 “协议号” 字段知道该数据包是TCP/UDP,所以可以根据这个信息确定送给哪个模块(TCP/UDP)处理,送给TCP/UDP模块的报文根据 “端口号” 确定送给哪个应用程序处理。
    因此,TCP/UDP各自的端口号也相互独立,如TCP有一个80号端口,UDP也可以有一个80号端口,二者并不冲突。

  5. 客户端的端口可以重复使用吗?

    只要客户端连接的不是相同的服务器,内核是允许端口重复使用的。TCP连接由四元组(源IP地址,源端口,目的IP地址,目的端口)唯一确认的,四元组其中任何一个元素改变,就表示不同的TCP连接。

    假如客户使用端口1与服务器A建立了连接,客户端也可以使用端口1与服务器B建立连接,即使客户端的端口号相同,但因四元组信息发生变化,并不会导致连接冲突。

  6. 多个TCP服务进程可以绑定同一个端口吗?

    若多个TCP服务进程同时绑定相同的IP地址和端口,那么执行bind()时候就会报错“Addressalreadyinuse”;若TCP服务进程只是绑定相同的端口,但绑定的IP地址不同,那么则不会报错。

IP层会分片,为什么TCP层还需要MSS呢

在这里插入图片描述

MTU:一个网络包的最大长度,以太网中一般为1500字节;
MSS:除去IP和TCP头部之后,一个网络包所能容纳的TCP数据的最大长度;

如果在TCP的整个报文(头部+数据)交给IP层进行分片,而IP层本身没有超时重传机制,它由传输层的TCP来负责超时和重传

当某一个IP分片丢失后,接收方的IP层就无法组装成一个完整的TCP报文(头部+数据),也就无法将数据报文送到TCP层,所以接收方不会响应ACK给发送方,因为发送方迟迟收不到ACK确认报文,所以会触发超时重传,就会重发 “整个TCP报文(头部+数据)” 。因此,由IP层进行分片传输,是非常没有效率的

所以,为了达到最佳的传输效能TCP协议在建立连接的时候通常要协商双方的MSS值,当TCP层发现数据超过MSS时,则就先会进行分片,当然由它形成的IP包的长度也就不会大于MTU,自然也就不用IP分片了。

经过TCP层分片后,如果一个TCP分片丢失后,进行重发时也是以MSS为单位,而不用重传所有的分片,大大增加了重传的效率。

HTTP3放弃TCP:

  • TCP存在队头阻塞问题———TCP发送出去的数据,都是需要按序确认的,只有在数据都被按顺序确认完后,发送窗口才会往前滑动。如果某个数据报文丢失或者其对应的ACK报文在网络中丢失,会导致发送方无法移动发送窗口,这时就无法再发送新的数据。如客户端发送了第5~9字节的数据,但是第5字节的ACK确认报文在网络中丢失了,那么即使客户端收到第6~9字节的ACK确认报文,发送窗口也不会往前移动。此时的第5字节相当于 “队头” ,因为没有收到 “队头” 的ACK确认报文,导致发送窗口无法往前移动,此时发送方就无法继续发送后面的数据,相当于按下了发送行为的暂停键,这就是发送窗口的队头阻塞问题。
  • 接收窗口的队头阻塞————接收窗口收到的数据不是有序的,比如收到第33~40字节的数据,由于第32字节数据没有收到,接收窗口无法向前滑动,那么即使先收到第33~40字节的数据,这些数据也无法被应用层读取的。

两个问题的原因都是因为TCP必须按序处理数据,也就是TCP层为了保证数据的有序性,只有在处理完有序的数据后,滑动窗口才能往前滑动,否则就停留。

NAPT(Network Address Port Transfer , 网络地址端口转换 )工作原理。

  • 发送流程
    在这里插入图片描述
    发送端IP地址填的就是192.168.30.5,接收端IP地址就是30.30.30.30。将数据包发到NAT路由器中。

    此时NAT路由器会将IP数据包里的源IP地址和端口号修改一下,从192.168.30.5:5000改写成20.20.20.20:6000。并且还会在NAT路由器内部留下一条192.168.30.5:5000->20.20.20.20:6000的映射记录。之后数据包经过公网里各个路由器的转发,发到了接收端30.30.30.30:3000,到这里发送流程结束。

  • 接收流程
    在这里插入图片描述
    接收端响应时,就会在数据包里填入发送端地址是30.30.30.30:3000,将接收端是20.20.20.20:6000,发往NAT路由器。NAT路由器发现下自己之前留下过这么一条192.168.30.5:5000->20.20.20.20:6000的记录,就会将这个数据包的目的IP地址和端口修改一下,变回原来的192.168.30.5:5000。之后将其转发给你的电脑上。

ping基于ICMP协议,ICMP协议报文里并不带端口信息

  • 事实上针对ICMP协议,NAT路由器做了特殊处理。ping报文头里有个Identifier的信息,它其实指的是放出ping命令的进程id。
  • 对NAT路由器来说,这个Identifier的作用就跟端口一样,所以可以ping通公网机器并收到回包。

内网穿透
使用了NAT上网的话,前提得内网机器主动请求公网IP,这样NAT才能将内网的IP端口转成外网IP端口。

反过来公网的机器想主动请求内网机器,就会被拦在NAT路由器上,此时由于NAT路由器并没有任何相关的IP端口的映射记录,因此也就不会转发数据给内网里的任何一台机器。

我们就在公网上加一台服务器x,并暴露一个访问域名,再让内网的服务主动连接服务器x,这样NAT路由器上就有对应的映射关系。接着,所有人都去访问服务器x,服务器x将数据转发给内网机器,再原路返回响应,这样数据就都通了。这就是所谓的内网穿透

上面提到的服务器x,也不需要自己去搭,已经有很多现成的方案,比如花某壳。
在这里插入图片描述

常用网络命令

  • route

  • nc 工具

  • netstat 命令

  • IP分配

    1. 手动在电脑里配IP地址还需要配上子网掩码和路由器的地址。
    2. DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)。在联网之后可以自动获取到本机需要的IP地址,子网掩码还有路由器地址。
# 在命令行里执行下面的命令,可以强行让电脑的en0网卡重新走一遍DHCP流程。
sudo ipconfig set en0 DHCP# 在 Linux下,TCP 的连接状态可以通过 netstat -napt 命令查看。
netstat -tunlp  # 用于显示所有TCP和UDP端口的监听状态。
lsof -i :端口号  # 用于显示指定端口的相关信息。
# 查看哪个端口被哪个进程占用,可以通过 lsof 或者 netstate 命令查看,比如查看 80 端口。
lsof -i :80
netstat -napt | grep 80# 查看close_wait状态的连接
netstat -napt  | grep close_wait# sort -k3 -nr用于按第三列(请求耗时)进行倒序排序。
# -k3表示按第三列排序,-n表示按数字排序,-r表示倒序排序。
# 然后,使用head -n 10来获取排序后的前10行,即耗时最高的10条记录。
sort -k3 -nr 日志文件 | head -n 10# telnet命令用于建立与远程主机的Telnet连接,并可以使用telnet命令测试特定端口的可访问性。
telnet IP地址 端口号 # 用于测试指定IP地址上的指定端口是否可访问。
# 如果能够建立连接,则表示端口通畅;如果连接失败或超时,则表示端口不可访问。# nc命令(也称为netcat)是一个网络工具,可以用于创建各种类型的网络连接,包括测试端口的可访问性。
nc -zv IP地址 端口号 # 用于测试指定IP地址上的指定端口是否可访问。
#如果能够成功连接,则表示端口通畅;如果连接失败或拒绝,则表示端口不可访问。

常用协议

ARP (Address Resolution Protocol) - Internet物理地址和IP地址转换
ICMP - Internet控制报文协议,处于网络层(IP层)

ARQ - 自动重传请求(Automatic Repeat-reQuest),是 OSI 模型中数据链路层和传输层的错误纠正协议之一。它通过使用确认和超时这两个机制,在不可靠服务的基础上实现可靠的信息传输。

ICMP - Internet Control Message Protocol - Internet控制消息协议。

墙裂推荐网络学习参考

图解网络介绍

相关文章:

网络协议常见问题

网络协议常见问题 OSI(Open Systems Interconnection)模型OSI 封装 TCP/IP协议栈IP数据报的报头TCP头格式UDP头格式TCP (3-way shake)三次握手建立连接:为什么三次握手才可以初始化 Socket、序列号和窗口大小并建立 TCP 连接。每次建立TCP连接…...

人工智能的迷惑行为

目录 前言1 人工智能的“幽默”瞬间1.1 语义误解1.2 逻辑错误 2 技术原理探究2.1 算法设计缺陷2.2 数据处理不当 3 社会影响分析3.1 信任度下降3.2 技术担忧 结语 前言 随着人工智能技术的迅猛发展,各类AI大模型如ChatGPT、文心一言、通义千问等纷纷登场&#xff0…...

XR技术:短剧制作的全新纪元

在数字技术的浪潮中,XR(扩展现实)技术以其独特的魅力,正在为短剧制作带来革命性的突破。这种融合了虚拟现实、增强现实和混合现实等先进技术的创新工具,正逐渐改变着短剧制作的传统模式,引领着短剧艺术走向…...

安卓 OpenGL ES 学习笔记

文章目录 OpenGL 学习笔记OpenGL 是什么?OpenGL ES是什么?怎么用?hello world如何实现动画效果 参考文章 OpenGL 学习笔记 OpenGL 是什么? OpenGL(Open Graphics Library)是一个跨平台的图形编程接口&…...

git分布式管理-头歌实验冲突处理、忽略文件

一、解决冲突 任务描述 在团队协作开发过程中,可能你和团队中的其他成员,都修改了某个文件的某一部分内容,且其他成员已将该修改推送到了远程仓库。这样当你需要合并他的代码的时候,可能就会在内容上出现冲突,这个时候…...

【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现

🌞前言 这里我们会实现一个项目:在linux操作系统下基于OpenCV和Socket的人脸识别系统。 目录 🌞前言 🌞一、项目介绍 🌞二、项目分工 🌞三、项目难题 🌞四、实现细节 🌼4.1 关…...

零售EDI:劳氏 Lowe‘s EDI项目案例

通过 EDI,企业与Lowes之间可以直接交换各种商业文档,如订单、发票、收据等,从而实现信息的实时交换,提高了供应链的效率和准确性。在现代供应链管理中,EDI 已经成为了不可或缺的重要工具。 作为一家拥有多条业务线的企…...

为什么不用 index 做 key?

“在 Vue 中,我们在使用 v-for 渲染列表的时候,为什么要绑定一个 key?能不能用 index 做 key?” 在聊这个问题之前我们还得需要知道 Vue 是如何操作 DOM 结构的。 虚拟DOM 我们知道,Vue 不可以直接操作 DOM 结构&am…...

Linux虚拟机安装Redis

官网下载压缩包:官网链接,然后将对应的tar.gz压缩包放入虚拟机下的/opt目录下。由于redis是C语言开发的,因此需要安装gcc编译器来编译代码,我们下载的压缩包里面是源代码,需要编译。通过yum install gcc指令下载C语言的…...

网络安全: Kali Linux 进行 SSH 渗透与防御

目录 一、实验 1.环境 2.nmap扫描目标主机 3.Kali Linux 进行 SSH 渗透 3.Kali Linux 进行 SSH 防御 二、问题 1.SSH有哪些安全配置 一、实验 1.环境 (1)主机 表1 主机 系统版本IP备注Kali Linux2022.4 192.168.204.154(动态&…...

近年来文本检测相关工作梳理

引言 场景文本检测任务,一直以来是OCR整个任务中最为重要的一环。虽然有一些相关工作是端对端OCR工作的,但是从工业界来看,相关落地应用较为困难。因此,两阶段的OCR方案一直是优先考虑的。 在两阶段中(文本检测文本识…...

文件系统事件监听

文件系统事件和网络IO事件一样,也可以通过epoll或者IOCP 事件管理器统一调度,当所监控的文件或文件夹发生了增删改的事件时,就会触发事件回调,进行事件处理。很常见的应用,如配置文件立即生效功能,就可以通…...

探秘HTTPS:如何通过SSL/TLS保证网络通信安全

目录 引言 详解HTTPS加密实现机制 SSL/TLS工作原理 结论 引言 随着网络安全威胁的日益增加,HTTPS通过SSL(Secure Sockets Layer)和TLS(Transport Layer Security)协议提供的加密技术变得至关重要。这些技术保证了用…...

Java算法之动态规划

Java算法之动态规划 前言 ​ 最近这一段时间一直在刷算法题,基本上一有时间就会做一两道,这两天做了几道动态规划的问题,动态规划之前一直是我比较头疼的一个问题,感觉好复杂,一遇到这样的问题就想跳过,昨…...

C++从零开始的打怪升级之路(day47)

这是关于一个普通双非本科大一学生的C的学习记录贴 在此前,我学了一点点C语言还有简单的数据结构,如果有小伙伴想和我一起学习的,可以私信我交流分享学习资料 那么开启正题 今天分享的是关于set和map的知识点 1.关联式容器 在前面&#…...

香橙派AIpro开发板开箱测评

2023年12月,香橙派联合华为发布了基于昇腾的Orange Pi AIpro开发板,提供8/20TOPS澎湃算力,能覆盖生态开发板者的主流应用场景,让用户实践各种创新场景,并为其提供配套的软硬件。香橙派AIpro开发板一经发布便吸引了众多…...

ISP基础概述

原文来自ISP 和摄像头基本知识 本文主要介绍ISP,以供读者能够理解该技术的定义、原理、应用。 🎬个人简介:一个全栈工程师的升级之路! 📋个人专栏:计算机杂记 🎀CSDN主页 发狂的小花 &#x1f3…...

C++第一弹---C++入门(上)

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】 【C详解】 C入门 1、C关键字(C98) 2、命名空间 2.1、命名空间定义 2.2、命名空间使用 3、C输入&输出 4、缺省参数 4.1、缺省参数概念 4.2、缺省参…...

VScode格式化快捷键

vscode格式化代码快捷键 如何使用快捷键格式化代码。使用Java的格式去设置,发现不起作用。 在这里记录一下: 在Windows中,vscode格式化代码快捷键是“ShiftAltF”; 在Mac中,vscode格式化代码快捷键是“ShiftOption…...

HCIP---IS-IS协议

文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据总结 一.IS-IS协议概述 IS-IS是一种基于链路状态的内部网关协议(IGP),它使用最短路径优先算法(SPF或Dijkstra)进行路由计算。这种协议在自治…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

AspectJ 在 Android 中的完整使用指南

一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...