HTTP、TCP 和 WebSocket
一、OSI 七层模型和 TCP/IP 模型
1. OSI 七层模型
| 层 | 名称 | 功能 | 协议示例 |
|---|---|---|---|
| 7 | 应用层 | 用户接口 | HTTP、FTP、SMTP |
| 6 | 表示层 | 数据格式转换 | SSL、TLS |
| 5 | 会话层 | 会话管理 | SQL、RPC |
| 4 | 传输层 | 端到端通信 | TCP、UDP |
| 3 | 网络层 | 路由转发 | IP、ICMP |
| 2 | 数据链路层 | 帧传输 | Ethernet、PPP |
| 1 | 物理层 | 比特流传输 | 双绞线、光纤 |
2. TCP/IP 四层模型
| 层 | 对应 OSI | 功能 | 协议 |
|---|---|---|---|
| 应用层 | 5-7 | 应用程序接口 | HTTP、FTP、DNS |
| 传输层 | 4 | 端到端通信 | TCP、UDP |
| 网络层 | 3 | IP 寻址和路由 | IP、ICMP |
| 网络接口层 | 1-2 | 物理和数据链路 | Ethernet |
二、TCP(传输控制协议)
1. TCP 的特点
✅ 面向连接 - 建立连接后才能通信
✅ 可靠传输 - 保证数据不丢失、不重复、有序到达
✅ 全双工通信 - 双向数据传输
✅ 流量控制 - 通过滑动窗口控制发送速度
✅ 拥塞控制 - 根据网络状况调整发送速率
2. TCP 三次握手
建立连接过程:
客户端 服务端
| |
|----SYN(seq=x)--------------->|
| | 进入 SYN_RCVD
|<--SYN+ACK(seq=y, ack=x+1)----|
| | 进入 ESTABLISHED
|----ACK(ack=y+1)-------------->|
| |
进入 ESTABLISHED |详细说明:
- 第一次握手:客户端发送 SYN(seq=x)到服务端,客户端进入 SYN_SENT
- 第二次握手:服务端发送 SYN+ACK(seq=y, ack=x+1)到客户端,服务端进入 SYN_RCVD
- 第三次握手:客户端发送 ACK(ack=y+1)到服务端,双方进入 ESTABLISHED
为什么需要三次握手?
- 防止旧的连接请求到达服务端(序列号验证)
- 确保双方都能发送和接收数据(确认双方的发送和接收能力)
- 同步初始序列号
3. TCP 四次挥手
断开连接过程:
客户端 服务端
| |
|----FIN(seq=x)--------------->|
| | 进入 CLOSE_WAIT
|<--ACK(ack=x+1)---------------|
| |
|<--FIN(seq=y)-----------------|
| | 进入 LAST_ACK
|----ACK(ack=y+1)-------------->|
| | 进入 CLOSED
进入 TIME_WAIT |
等待 2MSL |
进入 CLOSED |为什么需要四次挥手?
- 全双工通信,需要分别关闭发送和接收通道
- 客户端发送 FIN,服务端可能还有数据要发送
- 服务端发送完数据后再发送 FIN
TIME_WAIT 的作用?
- 确保最后的 ACK 到达服务端(如果丢失,服务端会重发 FIN)
- 防止旧连接的包影响新连接
- 等待时间通常是 2MSL(Maximum Segment Lifetime)
4. TCP 可靠传输机制
1. 确认应答(ACK)
- 接收方收到数据后发送 ACK 确认
- 序列号用于保证数据有序
2. 超时重传
- 发送方等待 ACK 超时后重传数据
- 超时时间根据网络状况动态调整
3. 滑动窗口
- 允许发送方连续发送多个数据包,无需等待每个 ACK
- 接收方通过窗口大小控制发送方的发送速度
4. 拥塞控制
- 慢启动 - 初始拥塞窗口较小,指数增长
- 拥塞避免 - 达到阈值后线性增长
- 快速重传 - 收到 3 个重复 ACK 后立即重传
- 快速恢复 - 快速重传后进入恢复阶段
5. TCP vs UDP
| 特性 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接 | 无连接 |
| 可靠性 | 可靠 | 不可靠 |
| 有序性 | 有序 | 无序 |
| 速度 | 较慢 | 较快 |
| 开销 | 较大 | 较小 |
| 应用场景 | HTTP、FTP、SMTP | DNS、视频流、游戏 |
三、HTTP(超文本传输协议)
1. HTTP 的特点
- 无状态 - 每个请求独立,不保存状态
- 请求-响应模式 - 客户端发送请求,服务端返回响应
- 基于 TCP - HTTP 运行在 TCP 之上
- 明文传输 - 默认不加密(HTTPS 加密)
2. HTTP 请求结构
GET /api/users HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Accept: application/json
Content-Type: application/json
请求体(可选)请求行:
- 方法:GET、POST、PUT、DELETE 等
- URL:请求的资源路径
- 版本:HTTP/1.1、HTTP/2
请求头:
- Host:服务器域名
- User-Agent:客户端信息
- Accept:接受的响应类型
- Content-Type:请求体类型
3. HTTP 响应结构
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 123
Date: Wed, 21 Oct 2025 12:00:00 GMT
响应体状态行:
- 版本:HTTP/1.1
- 状态码:200、404、500 等
- 状态文本:OK、Not Found、Internal Server Error
4. HTTP 方法
| 方法 | 说明 | 幂等性 | 安全性 |
|---|---|---|---|
| GET | 获取资源 | ✅ | ✅ |
| POST | 创建资源 | ❌ | ❌ |
| PUT | 更新资源(全量) | ✅ | ❌ |
| PATCH | 更新资源(部分) | ❌ | ❌ |
| DELETE | 删除资源 | ✅ | ❌ |
| HEAD | 获取响应头 | ✅ | ✅ |
| OPTIONS | 获取支持的方法 | ✅ | ✅ |
5. HTTP 状态码
1xx - 信息性
- 100 Continue - 继续
- 101 Switching Protocols - 切换协议
2xx - 成功
- 200 OK - 成功
- 201 Created - 已创建
- 204 No Content - 无内容
3xx - 重定向
- 301 Moved Permanently - 永久重定向
- 302 Found - 临时重定向
- 304 Not Modified - 未修改(缓存)
4xx - 客户端错误
- 400 Bad Request - 错误请求
- 401 Unauthorized - 未授权
- 403 Forbidden - 禁止访问
- 404 Not Found - 未找到
- 409 Conflict - 冲突
5xx - 服务器错误
- 500 Internal Server Error - 服务器内部错误
- 502 Bad Gateway - 网关错误
- 503 Service Unavailable - 服务不可用
6. HTTP/1.1 vs HTTP/2
| 特性 | HTTP/1.1 | HTTP/2 |
|---|---|---|
| 多路复用 | ❌ | ✅ |
| 头部压缩 | ❌ | ✅ |
| 服务器推送 | ❌ | ✅ |
| 二进制分帧 | ❌ | ✅ |
| 请求管道化 | ✅(有限) | ✅(真正) |
HTTP/2 优势:
- 多路复用 - 一个连接可以同时处理多个请求
- 头部压缩 - 使用 HPACK 压缩头部
- 服务器推送 - 服务器可以主动推送资源
- 二进制分帧 - 更高效的解析
7. HTTPS(安全超文本传输协议)
HTTPS = HTTP + SSL/TLS
加密过程:
- 客户端请求 HTTPS 连接
- 服务器返回证书(包含公钥)
- 客户端验证证书
- 客户端生成对称加密密钥,用公钥加密后发送给服务器
- 服务器用私钥解密,获得对称密钥
- 后续通信使用对称加密
SSL/TLS 握手过程:
- Client Hello - 客户端发送支持的加密套件
- Server Hello - 服务器选择加密套件并返回证书
- Client Key Exchange - 客户端生成并加密会话密钥
- Change Cipher Spec - 切换到加密通信
8. HTTP 常见面试题
Q1: GET 和 POST 的区别?
| 特性 | GET | POST |
|---|---|---|
| 参数位置 | URL 查询字符串 | 请求体 |
| 参数长度限制 | 有限(URL 长度限制) | 无限制 |
| 安全性 | 参数暴露在 URL | 相对安全 |
| 缓存 | 可缓存 | 通常不缓存 |
| 幂等性 | ✅ | ❌ |
| 使用场景 | 查询数据 | 创建/修改数据 |
Q2: Cookie 和 Session 的区别?
| 特性 | Cookie | Session |
|---|---|---|
| 存储位置 | 客户端 | 服务端 |
| 安全性 | 较低(可能被窃取) | 较高 |
| 存储大小 | 有限(4KB) | 无限制 |
| 性能 | 每次请求都携带 | 需要服务端存储 |
Q3: HTTP 缓存机制?
- 强缓存 - Cache-Control、Expires
- 协商缓存 - ETag、Last-Modified
http
# 强缓存
Cache-Control: max-age=3600
Expires: Wed, 21 Oct 2025 13:00:00 GMT
# 协商缓存
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Last-Modified: Wed, 21 Oct 2025 12:00:00 GMT四、WebSocket(Web 套接字)
1. WebSocket 的特点
✅ 全双工通信 - 客户端和服务器可以同时发送数据
✅ 持久连接 - 建立连接后保持打开状态
✅ 低延迟 - 无需每次发送 HTTP 请求头
✅ 服务器推送 - 服务器可以主动向客户端推送数据
✅ 跨域友好 - 通过 Origin 头部验证来源
2. WebSocket vs HTTP
| 特性 | WebSocket | HTTP |
|---|---|---|
| 连接方式 | 持久连接 | 请求-响应后断开 |
| 通信方式 | 全双工 | 半双工 |
| 协议开销 | 小(只有数据帧) | 大(每次都有头部) |
| 服务器推送 | ✅ 支持 | ❌ 不支持(需要轮询) |
| 使用场景 | 实时通信、游戏 | REST API、网页 |
3. WebSocket 握手过程
客户端请求:
http
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Origin: http://example.com服务器响应:
http
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=握手后:
- 连接升级为 WebSocket 协议
- 使用二进制帧进行通信
- 不再使用 HTTP 协议
4. WebSocket 帧结构
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+-------------------------------+关键字段:
- FIN - 是否最后一帧
- Opcode - 操作码(文本、二进制、关闭等)
- Mask - 是否掩码(客户端必须掩码)
- Payload length - 数据长度
5. .NET Core 中的 WebSocket 实现
服务端:
csharp
// Program.cs
app.UseWebSockets();
app.Map("/ws", async context =>
{
if (context.WebSockets.IsWebSocketRequest)
{
var webSocket = await context.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
context.Response.StatusCode = 400;
}
});
async Task Echo(WebSocket webSocket)
{
var buffer = new byte[1024 * 4];
while (webSocket.State == WebSocketState.Open)
{
var result = await webSocket.ReceiveAsync(
new ArraySegment<byte>(buffer),
CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Text)
{
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
// 处理消息
var echo = $"Echo: {message}";
await webSocket.SendAsync(
new ArraySegment<byte>(Encoding.UTF8.GetBytes(echo)),
WebSocketMessageType.Text,
true,
CancellationToken.None);
}
else if (result.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(
WebSocketCloseStatus.NormalClosure,
"Close received",
CancellationToken.None);
}
}
}客户端(JavaScript):
javascript
const ws = new WebSocket('ws://localhost:5000/ws');
ws.onopen = () => {
console.log('连接已建立');
ws.send('Hello Server');
};
ws.onmessage = (event) => {
console.log('收到消息:', event.data);
};
ws.onerror = (error) => {
console.error('错误:', error);
};
ws.onclose = () => {
console.log('连接已关闭');
};6. SignalR(ASP.NET Core)
SignalR 是 ASP.NET Core 提供的实时通信框架,基于 WebSocket,并提供降级方案。
服务端:
csharp
// Hub
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
public async Task JoinRoom(string roomName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, roomName);
}
public async Task SendToRoom(string roomName, string message)
{
await Clients.Group(roomName).SendAsync("ReceiveMessage", message);
}
}
// Program.cs
builder.Services.AddSignalR();
app.MapHub<ChatHub>("/chathub");客户端:
javascript
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.build();
connection.on("ReceiveMessage", (user, message) => {
console.log(`${user}: ${message}`);
});
connection.start().then(() => {
connection.invoke("SendMessage", "Alice", "Hello");
});7. WebSocket 常见面试题
Q1: WebSocket 和 HTTP 长轮询的区别?
| 特性 | WebSocket | HTTP 长轮询 |
|---|---|---|
| 连接 | 持久连接 | 每次请求保持一段时间 |
| 服务器推送 | ✅ 实时 | ⚠️ 伪推送(延迟) |
| 开销 | 小 | 大(每次都有 HTTP 头) |
| 实现复杂度 | 中等 | 简单 |
Q2: WebSocket 如何保持连接?
- 使用心跳机制(Ping/Pong)
- 定期发送 Ping 帧,接收方响应 Pong 帧
- 如果长时间没有收到响应,关闭连接
csharp
// 心跳检测
_ = Task.Run(async () =>
{
while (webSocket.State == WebSocketState.Open)
{
await Task.Delay(30000); // 30秒
await webSocket.SendAsync(
new ArraySegment<byte>(new byte[] { 0x9, 0x0 }), // Ping 帧
WebSocketMessageType.Text,
true,
CancellationToken.None);
}
});Q3: WebSocket 的安全性如何保证?
- 使用 WSS(WebSocket Secure)协议(基于 TLS)
- 验证 Origin 头部,防止跨站请求伪造
- 使用认证 Token 验证用户身份
- 实现速率限制,防止 DoS 攻击
五、应用场景
1. HTTP/HTTPS 使用场景
- RESTful API - 标准 HTTP 方法进行资源操作
- Web 页面 - 获取 HTML、CSS、JavaScript
- 文件传输 - 上传下载文件
- 微服务通信 - 服务间 HTTP 调用
2. TCP 使用场景
- HTTP/HTTPS - 运行在 TCP 之上
- 数据库连接 - MySQL、PostgreSQL 等
- 邮件传输 - SMTP、POP3、IMAP
- 文件传输 - FTP
3. WebSocket 使用场景
- 实时聊天 - 即时通讯应用
- 在线游戏 - 实时游戏状态同步
- 股票行情 - 实时价格推送
- 协作工具 - 多人同时编辑
- 监控大屏 - 实时数据展示
- 在线教育 - 实时互动
六、性能优化建议
1. HTTP 优化
- ✅ 使用 HTTP/2 或 HTTP/3
- ✅ 启用 Gzip/Brotli 压缩
- ✅ 使用 CDN 加速静态资源
- ✅ 合理使用缓存(强缓存 + 协商缓存)
- ✅ 合并请求,减少连接数(HTTP/1.1)
- ✅ 使用 Keep-Alive 保持连接
2. TCP 优化
- ✅ 调整 TCP 窗口大小
- ✅ 启用 TCP_NODELAY(禁用 Nagle 算法)
- ✅ 使用连接池复用连接
- ✅ 监控网络延迟和丢包率
3. WebSocket 优化
- ✅ 实现心跳机制保持连接
- ✅ 使用二进制格式减少数据大小
- ✅ 实现消息队列,防止消息丢失
- ✅ 使用负载均衡(支持 WebSocket 的负载均衡器)
- ✅ 监控连接数,防止资源耗尽