计算机网络原理

TCP 和 UDP 协议

HTTP 协议在 OSI 模型的哪一层?

HTTP协议在OSI模型中属于应用层协议。HTTP(超文本传输协议)是用于在Web上进行数据传输的协议,主要负责客户端和服务器之间的通信。

HTTP协议定义了请求和响应的格式,以及如何传输数据,因此它位于OSI模型的最高层——应用层。

OSI模型的七层

  1. 物理层

  2. 数据链路层

  3. 网络层

  4. 传输层

  5. 会话层

  6. 表示层

  7. 应用层

TCP/IP五层模型

  • 应用层

  • 传输层

  • 网络层

  • 数据链路层

  • 物理层

TCP 协议三次握手、四次挥手详解(必会)

三次握手,以客户端向服务端发起TCP链接请求举例子。

(有条件建议画图说明)

TCP三次握手

  • 客户端在主动打开链接后,发起 第一次握手(SYN=1,seq=x)。

  • 服务端在收到第一次握手报文段后,发送 第二次握手(SYN=1,ACK=1,seq=y,ack=x+1)。此时能够证明,服务端可以正确收到客户端发来的信息,并向客户端继续索要编号为x+1的报文段。

  • 客户端在收到第二次握手报文段后,会发送 第三次握手(ACK=1,seq=x+1,ack=y+1)。此时能够证明,客户端能够正确收到服务端发来的消息。

  • 第三次握手信息到达服务端后,TCP链接建立,握手过程结束。此时服务端知道客户端能够收到自己的信息。

四次挥手,以客户端做为主动断开链接的一方举例。

TCP四次挥手

  • 客户端在报文发送结束后,希望进入终止程序,所以进行 第一次挥手(FIN=1,seq=u)。这条信息告知服务端,客户端已经发完信息,希望断联。

  • 服务端在收到第一次挥手的报文段后,没有立即进入终止程序,因为可能还存在没有发送完的信息,所以进行 第二次挥手(ACK=1,seq=v,ack=u+1)。这条报文段是为了告知客户端,你(C)希望断开的信息我(S)收到了。

  • 此时进入半关状态,服务端在一段时间之后,数据也发送完毕,则进入终止程序,主动进行 第三次挥手(FIN=1,seq=w,ACK=1,ack=u+1)。这条报文段告知客户端,我的信息已发完,可以断联。

  • 客户端在收到第三次挥手的报文段后,进行 第四次挥手(ACK=1,seq=u+1,ack=w+1)。这条报文段告知服务端,你(S)希望断开的信息我(C)收到了。

为什么 TCP 协议握手是三次,而挥手需要四次

可以回答为:因为服务端不一定马上能关闭。

因为在断开TCP链接挥手阶段的时候,被动断开的一方可能还有信息没有发送完,所以产生了收到 FIN 终止报文后的回复报文终止报文两个报文,相比握手要多一个挥手次数。

TCP 和 UDP 的原理、区别、使用场景

原理:

TCP 协议通过三次握手建立连接,四次挥手断开连接,提供可靠的数据传输服务。TCP 协议还在 IP 协议上实现了校验、序号机制、确认和重传机制。保证了数据传输的安全性和可靠性。

UDP 协议仅仅在 IP 协议上加入了复用、分用、差错检测。约等于裸奔。


区别、使用场景:

TCP和UDP都是基于网络层IP协议之上的传输层协议,TCP是面向连接的协议,而UDP是无连接的协议。

  1. TCP(Transmission Control Protocol)提供可靠的数据传输服务,确保数据包按顺序到达,并且在传输过程中进行错误检测和纠正。TCP适用于需要保证数据完整性和可靠性的应用,如HTTP、FTP、SMTP等。

  2. UDP(User Datagram Protocol)提供无连接的数据传输服务,不保证数据包的顺序到达,不可靠。UDP适用于小型数据包或对速度要求较高,但对数据完整性不敏感的应用,如视频流、在线游戏、DNS解析等。

TCP的慢启动和拥塞避免

