目录

计算机网络

目录

概述

互联网服务提供商 ISP

  • 客户-服务器(C/S):客户是服务的请求方,服务器是服务的提供方。

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/167228b3fa90b50063dee6ac4ac7cdc7.png

  • 对等(P2P):不区分客户和服务器。

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/a1ca5d1396168515e38608f4a4f75bff.png

分组交换:每个分组都有首部和尾部,包含了源地址和目的地址等控制信息,在同一个传输线路上同时传输多个分组互相不会影响,因此在同一条传输线路上允许同时传输多个分组,也就是说分组交换不需要占用传输线路。

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/93f7a785132067fcfa6d94bfb65002b6.png

  • 应用层 :为特定应用程序提供数据传输服务,例如 HTTP、DNS 等协议。数据单位为报文
  • 传输层(进程) :为进程提供通用数据传输服务。由于应用层协议很多,定义通用的传输层协议就可以支持不断增多的应用层协议。运输层包括两种协议:传输控制协议 TCP,提供面向连接、可靠的数据传输服务,数据单位为报文段;用户数据报协议 UDP,提供无连接、尽最大努力的数据传输服务,数据单位为用户数据报。TCP 主要提供完整性服务,UDP 主要提供及时性服务。
  • 网络层(主机ip) :为主机提供数据传输服务。而传输层协议是为主机中的进程提供数据传输服务。网络层把传输层传递下来的报文段或者用户数据报封装成分组
  • 数据链路层(mac地址) :网络层针对的还是主机之间的数据传输服务,而主机之间可以有很多链路,链路层协议就是为同一链路的主机提供数据传输服务。数据链路层把网络层传下来的分组封装成帧
  • 物理层 :考虑的是怎样在传输媒体上传输数据比特流,而不是指具体的传输媒体。物理层的作用是尽可能屏蔽传输媒体和通信手段的差异,使数据链路层感觉不到这些差异。

五层协议的复杂版,多了表示层和会话层,

它只有四层,相当于五层协议中数据链路层和物理层(最下面两层)合并为网络接口层。

TCP/IP 体系结构不严格遵循 OSI 分层概念,应用层可能会直接使用 IP 层或者网络接口层。

