网络与部署笔记 | 青训营

本文旨在记录网络与部署课程笔记,学习了计算机网络相关知识,对TCP协议等知识有了进一步学习,对网络接入协议、网络传输协议、网络优化、网络稳定等知识有了初步了解,并在课后进行了UDP socket编程的学习。

课前思考

这一部分主要是对老师给的学习资料里的课前思考问题进行资料查找和提前学习,这里列出两个问题的解答。

TCP 的拥塞算法有哪些?

TCP的一些拥塞控制算法用于在网络拥塞时调整数据传输的速率,以避免网络拥塞进一步加剧。以下是一些常见的TCP拥塞控制算法:

  1. 慢启动(Slow Start):TCP连接刚建立时,发送方会发送少量数据,然后根据每次接收到的确认来逐渐增加发送窗口大小,从而逐渐加速数据传输速率。这有助于避免在连接建立时就过载网络。

  2. 拥塞避免(Congestion Avoidance):一旦发送方感知到网络开始拥塞,它会切换到拥塞避免状态。在这个状态下,发送方将逐渐增加发送窗口的大小,但增加的速率相对较慢,以减少进一步加重网络拥塞的可能性。

  3. 快重传(Fast Retransmit):当接收方接收到失序的数据段时,它会立即向发送方发送一个重复的确认。发送方在连续收到相同的确认时,会认为某个数据段丢失并立即重传该数据段,而不是等待超时。

  4. 快恢复(Fast Recovery):与快重传结合使用,发送方在执行快重传后,不会像慢启动那样减小发送窗口的大小。相反,它会将发送窗口减半,然后继续进行拥塞避免状态。

  5. TCP Reno算法:这是一种结合了快重传和快恢复的拥塞控制算法。它使用重复确认来快速检测丢失的数据段,并使用快恢复来减少发送窗口大小,以避免网络拥塞。

  6. TCP New Reno算法:这是对TCP Reno的改进,它在处理多个丢失数据段时更加有效,能够更快地恢复到正常的数据传输速率。

  7. TCP Cubic算法:Cubic是一种基于TCP Tahoe和TCP Reno的算法,它具有更加平滑的拥塞窗口增长曲线,能够更好地适应网络的拥塞情况。

  8. TCP Vegas算法:Vegas使用延迟作为网络拥塞的指标,通过测量数据包的往返时间来调整发送窗口大小,以避免过早进入拥塞状态。

  9. TCP BBR算法:BBR(Bottleneck Bandwidth and Round-trip propagation time)是谷歌提出的拥塞控制算法,它通过测量网络的瓶颈带宽和往返传播时间来决定数据传输速率,以实现更高的带宽利用率。

这些算法都旨在保持网络的稳定性,避免拥塞,以及在拥塞情况下调整数据传输的速率。不同的算法适用于不同的网络环境和拥塞情况。这些拥塞控制算法对于网络性能的优化和故障排除非常重要,但我对于这些算法仅限于了解的阶段,后续应用阶段还需要深入研究。

了解 Linux kernel 的网络包从收到包到用户态,从用户态发包到网卡整个流程。