为了防止网络中被注入过多的数据造成网络拥堵,在TCP的拥塞避免算法中使用了:慢启动,拥塞避免,快重传,快恢复等方法。

  • 慢启动:发送端最开始只发送一个报文段,每收到一个回复报文就将可发送数增加 1。所以一个传输轮次中是以二的倍数增加的。

  • 拥塞避免:当发送端的可发送数达到一个阈值时,进入拥塞避免阶段,此时每收到一个回复报文就将可发送数增加 1。

  • 一旦发送端察觉到出现拥堵,就会将发送窗口重新降为1,再次进入慢启动状态。这是为了让网络有时间处理完积压的数据。

  • 快重传:当发送端连续收到三个重复的 ACK 冗余报文时,立即重传丢失的数据包,而不必等待重传定时器到期。

  • 快恢复:当发送端收到三个重复的 ACK 冗余报文时,进入快恢复,发送窗口减小为一半,并进入拥塞避免算法。这是因为,既然能顺利收到3个重复的ACK报文说明非目标报文的后续报文段陆续抵达,此时可以认为网路不存在严重拥堵,不需要退避到1重新进行慢开始。

TCP为什么在关闭链接之后,主动发起关闭的那一方需要等待 2MSL

为什么在TCP断开链接之后,主动断开链接的一方会等待2MSL的时间?

首先,MSL是一个报文段在网络中的最长持续时间,TCP必须等待 2MSL 时长才能彻底断开链接是为了两点:

  1. 预留重传时间窗口:如果最后一次挥手的报文段丢失,那么服务器端超时会请求重传,如果提前关闭,服务器端可能无法正确关闭TCP链接。

  2. 防止脏数据污染:我们在建立tcp链接的时候是依靠着服务器和客户端的套接字来确认的,也就意味着,如果网络里还有一些延迟的旧数据包没消失,贸然在这个时间建立了新的TCP链接,可能会导致新链接误以为旧包是新数据。

TCP 报文段的首部的标志位有哪些?TIME_WAIT, CLOSE_WAIT 状态各属于哪一方?

TCP 报文段的首部包含以下标志位:

  • SYN(同步):用于建立连接的标志位。

  • ACK(确认):用于确认收到数据的标志位。

  • FIN(结束):用于终止连接的标志位。

  • RST(重置):用于重置连接的标志位。

  • PSH(推送):用于提示接收方立即将数据推送给应用层,不用等缓存区满了之后再向上交付。(尽快交付)

  • URG(紧急):用于标识报文段中有紧急数据的标志位。(尽快发送)


TIME_WAIT属于主动断联方,当一方主动关闭连接后,会进入 TIME_WAIT 状态,等待 2MSL 的时间,以确保对方收到最后的 ACK 报文段,并且防止旧的报文段干扰新的连接。

CLOSE_WAIT属于被断联方,当一方被动关闭连接后,但仍有数据需要发送(不发也有这个状态),会进入 CLOSE_WAIT 状态。

粘包拆包是什么,发生在哪一层

粘包和拆包是指在 TCP 协议中,由于 TCP 是一个面向字节流的协议,数据包可能会被分割成多个部分发送(拆包),或者多个数据包可能会被合并成一个数据包发送(粘包)。这主要发生在传输层。

黏包怎么解决?

解决粘包问题的方法有以下几种:

  1. 定长消息:每个消息固定长度,接收端按照固定长度读取

  2. 分隔符:在消息之间使用特殊的分隔符,接收端根据分隔符进行拆包

  3. 消息头:在消息前面添加一个固定长度的消息头,包含消息的长度信息,接收端先读取消息头,然后根据长度信息读取消息体

  4. 使用更高级的协议:如HTTP、WebSocket等,这些协议已经内置了解决粘包问题的机制。

SYN + ACK 包能不能拆开来发

SYN + ACK 包不能拆开来发,因为它们是TCP三次握手过程中第二步的一个整体,必须同时发送以确保连接的正确建立。

SYN 同步报文段本身也不携带任何数据。第二次握手的时候之所以要给同步报文段的确认位(ACK)置 1 是因为这也是针对第一次报文的确认报文。

讲讲听说过哪些快速重传算法

快速重传算法是TCP协议中的一种机制,用于在数据包丢失时快速恢复连接。它通过监测连续收到的重复ACK报文段来判断数据包是否丢失。当发送端连续收到三个重复的ACK报文段时,立即重传丢失的数据包,而不必等待重传定时器到期。