在向下的过程中,需要添加下层协议所需要的首部或者尾部,而在向上的过程中不断拆开首部和尾部。(越往下,越封装一层

物理层

根据信息在传输线上的传送方向,分为以下三种通信方式:

  • 单工通信:单向传输
  • 半双工通信:双向交替传输
  • 全双工通信:双向同时传输

链路层

  • 数据帧的传输: 链路层负责将网络层的数据包封装成数据帧,以便在物理介质上进行传输。
  • 介质访问控制: 链路层通过介质访问控制(MAC)协议来管理共享介质上的数据传输
  • 目前数据链路层广泛使用了循环冗余检验(CRC)来检查比特差错。
  1. 广播信道: 允许一对多通信,一个节点发送的数据能够被广播信道上所有的节点接收到。需要专门的控制方法进行协调,避免碰撞。常见的控制方法包括信道复用技术和CSMA/CD协议。
  2. 点对点信道: 适用于一对一通信,不会发生碰撞,使用简单的PPP协议进行控制。
  1. 频分复用(FDM): 将通信频段划分为多个不重叠的子频段,每个用户或信道占据一个特定的频段进行通信。常见于无线电通信和有线电视系统。

  2. 时分复用(TDM): 将通信时间段划分为若干个固定长度的时隙,不同用户或信道在不同时隙内进行通信。常见于数字通信系统和电话网络。

  3. 码分复用(CDM):数据通过不同的编码方案进行调制,然后同时发送到通信媒介上。接收端使用相应的解码方案来提取目标数据。常见于CDMA(Code Division Multiple Access)系统。

  4. 统计时分复用

    是对时分复用的一种改进,不固定每个用户在时分复用帧中的位置,只要有数据就集中起来组成统计时分复用帧然后发送。

  5. 统计时分复用

    是对时分复用的一种改进,不固定每个用户在时分复用帧中的位置,只要有数据就集中起来组成统计时分复用帧然后发送。

这些信道复用技术使得多个用户能够共享同一通信媒介,从而实现了高效的通信

CSMA/CD 表示载波监听多点接入 / 碰撞检测。

  • 多点接入 :说明这是总线型网络,许多主机以多点的方式连接到总线上。
  • 载波监听 :每个主机都必须不停地监听信道。在发送前,如果监听到信道正在使用,就必须等待。
  • 碰撞检测 :在发送中,如果监听到信道已有其它主机正在发送数据,就表示发生了碰撞。虽然每个主机在发送数据之前都已经监听到信道为空闲,但是由于电磁波的传播时延的存在,还是有可能会发生碰撞。

互联网用户通常需要连接到某个 ISP 之后才能接入到互联网,PPP 协议是用户计算机和 ISP 进行通信时所使用的数据链路层协议。

MAC 地址是链路层地址,长度为 6 字节(48 位,共2*6个字母数字表示),用于唯一标识网络适配器(网卡)。(可以有虚拟网卡)

交换机具有自学习能力,学习的是交换表的内容,交换表中存储着 MAC 地址到接口的映射。

**交换机通过在数据帧中标记 VLAN ID 来实现逻辑上的隔离,**使得不同 VLAN 的设备能够彼此通信,但在逻辑上却处于不同的虚拟网络中。

虚拟局域网可以建立与物理位置无关的逻辑组,只有在同一个虚拟局域网中的成员才会收到链路层广播信息。

当一个数据帧从一个VLAN发送到另一个VLAN时,交换机会在数据帧的头部添加一个VLAN标签,该标签包含了VLAN ID。这样,接收端的交换机就可以根据VLAN ID将数据帧转发到正确的VLAN。

网络层

网络层是整个互联网的核心,因此应当让网络层尽可能简单。网络层向上只提供简单灵活的、无连接的、尽最大努力交互的数据报服务。

这一层的链接用的IP地址

无分类编址 CIDR 消除了传统 A 类、B 类和 C 类地址以及划分子网的概念,使用网络前缀和主机号来对 IP 地址进行编码,网络前缀的长度可以根据需要变化。

IP 地址 ::= {< 网络前缀号 >, < 主机号 >}

CIDR 的记法上采用在 IP 地址后面加上网络前缀长度的方法,例如 128.14.35.7/20 表示前 20 位为网络前缀。

网络层实现主机之间的通信,而链路层实现具体每段链路之间的通信。因此在通信过程中,IP 数据报的源地址和目的地址始终不变,而 MAC 地址随着链路的改变而改变

为了应对MAC地址变换,ARP 实现由 IP 地址得到 MAC 地址。

每个主机都有一个 ARP 高速缓存,里面有本局域网上的各主机和路由器的 IP 地址到 MAC 地址的映射表。arp -a命令可以查看该映射表(向网络发送一个ARP请求的广播包)

如果主机 A 知道主机 B 的 IP 地址,但是 ARP 高速缓存中没有该 IP 地址到 MAC 地址的映射,此时主机 A 通过广播的方式发送 ARP 请求分组,主机 B 收到该请求后会发送 ARP 响应分组给主机 A 告知其 MAC 地址,随后主机 A 向其高速缓存中写入主机 B 的 IP 地址到 MAC 地址的映射。(简单来说,就是通过arp请求获取到指定ip的mac地址

ICMP(Internet Control Message Protocol)是一种网络协议,用于在IP网络上发送控制消息。它通常用于诊断网络故障、执行网络管理任务和提供错误报告。ICMP消息通常被内置在IP数据包中,以便在网络中传输。

Ping 是 ICMP 的一个重要应用,主要用来测试两台主机之间的连通性。

Ping 的原理是通过向目的主机发送 ICMP Echo 请求报文,目的主机收到之后会发送 Echo 回答报文。Ping 会根据时间和成功响应的次数估算出数据包往返时间以及丢包率

如果在交换机禁止ICMP嗅探会怎么样:无法使用ICMP工具(例如ping)来测试网络设备之间的连通性和延迟。

(用于查看数据包跳了哪些点)

Traceroute 是 ICMP 的另一个应用,用来跟踪一个分组从源点到终点的路径。

Traceroute 发送的 IP 数据报封装的是无法交付的 UDP 用户数据报,并由目的主机发送终点不可达差错报告报文。

源主机知道了到达目的主机所经过的路由器 IP 地址以及到达每个路由器的往返时间。

由于 IP 地址的紧缺,一个机构能申请到的 IP 地址数往往远小于本机构所拥有的主机数。并且一个机构并不需要把所有的主机接入到外部的互联网中,机构内的计算机可以使用仅在本机构有效的 IP 地址(专用地址)。

有三个专用地址块:

  • 10.0.0.0 ~ 10.255.255.255 通常被用于大型组织或企业内部的网络
  • 172.16.0.0 ~ 172.31.255.255 中型到大型组织的内部网络。
  • 192.168.0.0 ~ 192.168.255.255 家庭网络或小型办公室的内部网络

专用网内部的主机使用本地 IP 地址又想和互联网上的主机通信时,可以使用 NAT 来将本地 IP 转换为全球 IP。(主要是ipv4没有那么多ip。

  • 从数据报的首部提取目的主机的 IP 地址 D,得到目的网络地址 N。
  • 若 N 就是与此路由器直接相连的某个网络地址,则进行直接交付;
  • 若路由表中有目的地址为 D 的特定主机路由,则把数据报传送给表中所指明的下一跳路由器;
  • 若路由表中有到达网络 N 的路由,则把数据报传送给路由表中所指明的下一跳路由器;
  • 若路由表中有一个默认路由,则把数据报传送给路由表中所指明的默认路由器;
  • 报告转发分组出错。

传输层

网络层只把分组发送到目的主机,但是真正通信的并不是主机而是主机中的进程。

传输层提供了进程间的逻辑通信,

  • 用户数据报协议 UDP(User Datagram Protocol)是无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加 UDP 首部),支持一对一、一对多、多对一和多对多的交互通信。

  • 传输控制协议 TCP(Transmission Control Protocol)是面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条 TCP 连接只能是点对点的(一对一)。

  • UDP如何变得可靠:等待确认+超时重传+编号

    • UDP要想可靠,就要接收方收到UDP之后回复个确认包,发送方有个机制,收不到确认包就要重新发送每个包有递增的序号,接收方发现中间丢了包就要发重传请求,当网络太差时候频繁丢包,防止越丢包越重传的恶性循环,要有个发送窗口的限制,发送窗口的大小根据网络传输情况调整,调整算法要有一定自适应性。
  • 序号 :用于对字节流进行编号,例如序号为 301,表示第一个字节的编号为 301,如果携带的数据长度为 100 字节,那么下一个报文段的序号应为 401。

  • 确认 ACK :当 ACK=1 时确认号字段有效,否则无效。TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 置 1。

  • 同步 SYN :在连接建立时用来同步序号。当 SYN=1,ACK=0 时表示这是一个连接请求报文段。若对方同意建立连接,则响应报文中 SYN=1,ACK=1。

  • 终止 FIN :用来释放一个连接,当 FIN=1 时,表示此报文段的发送方的数据已发送完毕,并要求释放连接。

  • 窗口 :窗口值作为接收方让发送方设置其发送窗口的依据。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。

  • RST ,重置指令,表示出现严重错误,常用于拒绝非法报文段以及拒绝连接请求;

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/581452ee8c6e16e4026d922db86cea5c.png

① SYN(synchronous建立联机);

② ACK(acknowledgement 确认)

假设 A 为客户端,B 为服务器端。

  • 首先 B 处于 LISTEN(监听)状态,等待客户的连接请求。
  • A 向 B 发送连接请求报文,SYN=1,ACK=0,选择一个初始的序号 x。
  • B 收到连接请求报文,如果同意建立连接,则向 A 发送连接确认报文,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始的序号 y。
  • A 收到 B 的连接确认报文后,还要向 B 发出确认,确认号为 y+1,序号为 x+1。
  • B 收到 A 的确认后,连接建立。

(简单来说,就是客户端先向服务器端发送请求,表示发起连接(SYN码为1),服务器端收到后,同意建立连接(ACK为1),然后发送响应给客户端,告知自己OK了,然后客户端接受到消息,确认服务器OK后。发送消息告诉客户端自己也OK(ACK为1),到这里,服务器和客户端都确认对方OK能收发消息,开始通信。)

三次握手的原因

第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。

  1. 建立可靠的连接: 三次握手确保了客户端和服务器端在同一个初始序列号下建立连接,从而避免了可能出现的混乱和数据混乱。
  2. 防止旧连接的重新建立: 由于每次连接建立都会使用不同的初始序列号,因此可以防止旧的连接被重新建立,从而增强了连接的安全性。
  3. 减少不必要的资源占用: 如果客户端发送的连接请求在网络中因某些原因丢失,服务器将不会收到该请求,从而避免了不必要的资源占用和连接建立失败。

就会触发超时重传机制,重传 SYN 报文,而且重传的 SYN 报文的序列号都是一样的

通常,第一次超时重传是在 1 秒后,第二次超时重传是在 2 秒,第三次超时重传是在 4 秒后,第四次超时重传是在 8 秒后,第五次是在超时重传 16 秒后。没错,每次超时的时间是上一次的 2 倍

当第五次超时重传后,会继续等待 32 秒,如果服务端仍然没有回应 ACK,客户端就不再发送 SYN 包,然后断开 TCP 连接。

  • 客户端会重传 SYN 报文,也就是第一次握手,最大重传次数由 tcp_syn_retries内核参数决定
  • 服务端会重传 SYN-ACK 报文,也就是第二次握手,最大重传次数tcp_synack_retries 内核参数决定

服务端:

第三次的ACK在网络中丢失,那么服务端该TCP连接的状态为SYN_RECV,并且会根据 TCP的超时重传机制,会等待3秒、6秒、12秒后重新发送SYN+ACK包,以便客户端重新发送ACK包。如果重发指定次数之后,仍然未收到 客户端的ACK应答,那么一段时间后,服务端自动关闭这个连接。

客户端:(客户端假设还没接受到服务器端的重发,以为已经创建了连接

客户端认为这个连接已经建立,如果客户端向服务端发送数据,服务端将以RST包(Reset,复位,用于异常的关闭连接)响应。此时,客户端知道第三次握手失败

TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。序列号能够保证数据包不重复、不丢弃和按序传输。

不使用「两次握手」和「四次握手」的原因:

  • 「两次握手」:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号
  • 「四次握手」:三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。

三次握手建立连接的首要目的是「同步序列号」。

第三次是可以携带数据的。

假如第一次握手可以携带数据的话,如果恶意攻击服务器,每次都在第一次握手中的SYN报文中放入大量数据。而且频繁重复发SYN报文,服务器会花费很多的时间和内存空间去接收这些报文。

第三次握手,此时客户端已经处于ESTABLISHED状态。对于客户端来说,他已经建立起连接了,并且已经知道服务器的接收和发送能力是正常的。所以也就可以携带数据了。

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/55a478fca6881d2d9232bac974fea810.png

以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK,因为 ACK 在连接建立之后都为 1。

  • A 发送连接释放报文,FIN=1
  • B 收到之后发出确认,此时 TCP 属于半关闭状态,B 能向 A 发送数据但是 A 不能向 B 发送数据。
  • 当 B 不再需要连接时,发送连接释放报文,FIN=1。
  • A 收到后发出确认ACK=1,进入 TIME-WAIT 状态,等待 2 MSL(最大报文存活时间)后释放连接。
  • B 收到 A 的确认后释放连接ACK=1

四次挥手的原因

CLOSE-WAIT

客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。

TIME_WAIT

客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL(报文最大生存时间”,他是任何报文在网络上存活的最长时间,超过这个时间报文将被丢)。这么做有两个理由:

  • 确保最后一个确认报文能够到达。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。(主要是怕服务器端没有收到然后重发消息给客户端)
  • 等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。

TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题

粘包的问题出现是因为不知道一个用户消息的边界在哪,如果知道了边界在哪,接收方就可以通过边界来划分出有效的用户消息。

为什么会产生粘包和拆包呢?

  • 要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包;
  • 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包
  • 发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包
  • 待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。即TCP报文长度-TCP头部长度>MS

为了解决TCP沾包和拆包问题,通常采用以下几种方法:

  • 使用消息边界:在发送数据时,在数据之间添加特定的消息分隔符或者消息长度字段,接收端根据这些分隔符或长度字段来切分接收到的数据,从而保证每个消息的完整性。
  • 使用固定长度消息:发送端发送的每个消息都是固定长度的,接收端按照固定长度来切分接收到的数据,从而保证每个消息的完整性。

TCP 提供一种机制可以让发送端根据接收端的实际接收能力控制发送的数据量,这就是流量控制

TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文段在超时时间内没有收到确认,那么就重传这个报文段。

窗口是缓存的一部分,用来暂时存放字节流发送方和接收方各有一个窗口,接收方通过 TCP 报文段中的窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小。

发送窗口内的字节都允许被发送,接收窗口内的字节都允许被接收。如果发送窗口左部的字节已经发送并且收到了确认,那么就将发送窗口向右滑动一定距离,直到左部第一个字节不是已发送并且已确认的状态;接收窗口的滑动类似,接收窗口左部字节已经发送确认并交付主机,就向右滑动接收窗口。

流量控制是为了控制发送方发送速率,保证接收方来得及接收。

接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率(可以通过滑动窗口设置流量大小)。将窗口字段设置为 0,则发送方不能发送数据。

**如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。**因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度

原理:


为了在「发送方」调节所要发送数据的量,定义了一个叫做「拥塞窗口」的概念

拥塞窗口 cwnd发送方维护的一个的状态变量,它会根据网络的拥塞程度动态变化的

拥塞窗口 cwnd 变化的规则:

  • 只要网络中没有出现拥塞,cwnd 就会增大
  • 但网络中出现了拥塞,cwnd 就减少

其实只要「发送方」没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传,就会认为网络出现了拥塞


前置声明:

超时重传。

其实只要「发送方」没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传,就会认为网络出现了拥塞

快速重传(Fast Retransmit):当发送方连续收到三个相同的确认 ACK 时,它会认为有一个分组丢失,并立即重传这个分组,而不用等待超时

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/b5ba508e38bd6d058a9f704112bb1e32.png

慢开始(Slow Start)和拥塞避免(Congestion Avoidance)是 TCP 拥塞控制的两个关键机制。

  1. 慢开始(Slow Start):在开始发送数据时,TCP 发送方会以较小的拥塞窗口大小开始发送数据。随着时间的推移和收到确认的数据包数量的增加,发送方会逐渐增加拥塞窗口的大小,指数级增长,以便测试网络的容量。如果没有发生丢包,拥塞窗口大小会快速增长,直到达到一个阈值(慢开始阈值)
1
2
3
4
有一个叫慢启动门限 ssthresh (slow start threshold)状态变量。

当 cwnd < ssthresh 时,使用慢启动算法。 指数增长
当 cwnd >= ssthresh 时,就会使用「拥塞避免算法」。线性增长
  1. 拥塞避免(Congestion Avoidance)一旦拥塞窗口大小达到了慢开始阈值,TCP 发送方就会进入拥塞避免阶段。在这个阶段,拥塞窗口的增长变得线性,而不是指数增长。这样做是为了避免过快地增加发送的数据量,从而导致网络拥塞。

  2. 拥塞检测(Congestion Detection):如果发送方检测到网络拥塞的迹象,如丢失数据包或收到拥塞通知,它将执行拥塞检测。在这个阶段,发送方降低其发送速率,以减轻网络负载,从而帮助缓解拥塞。

如果检测出了拥塞,也就是会发生数据包重传,重传机制主要有两种: 超时重传 快速重传发生了「超时重传」,则就会使用拥塞发生算法。(一般不用这个,在发着这个之前,就有快速重传算法)

1
2
3
4
这个时候,ssthresh 和 cwnd 的值会发生变化:

ssthresh 设为 cwnd/2,
cwnd 重置为 1 (是恢复为 cwnd 初始化值,我这里假定 cwnd 初始化值 1)

发生快速重传的拥塞发生算法(一般是执行这个)

1
2
3
4
5
6
则 ssthresh 和 cwnd 变化如下:

cwnd = cwnd/2 ,也就是设置为原来的一半;窗口减半,阈值变为窗口大小,立马启动拥塞避免算法,开始线性增长。进入快恢复
ssthresh = cwnd;
进入快速恢复算法
#快速恢复
  1. 快恢复(Fast Recovery):在进行快重传后,TCP 发送方不会立即进入慢开始阶段,而是将拥塞窗口减半,然后进入快恢复状态。在快恢复状态下,拥塞窗口大小会增加,并且继续线性增长而不是指数增长。这样可以更快地恢复到之前的发送速率。

应用层

DNS 是一个分布式数据库,提供了主机名和 IP 地址之间相互转换的服务。

**DNS 可以使用 UDP 或者 TCP 进行传输,使用的端口号都为 53。大多数情况下 DNS 使用 UDP 进行传输,**这就要求域名解析器和域名服务器都必须自己处理超时和重传从而保证可靠性。在两种情况下会使用 TCP 进行传输:

  • 如果返回的响应超过的 512 字节(UDP 最大只支持 512 字节的数据)。
  • 区域传送(区域传送是主域名服务器向辅助域名服务器传送变化的那部分数据)

FTP 使用 TCP 进行连接,它需要两个连接来传送一个文件:服务器端使用21端口

DHCP (Dynamic Host Configuration Protocol) 提供了即插即用的连网方式,用户不再需要手动配置 IP 地址等信息。

DHCP 工作过程如下:

  1. 客户端发送 Discover 报文,该报文的目的地址为 255.255.255.255:67,源地址为 0.0.0.0:68,被放入 UDP 中,该报文被广播到同一个子网的所有主机上(UDP支持点对多,TCP只能点对点)。如果客户端和 DHCP 服务器不在同一个子网,就需要使用中继代理。
  2. DHCP 服务器收到 Discover 报文之后,发送 Offer 报文给客户端,该报文包含了客户端所需要的信息。因为客户端可能收到多个 DHCP 服务器提供的信息,因此客户端需要进行选择。
  3. 如果客户端选择了某个 DHCP 服务器提供的信息,那么就发送 Request 报文给该 DHCP 服务器。
  4. DHCP 服务器发送 Ack 报文,表示客户端此时可以使用提供给它的信息。

TELNET 用于登录到远程主机上,并且远程主机上的输出也会返回。

一个电子邮件系统由三部分组成:用户代理、邮件服务器以及邮件协议。

邮件协议包含发送协议和读取协议,发送协议常用 SMTP,读取协议常用 POP3 和 IMAP。

Socket 不是一个严格意义上的网络层或协议,而是一个应用程序接口(API)层。因此,Socket 位于 OSI 模型的最顶层——应用层,用于帮助应用程序与传输层(如 TCP 和 UDP)进行通信。TCP与UDP都行

其他综合网络题目

  1. 浏览器通过域名查找对应的ip地址
    1. DNS
  2. 浏览器与服务器通过三次握手建议TCP连接
  3. 浏览器向服务器发送一个HTTP请求
  4. 服务器处理请求(处理请求参数、cookie,生成HTML响应)
  5. 服务器返回一个HTML响应
  6. 浏览器解析渲染页面
  7. TCP四次挥手,结束

简化版区别:

HTTP/1.0:默认是短连接,可以强制开启,通过加入Connection: keep - alive

  • 默认使用短连接每次请求都需要建立一个TCP连接

HTTP/1.1:默认为长连接

  • 最主要的改进就是引入了持久连接。所谓的持久连接即TCP连接默认不关闭,可以被多个请求复用
  • 引入了管道机制(pipelining),即在同一个TCP连接里面,客户端可以同时发送多个请求。这样就进一步改进了HTTP协议的效率
  • 支持断点续传

HTTP/2.0:多路复用

  • 多路复用:在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应
  • 做了Header压缩、服务端推送等优化

HTTP/3.0:基于UDP的quic协议。

  1. 发起请求(TCP链接): 客户端在通过TCP 和服务器建立连接之后( 443 端口),发出一个请求证书的消息给服务器,在该请求消息里包含自己可实现的算法列表和其他需要的消息。
  2. 证书返回:服务器端在收到消息后回应客户端并返回证书,在证书中包含服务器信息、域名、申请证书的公司、公钥、数据加密算法等。
  3. 证书验证: 客户端在收到证书后,判断证书签发机构是否正确,并使用该签发机构的公钥确认签名是否有效, 客户端还会确保在证书中列出的域名就是它正在连接的域名。如果客户端确认证书有效,则生成对称密钥,并使用公钥将对称密钥加密。
  4. 密钥交换: 客户端将加密后的对称密钥发送给服务器,服务器在接收到对称密钥后使用私钥解密
  5. 数据传输: 经过上述步骤,客户端和服务器就完成了密钥对的交换, 在之后的数据传输过程中, 客户端和服务端就可以基于对称加密( 加密和解密使用相同密钥的加密算法)对数据加密后在网络上传输,保证了网络数据传输的安全性

总结:实际上是一种混合加密,通过非对称加密交换了对称加密的对称秘钥,实现了安全性和性能的综合

基于TCP的应用层协议有:HTTP、FTP、SMTP、TELNET、SSH

  • HTTP:HyperText Transfer Protocol(超文本传输协议),默认端口80
  • FTP: File Transfer Protocol (文件传输协议), 默认端口(20用于传输数据,21用于传输控制信息)
  • SMTP: Simple Mail Transfer Protocol (简单邮件传输协议) ,默认端口25
  • TELNET: Teletype over the Network (网络电传), 默认端口23
  • SSH:Secure Shell(安全外壳协议),默认端口 22

基于UDP的应用层协议:DNS、TFTP、SNMP

  • DNS : Domain Name Service (域名服务),默认端口 53
  • TFTP: Trivial File Transfer Protocol (简单文件传输协议),默认端口69
  • SNMP:Simple Network Management Protocol(简单网络管理协议),通过UDP端口161接收,只有Trap信息采用UDP端口162
  • 强制缓存:只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边,(检测到一样的请求链接,在过期时间内,直接访问本地缓存结构,不发送http请求)
  • 协商缓存:通过服务端告知客户端是否可以使用缓存的方式,协商缓存就是与服务端协商之后,通过协商结果来判断是否使用本地缓存

TCP 的连接状态查看,在 Linux 可以通过 netstat -napt 命令查看

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/f1193ff8b388617c0de6badda63473af.png

状态码 类别
1XX 信息性状态码
2XX 成功类状态码
3XX 重定向状态码
4XX 客户端错误状态码
5XX 服务端错误状态码

HTTP 协议(Hyper Text Transfer Protocol),又叫做超文本传输协议。我们用的比较多,平时上网在浏览器上敲个网址就能访问网页,这里用到的就是 HTTP 协议。

RPCRemote Procedure Call),又叫做远程过程调用。它本身并不是一个具体的协议,而是一种调用方式。(远程调用其他服务的函数,比较有名的gRPCthrift。)(RPC必http早)。RPC 有很多种实现方式,不一定非得基于 TCP 协议

由于RPC可以自己根据需求研发,可以实现根据一些内部服务需求做性能上的优化。

  • 例如减去header里面一些用不上的信息
  • 强制缓存:只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边
  • 协商缓存:通过服务端告知客户端是否可以使用缓存的方式,协商缓存就是与服务端协商之后,通过协商结果来判断是否使用本地缓存

我们都知道 TCP 连接建立是需要三次握手,假设攻击者短时间伪造不同 IP 地址的 SYN 报文,服务端每接收到一个 SYN 报文,就进入SYN_RCVD 状态,但服务端发送出去的 ACK + SYN 报文,无法得到未知 IP 主机的 ACK 应答,久而久之就会占满服务端的半连接队列,使得服务端不能为正常用户服务

说明:在 TCP 三次握手的时候,Linux 内核会维护两个队列,分别是:

  • 半连接队列,也称 SYN 队列;
  • 全连接队列,也称 accept 队列;

SYN 攻击方式最直接的表现就会把 TCP 半连接队列打满,这样当 TCP 半连接队列满了,后续再在收到 SYN 报文就会丢弃导致客户端无法和服务端建立连接。

如何处理SYN攻击

  1. 加强网络安全策略:配置防火墙规则,限制网络流量,过滤恶意请求。
  2. SYN Cookies:在操作系统层面启用SYN Cookies机制,当TCP连接队列满时,使用SYN Cookies代替正常的TCP连接,防止队列耗尽。
  3. 网络设备升级:更新和升级网络设备的固件和软件,以修复已知的SYN攻击漏洞。
  4. 限制并发连接数:限制单个IP地址的并发连接数,减少攻击的影响范围。
  5. 使用反向代理:使用反向代理来处理外部的网络请求,可以有效过滤掉一部分恶意流量。

UDP Flood 主要通过利用服务器响应发送到其中一个端口的 UDP 数据包所采取的步骤。在正常情况下,当服务器在特定端口接收到 UDP 数据包时,会经过两个步骤:

  • 服务器首先检查是否正在运行正在侦听指定端口的请求的程序。
  • 如果没有程序在该端口接收数据包,则服务器使用 ICMP(ping)数据包进行响应,以通知发送方目的地不可达。

当服务器接收到每个新的 UDP 数据包时,它将通过步骤来处理请求,并利用该过程中的服务器资源。发送 UDP 报文时,每个报文将包含源设备的 IP 地址。在这种类型的 DDoS 攻击期间,攻击者通常不会使用自己的真实 IP 地址,而是会欺骗 UDP 数据包的源 IP 地址,从而阻止攻击者的真实位置被暴露并潜在地饱和来自目标的响应数据包服务器。

同时发送大量的带有隐藏IP的UDP数据包,将服务器资源迅速耗尽。

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/bd80dd5b6567f5d32e8a82bf3ec52a82.png

如何缓解 UDP Flooding?

大多数操作系统部分限制了 ICMP 报文的响应速率以中断需要 ICMP 响应的 DDoS 攻击。这种缓解的一个缺点是在攻击过程中,合法的数据包也可能被过滤。如果 UDP Flood 的容量足够高以使目标服务器的防火墙的状态表饱和,则在服务器级别发生的任何缓解都将不足以应对目标设备上游的瓶颈。

HTTP Flood 是一种大规模的 DDoS(Distributed Denial of Service,分布式拒绝服务)攻击,旨在利用 HTTP 请求使目标服务器不堪重负。

缓解原理

TCP 重置攻击中,攻击者通过向通信的一方或双方发送伪造的消息,告诉它们立即断开连接,从而使通信双方连接中断。正常情况下,如果客户端收发现到达的报文段对于相关连接而言是不正确的,TCP 就会发送一个重置报文段,从而导致 TCP 连接的快速拆卸。

TCP 重置攻击利用这一机制,通过向通信方发送伪造的重置报文段,欺骗通信双方提前关闭 TCP 连接。

从某种意义上来说,伪造 TCP 报文段是很容易的,因为 TCP/IP 都没有任何内置的方法来验证服务端的身份。

前面很多东西都是ddos,DDos 全名 Distributed Denial of Service,翻译成中文就是分布式拒绝服务。指的是处于不同位置的多个攻击者同时向一个或数个目标发动攻击,是一种分布的、协同的大规模攻击方式。

解决办法

  • 高防服务器
  • ip黑名单
  • ddos清洗,DDoS 清洗会对用户请求数据进行实时监控,及时发现 DOS 攻击等异常流量,在不影响正常业务开展的情况下清洗掉这些异常流量。
  • CDN加速,将资源分布到不同的地方,隐藏真实ip。

为了兼容这些使用场景。浏览器在 TCP 三次握手建立连接之后,都统一使用 HTTP 协议先进行一次通信。

  • 如果此时是普通的 HTTP 请求,那后续双方就还是老样子继续用普通 HTTP 协议进行交互,这点没啥疑问。
  • 如果这时候是想建立 WebSocket 连接,就会在 HTTP 请求里带上一些特殊的header 头,如下:
1
2
3
Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Key: T2a6wZlAwhgQNqruZ2YUyg==\r\n

这些 header 头的意思是,浏览器想升级协议(Connection: Upgrade),并且想升级成 WebSocket 协议(Upgrade: WebSocket)。同时带上一段随机生成的 base64 码(Sec-WebSocket-Key),发给服务器。

  • 简介: KCP是一种快速可靠的UDP传输协议,由著名的开源项目kcptun提供支持,旨在解决UDP在不可靠网络上的不足之处,例如高丢包率和乱序。(常用于游戏和直播等)
  • 特点:
    • 高效的流量控制:KCP使用了自定义的流量控制算法,能够更好地适应不同的网络环境,从而实现更加稳定的数据传输。
    • 极低的延迟:KCP在设计上考虑了延迟敏感型应用,尽可能地减少了数据传输的延迟。
    • 可定制性强:KCP的参数可以根据具体的网络环境和应用需求进行调整,具有很高的灵活性
  • 简介: QUIC是由Google推出的基于UDP的传输协议,旨在提供更加快速和安全的网络连接。QUIC已经被广泛应用于Google的服务中,并逐渐得到其他厂商和开发者的关注。
  • 特点:
    • 多路复用:QUIC支持多路复用,允许在同一个连接上同时进行多个数据流的传输,从而提高了网络的利用率和性能。
    • 连接迁移:QUIC支持连接迁移,即在网络切换或IP地址变化时能够自动重新建立连接,而无需重新握手。
    • 安全性:QUIC内置了加密机制,使得数据在传输过程中更加安全可靠,同时也能够防止中间人攻击等安全威胁。

QUIC内置了加密机制,使得数据传输更加安全可靠,而KCP则需要在应用层实现相应的加密机制。

是一种网络安全工具,用于保护网络应用程序免受常见的网络攻击和漏洞利用。WAF通过检测和阻止恶意的HTTP/HTTPS流量,以及对应用程序层的攻击进行识别和防御,从而增强了网络应用程序的安全性。

一种是前端需要更多的数据库权限,而且开发速度有要求,这样直接把操作数据库的权限放到前端。

前端需要更多时间调整代码,并注意查询和操作数据库的可用性。

BBR最大的改进是由丢包率为主的有限状态机转为了由带宽时延积,(物理时延和带宽瓶颈)控制的状态机,走了两轮。参见这个链接[状态机,了解]

  • TCP的keepalive是侧重在保持客户端和服务端的连接,一方会不定期发送心跳包给另一方,当一方端掉的时候,没有断掉的定时发送几次心跳包,如果间隔发送几次,对方都返回的是RST,或者没有响应,而不是ACK,那么就释放当前链接。设想一下,如果tcp层没有keepalive的机制,一旦一方断开连接却没有发送FIN给另外一方的话,那么另外一方会一直以为这个连接还是存活的,几天,几月。那么这对服务器资源的影响是很大的。
  • HTTP的keep-alive一般我们都会带上中间的横杠,主要功能是保活复用。普通的http连接是客户端连接上服务端,然后结束请求后,由客户端或者服务端进行http连接的关闭。下次再发送请求的时候,客户端再发起一个连接,传送数据,关闭连接。这么个流程反复。但是一旦客户端发送connection:keep-alive头给服务端,且服务端也接受这个keep-alive的话,两边对上暗号,这个连接就可以复用了,一个http处理完之后,另外一个http数据直接从这个连接走了。减少新建和断开TCP连接的消耗。
  • 客户端的 SYN 报文里的端口号与历史连接不相同

如果客户端恢复后发送的 SYN 报文中的源端口号跟上一次连接的源端口号不一样,此时服务端会认为是新的连接要建立,于是就会通过三次握手来建立新的连接。

那旧连接里处于 Established 状态的服务端最后会怎么样呢?

如果服务端发送了数据包给客户端,由于客户端的连接已经被关闭了,此时客户的内核就会回 RST 报文,服务端收到后就会释放连接。

如果服务端一直没有发送数据包给客户端,在超过一段时间后,TCP 保活机制就会启动,检测到客户端没有存活后,接着服务端就会释放掉该连接。

  • 客户端的 SYN 报文里的端口号与历史连接相同

处于 Established 状态的服务端,如果收到了客户端的 SYN 报文(注意此时的 SYN 报文其实是乱序的,因为 SYN 报文的初始化序列号其实是一个随机数),会回复一个携带了正确序列号和确认号的 ACK 报文,这个 ACK 被称之为 Challenge ACK。

接着,客户端收到这个 Challenge ACK,发现确认号(ack num)并不是自己期望收到的,于是就会回 RST 报文,服务端收到后,就会释放掉该连接。

收到合法 SYN

如果处于 TIME_WAIT 状态的连接收到「合法的 SYN 」后,就会重用此四元组连接,跳过 2MSL 而转变为 SYN_RECV 状态,接着就能进行建立连接过程

收到非法的 SYN

如果处于 TIME_WAIT 状态的连接收到「非法的 SYN 」后,就会再回复一个第四次挥手的 ACK 报文,客户端收到后,发现并不是自己期望收到确认号(ack num),就回 RST 报文给服务端

TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且有序的,如果序列号较低的 TCP 段在网络传输中丢失了,即使序列号较高的 TCP 段已经被接收了,应用层也无法从内核中读取到这部分数据。如下图:

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/5a309f17f0182a816ddbc4cac4a5141e.gif

图中发送方发送了很多个 packet,每个 packet 都有自己的序号,你可以认为是 TCP 的序列号,其中 packet #3 在网络中丢失了,即使 packet #4-6 被接收方收到后,由于内核中的 TCP 数据不是连续的,于是接收方的应用层就无法从内核中读取到,只有等到 packet #3 重传后,接收方的应用层才可以从内核中读取到数据。

这就是 TCP 队头阻塞问题,但这也不能怪 TCP ,因为只有这样做才能保证数据的有序性。

HTTP/2 多个请求是跑在一个 TCP 连接中的,那么当 TCP 丢包时,整个 TCP 都要等待重传,那么就会阻塞该 TCP 连接中的所有请求,所以 HTTP/2 队头阻塞问题就是因为 TCP 协议导致的。

TCP 队头阻塞的问题,其实就是接收窗口的队头阻塞问题!!!!!!!

TCP 协议四个方面的缺陷

  • 升级 TCP 的工作很困难;
  • TCP 建立连接的延迟;
  • TCP 存在队头阻塞问题;
  • 网络迁移需要重新建立 TCP 连接;

要基于 UDP 实现的可靠传输协议,那么就要在应用层下功夫,也就是要设计好协议的头部字段。

quic协议的结构

  • 先是udp的头部
  • 然后是quic的packet的头部
  • 最后是quic的frame的头部

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/72522dd50c22f5662c07f6a8ecc9197b.png

Packet Header 首次建立连接时和日常传输数据时使用的 Header 是不同的。如下图(注意我没有把 Header 所有字段都画出来,只是画出了重要的字段):

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/f7eed932a3f2b867e04bfb4297dd5e43.png

QUIC 报文中的 Pakcet Number 是严格递增的, 即使是重传报文,它的 Pakcet Number 也是递增的,这样就能更加精确计算出报文的 RTT。

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/8d5565d9c3efe331bb9fb8e8f2d09dac.png

QUIC 使用的 Packet Number 单调递增的设计,可以让数据包不再像 TCP 那样必须有序确认,QUIC 支持乱序确认,当数据包Packet N 丢失后,只要有新的已接收数据包确认,当前窗口就会继续向右滑动(后面讲流量控制的时候,会举例子)

一个 Packet 报文中可以存放多个 QUIC Frame。

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/ac87e9f1a26f40be280e62c1d5f3f8f6.png

每一个 Frame 都有明确的类型,针对类型的不同,功能也不同,自然格式也不同。

Frame 格式,Stream 可以认为就是一条 HTTP 请求,它长这样:

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/ad87d5897557f51a5da504aa51b4c283/e420eb13ca194f7e657526eafe356c8b.png

  • Stream ID 作用:多个并发传输的 HTTP 消息,通过不同的 Stream ID 加以区别,类似于 HTTP2 的 Stream ID;
  • Offset 作用:类似于 TCP 协议中的 Seq 序号保证数据的顺序性和可靠性
  • Length 作用:指明了 Frame 数据的长度。

通过 Stream ID + Offset 字段信息实现数据的有序性,通过比较两个数据包的 Stream ID 与 Stream Offset ,如果都是一致,就说明这两个数据包的内容一致。

总的来说,QUIC 通过单向递增的 Packet Number,配合 Stream ID 与 Offset 字段信息,可以支持乱序确认而不影响数据包的正确组装,摆脱了TCP 必须按顺序确认应答 ACK 的限制,解决了 TCP 因某个数据包重传而阻塞后续所有待发送数据包的问题。

为什么这样解决了TCP队头阻塞问题!!!!!!!,TCP队头阻塞主要是多个http公用一个tcp请求,一个steam阻塞导致所有的阻塞了。而quic不一样,它给每个steam都分配了一个独立的滑动窗口这样使得一个连接上的多个 Stream 之间没有依赖关系,都是相互独立的,各自控制的滑动窗口

quic的机制

  • 滑动窗口
  • 流量控制,通过几个参数
  • 拥塞控制。

QUIC的TLS

TCP的缺点:TCP 和 TLS 是分层的,分别属于内核实现的传输层、openssl 库实现的表示层,因此它们难以合并在一起,需要分批次来握手,先 TCP 握手(1RTT),再 TLS 握手(2RTT),所以需要 3RTT 的延迟才能传输数据,就算 Session 会话服用,也需要至少 2 个 RTT。

QUIC 内部包含了 TLS,它在自己的帧会携带 TLS 里的“记录”,再加上 QUIC 使用的是 TLS1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商,甚至在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果

可以的。

TCP 和 UDP 传输协议,在内核中是由两个完全独立的软件模块实现的。

当主机收到数据包后,可以在 IP 包头的「协议号」字段知道该数据包是 TCP/UDP,所以可以根据这个信息确定送给哪个模块(TCP/UDP)处理,送给 TCP/UDP 模块的报文根据「端口号」确定送给哪个应用程序处理。

因此, TCP/UDP 各自的端口号也相互独立,互不影响。

客户端-》交换机-》路由器

注意:从客户端出发的时候是内网ip,在路由器可能会执行网络地址转换(NAT)将内网的私有IP地址转换为路由器的公网IP地址。当数据包从客户端发送到服务器时,路由器会将源IP地址修改为其自身的公网IP地址,它会在NAT转换表中记录这个映射关系,以便在响应数据包到达时进行逆向转换。(这也是数据包能够回传的重要原因)

然后路由器根据自身的路由表一个一个传递。

-》到达服务器,服务器拆包,然后发送回nat出来的对应的运营商的公网ip

-》nat映射到内网,发送到指定的客户端

RPC与proto协议

Protocol Buffers(通常简称为protobuf)是Google开发的一种数据序列化协议(类似于XML、JSON、YAML等),它能将结构化数据序列化,用于数据存储、通信协议等方面。

protobuf的主要优点是:

  1. 紧凑:protobuf序列化后的数据非常小,比XML、JSON等格式更加紧凑。
  2. 高效:protobuf的序列化和反序列化速度非常快。
  3. 强类型:protobuf的数据是强类型的,可以明确数据的类型。
  4. 语言无关:protobuf支持多种编程语言,如Java、C++、Python等。
  5. 向后兼容:protobuf定义的消息格式可以方便地进行升级,新旧版本的消息格式可以兼容。

下面是一个protobuf的使用示例:

首先,定义一个protobuf的消息格式(保存为person.proto文件):

1
2
3
4
5
6
7
syntax = "proto3";

message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;
}

然后,使用protobuf的编译器(protoc)生成对应语言的代码,例如生成Python代码:

1
protoc --python_out=. person.proto

这将生成一个person_pb2.py文件,里面包含了Person类的定义。

接下来,就可以在Python代码中使用Person类进行序列化和反序列化:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import person_pb2

# 创建一个Person对象
person = person_pb2.Person()
person.name = "Alice"
person.id = 123
person.email = "alice@example.com"

# 序列化
data = person.SerializeToString()

# 反序列化
new_person = person_pb2.Person()
new_person.ParseFromString(data)
print(new_person.name, new_person.id, new_person.email)  # 输出 "Alice 123 alice@example.com"

在这个示例中,我们首先创建了一个Person对象,并赋值。然后,我们将Person对象序列化为一个字符串。接着,我们创建了一个新的Person对象,并从字符串中反序列化。最后,我们打印出反序列化后的数据,可以看到数据是正确的。

CGI和WSGI

CGI是通用网关接口,是连接web服务器和应用程序的接口,用户通过CGI来获取动态数据或文件等。 CGI程序是一个独立的程序,它可以用几乎所有语言来写,包括perl,c,lua,python等等

WSGI, Web Server Gateway Interface,是Python应用程序或框架和Web服务器之间的一种接口,WSGI的其中一个目的就是让用户可以用统一的语言(Python)编写前后端。

c10k问题

C10K问题是指服务器同时处理大量(例如:上万,即10K)客户端连接的问题。这个问题在1999年由Dan Kegel首次提出,当时的很多服务器软件在面对大量并发连接时会出现各种问题,如性能下降,无法处理更多的连接等。

C10K问题的解决方法主要涉及到操作系统级别的网络编程模型优化,如使用事件驱动(event-driven)或异步I/O(asynchronous I/O)模型,以及使用更现代的多线程或多进程模型等。

现在,很多现代的Web服务器和操作系统(如Nginx,Linux等)已经可以很好地处理C10K问题,能够支持上万甚至更多的并发连接。

TCP同时打开和同时关闭

两个应用程序同时彼此执行主动打开的情况是可能的,尽管发生的可能性极小。每一方必须发送一个SYN,且这些SYN必须传递给对方。这需要每一方使用一个对方熟知的端口最为本地端口。 当出现同时打开的情况时,状态迁移图就与标准的连接状态迁移图不一样了。两端几乎同时发送SYN并进入SYN_SENT状态。当每一端收到SYN时,状态变为SYN_RCVD,同时它们都再发SYN并对收到的SYN进行确认。当双方都接收到SYN及相应的ACK时,状态都变味了ESTABLISHED。 一个同时打开的连接需要交换需要交换4个报文段,比正常的三次握手多一个。没有任何一端称为客户或服务器,因为每一端既是客户又是服务器。

https://img-blog.csdn.net/20170704164020832?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbV9idWRkeQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast

在标准的情况下通过一方发送FIN来关闭连接,但是双方都执行主动关闭也是有可能的,TCP协议也允许这样的同时关闭。当应用层发出关闭命令时,梁福安均从ESTABLISHED变为FIN_WAITE_1。这将导致双发各发送一个FIN,两个FIN经过网络传输后分别达到另一端。收到FIN后,状态由FIN_WAIT_1变签到CLOSING,并将发送最后的ACK。当收到最后的ACK时,状态变化为TIME_WAIT。

https://img-blog.csdn.net/20170704164028654?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbV9idWRkeQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast

ref

cs-note