处理Linux内核网络数据包的完整流程涉及多个阶段和组件,包括数据包从收到到用户态,以及从用户态发送到网卡的过程:

  1. 数据包接收阶段

    1.1. 网卡硬件接收:数据包首先通过物理网卡接口被接收到。网卡硬件会将数据包存储在接收缓冲区中,并产生中断通知内核。

    1.2. 中断处理程序:内核中的中断处理程序会响应网卡的中断,负责将数据包从网卡缓冲区复制到内核内存。

    1.3. 网络协议栈处理:内核会对接收到的数据包进行网络协议栈处理,这包括根据协议类型(如IPv4、IPv6、ARP等)进行路由选择、解析IP头部、检查TCP/UDP端口等。

    1.4. 套接字接收缓冲区:内核会将数据包复制到相应的套接字接收缓冲区,该缓冲区与正在等待接收数据的用户态应用程序相关联。

  2. 用户态接收数据包

    2.1. 用户态应用程序:用户态的应用程序可以使用套接字进行数据包的接收操作。

    2.2. 系统调用:应用程序会通过系统调用(如recv)通知内核要进行数据包的接收。内核会将数据包从套接字接收缓冲区复制到用户态应用程序的内存空间。

  3. 用户态发送数据包

    3.1. 用户态应用程序:用户态的应用程序可以使用套接字进行数据包的发送操作。

    3.2. 系统调用:应用程序会通过系统调用(如send)通知内核要进行数据包的发送。

    3.3. 套接字发送缓冲区:内核会将数据包复制到相应的套接字发送缓冲区,然后调用网络协议栈将数据包发送到目标IP地址。

  4. 数据包发送阶段

    4.1. 网络协议栈处理:内核会对要发送的数据包进行网络协议栈处理,包括构建IP头部、TCP/UDP头部等。

    4.2. 路由选择:内核会确定发送数据包的下一跳路由。

    4.3. 网卡驱动发送:数据包通过网卡驱动发送到物理网络。网卡驱动将数据包放入网卡发送队列中。

    4.4. 网卡硬件发送:网卡硬件会将数据包从发送队列中取出,并发送到网络。

整个过程涉及许多细节和复杂的操作,包括协议解析、路由选择、内核空间和用户空间的数据拷贝等。不同的内核版本和配置可能会有微小的差异,但上述描述涵盖了整个数据包的接收和发送过程的基本步骤,实际的内核网络处理涉及更多的细节和优化。

课中

网络接入

- 路由发包原理:

-   同网段:配置网段即可默认添加静态路由。获取对端MAC直接发包 
-   跨网段:配置网关路由。获取网关MAC地址发包
-   动态路由:BGP/OSPF等,路由表在动态变化
-   路由是网状的,不一定是对称的

- ARP协议

-   ARP广播/应答:协议原理
-   免费ARP:主动广播告知MAC地址
-   ARP代理:虚拟网络/伪造MAC地址

- IP协议

-   IPv4:互联网终端节点的唯一标识
-   IPv6:不仅仅是IP地址长度的增加

- NAT

-   NAT上网:家用路由器
-   NAT出网:机房内网主机上外网
-   NAT原理:注意不仅仅是源地址变换,源端口/校验和/SEQ等都会变化

网络传输

- 数据包:

数据包是网络中传输的基本单位。它是将数据按照一定的格式封装起来,以便在网络中传递。数据包通常包含了数据本身以及一些用于路由、传输控制和错误检测的元信息。

数据包的结构通常包括以下几个部分:

  1. 头部(Header) :头部是数据包的开头部分,包含了一些控制信息,如源地址、目标地址、协议类型、序列号等。这些信息有助于在网络中正确路由和传递数据。
  2. 数据(Payload) :数据是实际要传输的内容,可以是文本、图像、音频、视频等各种类型的数据。
  3. 尾部(Footer 或 Trailer) :尾部包含了一些额外的信息,如校验和(Checksum)或纠错码,用于在接收端检测数据传输中可能出现的错误。

数据包的大小可以根据不同的网络协议和应用需求而有所不同。在互联网中,常见的数据包格式包括以太网帧、IP数据包(IPv4或IPv6)、TCP段、UDP数据报等,每个层级的协议都会在数据包中添加适当的头部信息,以使数据能够在网络中被正确处理和传递。

数据包的使用让网络通信变得灵活且可扩展,因为它允许数据被分割成小块,然后在网络中进行传输,同时也方便了不同协议的协同工作。 本质上是一段内存,里面存储的内存是有序的,一般是按照TCP/IP的多层协议去封装。拆包/封包都是按照协议去写内存/读内存,如下图。

- DNS递归迭代

