1、网络基础与Socket概念:OSI七层模型、TCP/IP协议栈、Socket是什么、Socket通信流程
各位同学,咱们今天正式开课。做网络编程,尤其是Socket通信,很多人一上来就撸代码,结果遇到莫名其妙的问题——连不上、发乱码、收不全。说白了,底层概念没吃透。
我个人习惯,学任何网络技术,先看它站在哪一层。今天咱们就把地基打牢。
1.1 OSI七层模型——网络世界的分层哲学
OSI七层模型,全称“开放系统互连参考模型”。它是个理论框架,定义了网络通信应该怎么分层。你想想看,两个人打电话,从拨号到挂断,中间经历了多少环节?OSI就是把这些环节拆成了七层。
| 层级 | 名称 | 核心作用 | 常见协议/设备 |
|---|---|---|---|
| 7 | 应用层 | 为用户提供网络服务接口 | HTTP、FTP、SMTP |
| 6 | 表示层 | 数据格式转换、加密、压缩 | SSL/TLS、JPEG |
| 5 | 会话层 | 建立、管理、终止会话 | NetBIOS、RPC |
| 4 | 传输层 | 端到端可靠传输 | TCP、UDP |
| 3 | 网络层 | 路由寻址、分组转发 | IP、ICMP、路由器 |
| 2 | 数据链路层 | 帧封装、MAC寻址、差错检测 | 以太网、交换机 |
| 1 | 物理层 | 比特流传输、电气特性 | 网线、集线器、光纤 |
1.2 TCP/IP协议栈——工业界的“事实标准”
OSI七层模型太完美了,完美到没人能完全实现它。工业界用的是TCP/IP协议栈,它把七层压缩成了四层。嗯,这里要注意,TCP/IP不是TCP和IP的简单组合,而是一整套协议簇。
| TCP/IP四层模型 | 对应OSI层级 | 核心协议 |
|---|---|---|
| 应用层 | 5~7层(会话、表示、应用) | HTTP、DNS、SSH |
| 传输层 | 4层(传输层) | TCP、UDP |
| 网络层 | 3层(网络层) | IP、ICMP、ARP |
| 网络接口层 | 1~2层(物理、数据链路) | 以太网、Wi-Fi |
为什么会这样?因为OSI的会话层和表示层在实际应用中,功能被合并到了应用层协议里。比如HTTPS,加密(表示层功能)直接在应用层用SSL/TLS搞定,不需要单独一层。
1.3 Socket到底是什么?
很多教材把Socket翻译成“套接字”,听着挺玄乎。说白了,Socket就是一个文件描述符。
在Linux系统里,一切皆文件。网络连接也不例外。当你创建一个Socket时,操作系统返回给你一个整数(比如3、4、5),你往这个整数里写数据,数据就发出去了;你从这个整数里读数据,数据就接收到了。
ulimit -n。
Socket的完整定义:它是IP地址和端口号的组合,唯一标识了网络上的一个通信端点。
比如 192.168.1.100:8080 就是一个Socket。IP地址找到主机,端口号找到主机上的具体进程。
1.4 Socket通信流程——从建立到关闭
咱们以最经典的TCP Socket为例,走一遍完整流程。TCP是面向连接的、可靠的传输协议,它的通信流程可以用“三次握手”和“四次挥手”来概括。
1.5 核心步骤详解
咱们把流程拆开,一个一个说。
- socket() 创建套接字:告诉操作系统,我要用IPv4还是IPv6,用TCP还是UDP。返回一个文件描述符。
- bind() 绑定地址(服务端):把IP和端口号绑定到套接字上。不绑定的话,操作系统随机分配端口。
- listen() 监听(服务端):把主动套接字变成被动套接字,开始等待客户端连接。参数是最大等待队列长度。
- connect() 发起连接(客户端):客户端主动连接服务端。这里触发三次握手。
- accept() 接受连接(服务端):从等待队列里取出一个已完成三次握手的连接,返回一个新的套接字用于通信。
- send() / recv() 收发数据:通过套接字读写数据。TCP保证数据按序、不丢失到达。
- close() 关闭连接:释放资源。TCP四次挥手在这里发生。
1.6 一个最简单的TCP Socket代码示例
光说不练假把式。咱们看一段最精简的代码,感受一下流程。
// 服务端示例(伪代码风格,聚焦流程)
int server_fd = socket(AF_INET, SOCK_STREAM, 0); // 1. 创建
bind(server_fd, &addr, sizeof(addr)); // 2. 绑定
listen(server_fd, 5); // 3. 监听
while (1) {
int client_fd = accept(server_fd, NULL, NULL); // 4. 接受连接
char buffer[1024] = {0};
recv(client_fd, buffer, 1024, 0); // 5. 接收数据
printf("收到: %s\n", buffer);
send(client_fd, "OK", 2, 0); // 6. 发送响应
close(client_fd); // 7. 关闭连接
}
// 客户端示例
int sock = socket(AF_INET, SOCK_STREAM, 0); // 1. 创建
connect(sock, &addr, sizeof(addr)); // 2. 连接
send(sock, "Hello", 5, 0); // 3. 发送
recv(sock, buffer, 1024, 0); // 4. 接收
close(sock); // 5. 关闭
accept() 返回的 client_fd 用完一定要 close()。否则文件描述符泄漏,跑个几千个连接后,服务端就再也无法 accept 新连接了。嗯,线上故障就是这么来的。
1.7 本章小结
咱们这一章把网络基础捋了一遍。OSI七层模型是理论框架,TCP/IP四层是实战标准。Socket就是操作传输层的文件描述符。通信流程七个步骤:创建、绑定、监听、连接、接受、收发、关闭。
我个人觉得,理解Socket的关键不在于记住函数名,而在于脑子里有那张流程图。数据怎么从应用层一层层封装,穿过网线,再一层层解封装到对端应用层——这个画面感建立起来,后面学HTTP、WebSocket、epoll都会轻松很多。
man socket、man bind 看看手册。然后照着上面的代码敲一遍,用 telnet 或者 nc 连上去测试。亲手跑通一次,比看十遍书都管用。