上文也提到了,只要接收端漏接了某个报文号,又接到之后的报文号,接收端会返回“冗余ACK”,次数到三次就立刻触发重传。

应用层协议

HTTPS用到的是对称加密还是非对称加密?分别体现在哪里?

HTTPS 即用到了对称加密,也用到了非对称加密。

  • 非对称加密的特点是安全,但是慢。

  • 对称加密的特点是快,但是不安全。

由此,结合 TCP 的特性,我们就可以在握手过程中使用 TLS 协议中的 RSA 算法进行非对称加密。在握手的过程中,浏览器先核实路由器中保存的CA机构签发的证书,并提取公钥。
再之后客户端本地生成一段随机码(密钥),使用公钥进行加密,由于解码这段信息的私钥仅保存在服务器上,所以就算中途被劫持也无法破译,使得密钥的安全性得到保障。
在后续的通信过程中,客户端和服务器就可以使用对称加密算法(如AES)来加密数据,因为双方都已经拥有了相同的密钥,这样可以保证通信的效率。

http协议各个版本

HTTP 1.0

HTTP1.0 协议是每个请求都得重新建立一次TCP链接,结束就会断开,那么一个页面如果有十几个资源,就会导致十几次的TCP链接的建立。性能灾难。

关键性能卡点:每个请求都需要重新建立一次TCP链接。

HTTP 1.1

HTTP1.1 协议引入了持久连接(Persistent Connection)和管道化(Pipelining)机制,允许在一个TCP连接上发送多个HTTP请求和响应,从而减少了TCP连接的建立和关闭次数,提高了性能。

HTTP1.1队头阻塞示意图

关键性能卡点:多个请求发送后,必须按序处理先来后到,才能处理处理下一个请求,这就会产生阻塞时间。这就是所谓的:队头阻塞(Head-of-Line Blocking)问题。

HTTP 2.0

HTTP2.0 协议引入了多路复用(Multiplexing)机制,允许在一个TCP连接上同时发送多个HTTP请求和响应,而不需要等待前一个请求完成。这解决了HTTP1.1中的队头阻塞问题,提高了性能。
HTTP2.0 还引入了头部压缩(Header Compression)和服务器推送(Server Push)等功能,进一步优化了性能。

关键升级:
二进制分帧

  • 优先级
  • 多路复用
  • 流式传输

头部压缩
服务器推送(已过时)


关键性能卡点:在TCP 层仍然存在队头阻塞问题,因为当一个请求的分帧包丢了,就要等这个包完成重传才能一起提交给浏览器。只是从应用层上解决了并发问题,但是还是受到单个TCP链接的底层限制。

HTTP 3.0

HTTP3.0 协议引入了基于QUIC协议的传输机制,使用UDP协议代替TCP协议进行数据传输,从而解决了TCP协议中的队头阻塞问题,提高了性能和安全性。(了解即可)

GET 方法和 POST 方法区别

GET

  • GET 是用来请求数据的

  • GET 方法具有幂等性(不会影响服务器中的资源)

  • GET 通常情况下把参数写在URL里

  • GET 请求的数据会被保存在浏览器的历史记录中,也可以保存在CDN中

POST

  • POST 是用来传输数据的

  • POST 方法不具有幂等性(可能会影响服务器中的资源)

  • POST 一般方法把参数写在请求体里

  • POST 请求的数据不会被保存,而是直接打到服务器

误区:
GET 和 POST 实际上都可以把参数写在URL里或者请求体里,这不是核心差异。
GET 和 POST 都不保证安全,需要靠 HTTPS 的 TLS 协议完成加密才有安全性可言。
POST 方法传递参数的实际大小可能会受到服务器端的限制。如 Nignx 服务最高只支持 1MB 的请求体。

WebSocket

WebSocket 是一种在单个TCP连接上进行全双工通信的协议。它允许客户端和服务器之间进行实时数据交换,适用于需要频繁更新数据的应用,如在线聊天、实时游戏等。

  • 建立在 HTTP 之上(通过 Upgrade 升级)

  • 长连接(区别轮询)

  • 低延迟(无重复握手)

WebSocket 握手过程(重点)