递归查询是指客户端向本地DNS服务器发送一个查询请求,本地DNS服务器会负责查询整个DNS层级结构,直到找到所需的域名解析结果。本地DNS服务器在查询过程中会向根域名服务器、顶级域名服务器和权威域名服务器递归地请求信息,直到获取到最终的IP地址或错误响应。然后本地DNS服务器将结果返回给客户端。

递归查询的过程中,本地DNS服务器充当了一个中间人的角色,处理了所有的递归步骤,从而减轻了客户端的工作负担。

迭代查询是指客户端向本地DNS服务器发送一个查询请求,本地DNS服务器会将查询请求逐级传递给不同的DNS服务器,每个DNS服务器都只负责返回一个指向下一个DNS服务器的指针,直到找到所需的域名解析结果。在迭代查询中,每个DNS服务器只返回自己所知道的信息,而不负责继续向下递归查询。

客户端需要连续向下迭代查询直到获得所需的IP地址,然后将结果返回给本地DNS服务器。

- UDP

-   协议简单
-   需要考虑可靠性的场景使用复杂
  • TCP

TCP提供了可靠的、面向连接的数据传输,适用于对数据完整性要求较高的场景;而UDP是一种轻量级的、无连接的协议,适用于实时性要求高、对数据丢失较不敏感的场景。

-   三次握手:确认传输的序列号/MSS/Option字段,建立连接

在建立TCP连接时,客户端和服务器之间需要进行三次握手。客户端首先发送一个请求连接的报文,服务器回复确认并表示准备好连接,最后客户端再次回复确认,建立连接。这确保了双方都愿意通信,并交换了初始序列号。

-   TCP连接:是一个虚拟的概念,本质上两倍维持一段内存,记录连接状态,就是session

TCP连接是一个虚拟的概念,用于表示通信双方之间的数据传输。连接状态在内存中维护,包含了通信双方的IP地址、端口、序列号、窗口大小等信息,以及当前连接的状态(建立、关闭等)。

-   TCP传输:理解sequence number/acknowledge number

TCP使用序列号(Sequence Number)和确认号(Acknowledgment Number)来保证数据传输的可靠性和顺序性。序列号表示发送方发送的字节流中的第一个字节的序号,而确认号表示接收方期望接收的下一个字节的序号。

-   丢包重传:理解丢包怎么感知并重传,理解快速重传发生在什么时候

如果发送方发送的数据包在传输过程中丢失,接收方可以通过确认号告知发送方它期望接收哪个序列号的数据。发送方根据这个信息进行丢包的重传。

快速重传:当接收方收到乱序的数据包时,它会立即向发送方发送一个重复的确认,指示丢失的数据包。发送方在连续接收到相同的确认时,可以认为某个数据包丢失,并快速地进行重传,从而避免等待超时。

-   滑动窗口:课后自学

滑动窗口是TCP用于流量控制和拥塞控制的机制之一。它表示发送方可以发送的字节流范围,接收方通过调整窗口大小来控制发送方的数据流量。

-   流量控制:课后自学

流量控制是TCP通过滑动窗口机制来控制发送方发送数据的速率,以适应接收方的处理能力,防止过多的数据堆积在接收方,导致丢包或延迟。

- HTTP

-   HTTP比TCP好在哪里:方便
-   HTTP1.1的优化:长连接是重点

- HTTPS

-   HTTPS的产生背景:加密/可靠/防劫持
-   SSL/TLS握手:非对称加密/对称加密

在这部分,主要了解了网络传输的步骤,涉及的一些协议以及这些协议的一些使用场景,各自的优劣势,使我对网络传输有了初步了解。

网络提速

- HTTP2.0

-   多路复用:依然有队头阻塞

多路复用(Multiplexing) :HTTP/2使用多路复用来解决“队头阻塞”问题。在传统的HTTP/1.x中,浏览器和服务器之间的请求和响应必须一个接一个地进行。这意味着如果一个请求阻塞了,后续的请求也会受到影响,导致效率降低。

