计算机网络
网络OSI模型和TCP/IP模型
OSI 七层模型 是国际标准化组织提出的一个网络分层模型
每一层都专注做一件事情,并且每一层都需要使用下一层提供的功能比如传输层需要使用网络层提供的路由和寻址功能,这样传输层才知道把数据传输到哪里去。
OSI 的七层体系结构概念清楚,理论也很完整,但是它比较复杂而且不实用,而且有些功能在多个层中重复出现。
为什么网络要分层?
- 各层之间相互独立:各层之间相互独立,各层之间不需要关心其他层是如何实现的,只需要知道自己如何调用下层提供好的功能就可以了(可以简单理解为接口调用)。这个和我们对开发时系统进行分层是一个道理。
- 提高了灵活性和可替换性:每一层都可以使用最适合的技术来实现,你只需要保证你提供的功能以及暴露的接口的规则没有改变就行了。并且,每一层都可以根据需要进行修改或替换,而不会影响到整个网络的结构。这个和我们平时开发系统的时候要求的高内聚、低耦合的原则也是可以对应上的。
- 大问题化小:分层可以将复杂的网络问题分解为许多比较小的、界线比较清晰简单的小问题来处理和解决。这样使得复杂的计算机网络系统变得易于设计,实现和标准化。 这个和我们平时开发的时候,一般会将系统功能分解,然后将复杂的问题分解为容易理解的更小的问题是相对应的,这些较小的问题具有更好的边界(目标和接口)定义。
而osi模型非常繁琐 所以现代我们用的都是tcp/ip模型
TCP/IP 四层模型 是目前被广泛采用的一种模型,我们可以将 TCP / IP 模型看作是 OSI 七层模型的精简版本,由以下 4 层组成:
- 应用层
- 传输层
- 网络层
- 网络接口层
网络协议
应用层
HTTP(Hypertext Transfer Protocol,超文本传输协议):基于 TCP 协议,是一种用于传输超文本和多媒体内容的协议,主要是为 Web 浏览器与 Web 服务器之间的通信而设计的。当我们使用浏览器浏览网页的时候,我们网页就是通过 HTTP 请求进行加载的。
传输层 TCP VS UDP
一、什么是 TCP?
TCP(Transmission Control Protocol) 是一种面向连接的、可靠的传输协议。它在发送数据之前必须先建立连接,这一过程称为“三次握手”。数据在传输过程中经过确认应答机制、重传机制和排序机制,确保数据完整、按顺序地送达接收端。
TCP 的几个关键特性包括:
- 面向连接:传输数据前先建立连接
- 可靠传输:有重传、应答、校验等机制保障可靠性
- 有序性:接收方按发送顺序接收数据
- 拥塞控制和流量控制:防止网络拥塞
二、什么是 UDP?
UDP(User Datagram Protocol) 是一种无连接的、不可靠的传输协议。它不建立连接,数据直接发出,不确认是否到达。虽然它不保证数据的顺序与完整性,但正因为简洁,传输效率非常高,常用于对实时性要求高的应用。
UDP 的关键特性:
- 无连接:无需建立连接即可发送数据
- 不保证可靠性:不确认、不重传
- 不保证顺序:数据包可能乱序到达
- 传输快,资源消耗小,适合高并发
三、TCP 与 UDP 的全面对比
对比维度 | TCP | UDP |
---|---|---|
是否连接 | 面向连接(三次握手) | 无连接 |
是否可靠 | 可靠(确认+重传) | 不可靠(尽力而为) |
顺序保证 | 有序传输 | 无序传输 |
传输效率 | 较低 | 高 |
开销 | 大(20字节以上) | 小(8字节) |
是否拥塞控制 | 有 | 无 |
适合场景 | 文件传输、HTTP、数据库等 | 视频直播、语音通话、DNS等 |
- TCP 更可靠、更稳定,但速度稍慢,适合需要数据完整性的场景。
- UDP 更轻便、更快速,但不保证可靠性,适合实时性强的应用。
在实际开发中,我们应根据业务需求来选择合适的协议。例如,做一个聊天室服务时,如果追求消息的准确性与顺序,就选 TCP;如果做语音通话,优先保证实时响应,那 UDP 就更合适。
TCP三次握手 四次挥手
建立一个 TCP 连接需要“三次握手”,缺一不可:
- 一次握手:客户端发送带有 SYN(SEQ=x) 标志的数据包 -> 服务端,然后客户端进入 SYN_SEND 状态,等待服务端的确认;
- 二次握手:服务端发送带有 SYN+ACK(SEQ=y,ACK=x+1) 标志的数据包 –> 客户端,然后服务端进入 SYN_RECV 状态;
- 三次握手:客户端发送带有 ACK(ACK=y+1) 标志的数据包 –> 服务端,然后客户端和服务端都进入ESTABLISHED 状态,完成 TCP 三次握手。
在 TCP 三次握手过程中,Linux 内核会维护两个队列来管理连接请求:
- 半连接队列(也称 SYN Queue):当服务端收到客户端的 SYN 请求时,此时双方还没有完全建立连接,它会把半连接状态的连接放在半连接队列。
- 全连接队列(也称 Accept Queue):当服务端收到客户端对 ACK 响应时,意味着三次握手成功完成,服务端会将该连接从半连接队列移动到全连接队列。如果未收到客户端的 ACK 响应,会进行重传,重传的等待时间通常是指数增长的。如果重传次数超过系统规定的最大重传次数,系统将从半连接队列中删除该连接信息。
三次握手的必要性
三次握手的目的是建立可靠的通信信道,说到通讯,简单来说就是数据的发送与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的。
- 第一次握手:Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常
- 第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:对方发送正常,自己接收正常
- 第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常
三次握手就能确认双方收发功能都正常,缺一不可。
断开连接—四次挥手
- 第一次挥手:客户端发送一个 FIN(SEQ=x) 标志的数据包->服务端,用来关闭客户端到服务端的数据传送。然后客户端进入 FIN-WAIT-1 状态。
- 第二次挥手:服务端收到这个 FIN(SEQ=X) 标志的数据包,它发送一个 ACK (ACK=x+1)标志的数据包->客户端 。然后服务端进入 CLOSE-WAIT 状态,客户端进入 FIN-WAIT-2 状态。
- 第三次挥手:服务端发送一个 FIN (SEQ=y)标志的数据包->客户端,请求关闭连接,然后服务端进入 LAST-ACK 状态。
- 第四次挥手:客户端发送 ACK (ACK=y+1)标志的数据包->服务端,然后客户端进入TIME-WAIT状态,服务端在收到 ACK (ACK=y+1)标志的数据包后进入 CLOSE 状态。此时如果客户端等待 2MSL 后依然没有收到回复,就证明服务端已正常关闭,随后客户端也可以关闭连接了。
为什么不能把服务端发送的 ACK 和 FIN 合并起来,变成三次挥手?
因为服务端收到客户端断开连接的请求时,可能还有一些数据没有发完,这时先回复 ACK,表示接收到了断开连接的请求。等到数据发完之后再发 FIN,断开服务端到客户端的数据传送。
为什么不能“两次握手”?
两次握手可能出现的问题:“已失效的连接请求再次被接受”
设想情景:
- 客户端发送一个 SYN 请求后因网络延迟未响应,超时重试,与服务端建立新连接成功;
- 旧的 SYN 数据包后来又抵达服务端,服务端误以为是新的连接请求,建立了无效连接;
这将导致:
- 服务端为不存在的连接分配资源;
- 引发伪连接(半开连接),浪费系统资源甚至被攻击(SYN Flood)
第三次握手的作用:客户端确认服务端的确认
客户端必须再次确认,服务端返回的 ACK 是对自己发送的 SYN 的回应,确保连接是有效的、双方都正常通信。
三次挥手会出现的问题:服务端数据还没发完,连接就被断了
如果你尝试用三次挥手:
- 客户端发送 FIN
- 服务端回复 ACK + FIN
- 客户端回复 ACK
这种情况下服务端未必发完数据,或者客户端未必确认收到,容易导致数据丢失或未完整传输
TCP 是一个为稳定通信设计的复杂协议,它在每一个步骤中都追求“可靠传输 + 高效利用资源”,三次握手与四次挥手正是这个理念的最佳体现。
字段 | 含义 |
---|---|
FIN | “Finish”,表示“我已经没有数据要发送了”,请求关闭连接 |
SEQ | Sequence Number,序列号,用来标记当前这段数据的顺序位置 |
ACK | Acknowledgment Number,确认号,表示“我期望接收的下一个 SEQ 编号” |