流程:

  • 客户端发 HTTP 请求(带 Upgrade)
  • 服务端返回 101 Switching Protocols
  • 升级为 WebSocket 连接
1
2
3
4
5
6
👉 关键请求头:

Upgrade: websocket /*告诉服务器,我想升级为websocket*/
Connection: Upgrade /*用于升级协议*/
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==(base64编码的一组随机元素)
Sec-WebSocket-Version

升级完成后就和 HTTP 协议没关系了。

有了HTTP2,为什么还需要 WebSocket

虽然 HTTP2 也完成了所谓的“全双工”通信和“服务器推”,但是服务器并不能主动向客户端发送消息,必须等到客户端先发起请求之后才能响应,这就导致了服务器无法主动推送消息的情况。而 WebSocket 则允许服务器在任何时候主动向客户端发送消息,实现真正的全双工通信。

服务器推:服务器在响应请求时,顺便把你“可能会用到的资源”提前发给你。Server Push 本质是“资源优化”,不是“通信机制”

DNS服务器用的是什么协议

UDP协议

DNS 查询通常情况下都是一些小的数据包,我们需要保证 DNS 查询的速度。TCP 维护链接状态和频繁的握手、挥手(不同DNS服务器之间查询)会造成很大的性能开销。

ping命令 用的是什么协议?在哪一层?

ping命令用的是ICMP(网际控制报文)协议,是网络层协议

能详细讲一下有限状态机怎么解析http报文吗

HTTP 报文可以分为:请求行请求头空行内容体 四大块内容

那我们就可以根据:空格回车换行空行来做不同状态的转变。

做一个简单的状态机:

  • 解析前:STATE_BEGIN

  • 解析请求行:STATE_REQUEST_LINE

  • 解析请求头:STATE_HEAD_LINE

  • 请求头解析结束:STATE_HEAD_DONE

  • 解析内容体:STATE_CONTENT

  • 解析结束:STATE_DONE

  • 错误状态:STATE_ERROR

其中 解析请求行 和 解析请求头 还可以根据空格和冒号的存在做更细致的 划分

假设我们收到了一个POST请求如下:

1
2
3
4
5
POST /login HTTP/1.1\r\n
Host: www.example.com\r\n
Content-Length: 5
\r\n
hello

那么解析过程:

  1. 起始状态:STATE_BEGIN读取第一个字符 P 进入 STATE_REQUEST_LINE 状态

程序从缓冲区一个字符一个字符读:

P O S T / l o g i n H T T P / 1 . 1 \r \n

当读到 \r\n,说明请求行结束。

然后把这一行拆成三部分:

  1. method = POST
  2. path = /login
  3. version = HTTP/1.1

如果这一行不满足“三段结构”,就进入错误状态 STATE_ERROR

  1. 解析请求头:由 \r\n 触发到 STATE_HEAD_LINE 状态

以此类推。

如果解析http请求的时候,用户一次性没传完数据,(如果头部都没传完,请求报文长度字段都没传完,怎么办)

在解析 HTTP 请求时,如果数据没有接收完整,比如请求头还没结束或者 Content-Length 还没读取完整,解析器 不会进行错误处理,而是保留当前解析状态和缓冲区内容。等下一批数据到达后,再从当前状态继续解析。这种方式依赖有限状态机来记录解析进度,可以正确处理 TCP 的半包和粘包问题。

网络层协议

路由表

路由表是网络设备(如路由器)用来决定数据包转发路径的数据结构。它包含了目的地址、下一跳地址、接口等信息。当一个数据包到达路由器时,路由器会根据目的地址在路由表中查找匹配的条目,并根据下一跳地址将数据包转发到下一个设备。

未完待续

路由表为空怎么找到下一跳

当路由表为空时,路由器无法找到匹配的条目来转发数据包,这时会根据默认路由(Default Route)来处理。默认路由是一个特殊的路由条目,通常指向一个网关地址。当没有其他匹配的路由条目时,数据包会被转发到默认网关,由网关负责进一步处理和转发数据包。

未完待续

查看网络状况(ping、Traceroute)

ping 是运行在应用层,但是是基于网络层的ICMP协议的。
Traceroute 就直接工作在网络层

抓包工具

Fiddler,wireshark