HTTP/2引入了多路复用的概念,允许在单个连接上同时传输多个请求和响应。每个请求和响应都被分割成帧(Frame),然后通过帧的优先级进行调度,以确保高优先级的帧优先处理。这大大提升了网络连接的利用率,减少了等待时间。

队头阻塞(Head-of-Line Blocking) :虽然多路复用可以同时处理多个请求,但如果其中一个请求阻塞了(比如一个大文件的下载),它后面的请求也会被阻塞,因为HTTP/2要保证响应的顺序性。这被称为队头阻塞,虽然它的影响相对于HTTP/1.x的影响要小,但仍然可能会影响效率。

为了减轻队头阻塞的问题,HTTP/2引入了“流优先级”机制,可以给不同的请求分配不同的优先级,但这需要在实际应用中进行适当的配置和调整。

总的来说,HTTP/2通过引入多路复用等特性,极大地改善了原始HTTP/1.x的性能瓶颈。但在应用中,仍需要考虑队头阻塞等问题,并根据具体场景和需求进行合适的优化和配置。

- QUIC

QUIC(Quick UDP Internet Connections)是一种由Google推出的基于UDP的传输协议,旨在提供更快的网络连接和传输效率,以解决TCP存在的一些问题。

  • 为什么在用户态实现?

QUIC协议在用户态实现的主要原因之一是为了快速推出并迭代更新。在内核中实现新的网络协议需要较长的时间和更多的验证,而用户态实现可以更快地进行开发、测试和更新。这种方式使得QUIC协议能够更迅速地适应网络环境的变化和需求,而不受内核更新频率的限制。

  • 为什么用UDP?

使用UDP作为传输层协议的主要原因之一是为了避免TCP的队头阻塞问题。TCP中的队头阻塞可能会导致数据传输的延迟,特别是在高丢包率或不稳定网络环境下。QUIC使用UDP作为底层传输协议,可以更灵活地控制数据的发送和接收,从而减轻了队头阻塞的问题。

此外,使用UDP还有其他优势,如允许更灵活的数据分割、更低的连接建立时间和更好的连接迁移支持(比如从移动网络切换到Wi-Fi)。

课后

课后作业1- UDP socket 实现 ack,感知丢包重传

package main

import (
	"fmt"
	"net"
	"time"
)

const serverAddr = "127.0.0.1:12345"

func main() {
	conn, err := net.Dial("udp", serverAddr)
	if err != nil {
		fmt.Println("Error connecting to server:", err)
		return
	}
	defer conn.Close()

	message := []byte("Hello, server!")

	for {
		// 发送数据
		_, err := conn.Write(message)
		if err != nil {
			fmt.Println("Error sending data:", err)
			return
		}

		// 设置接收超时
		conn.SetReadDeadline(time.Now().Add(time.Second))
		buffer := make([]byte, 1024)
		_, err = conn.Read(buffer)

		if err == nil {
			fmt.Println("Received ACK from server:", string(buffer))
			break
		} else {
			fmt.Println("Timeout waiting for ACK, retransmitting...")
		}
	}

	fmt.Println("Data transmission successful!")
}

客户端发送数据,然后等待服务器的ACK确认。如果在超时时间内未收到ACK,客户端会认为数据包丢失,并进行重传。

为了实现更高效的重传机制,可以考虑实现选择性重传、快速重传等技术。此外,实现不阻塞只传递丢掉的中间段可能需要更复杂的逻辑,例如使用滑动窗口来管理已发送的数据段。

总结

在这节课中,我通过抖音接入网络的案例,学习了计算机网络相关知识,对TCP协议等知识有了进一步学习,对网络接入协议、网络传输协议、网络优化、网络稳定等知识有了初步了解,并在课后进行了UDP socket编程的学习。

下一篇进行网络接入动手实践。

全部评论

相关推荐

头像
10-16 09:58
已编辑
门头沟学院 Java
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务