TCP 通信全流程:服务器与客户端
一、 通信流程总览:像“打电话”一样简单
我们可以把 TCP 通信比作一次传统的电话服务:
-
服务器(接线员):
- 装个电话机 (
socket)。 - 申请一个固定电话号码 (
bind)。 - 把电话线插好,确保能听到铃声 (
listen)。 - 电话响了,接起来 (
accept)。 - 开始聊天 (
read/write)。 - 挂断 (
close)。
- 装个电话机 (
-
客户端(拨打者):
- 装个电话机 (
socket)。 - 不需要申请固定号码(系统自动分配临时号码)。
- 拨打服务器的电话号码 (
connect)。 - 开始聊天 (
read/write)。 - 挂断 (
close)。
- 装个电话机 (
二、 流程深度对比
1. 服务器端:六步走(重在“等”)
服务器的核心任务是等待。它有两个关键的文件描述符:
- 监听描述符 (lfd):仅用于检测有没有人打电话进来。
- 通信描述符 (cfd):当电话接通后,产生一个新的 fd 专门用来通话。
流程:
socket(): 创建监听 fd。bind(): 绑定本地 IP+端口(必须做,否则客户端找不到)。listen(): 开启监听模式。accept(): 阻塞等待,直到连接建立,返回 cfd。read/write(): 使用 cfd 通信。close(): 关闭 cfd(结束通话)或 lfd(关停服务)。
2. 客户端:四步走(重在“连”)
客户端的核心任务是发起。它只需要一个文件描述符。
流程:
socket(): 创建通信 fd。connect(): 主动连接服务器的 IP+端口。- 注:这里替代了服务器端的 bind+listen+accept 复杂过程。
read/write(): 数据收发。close(): 关闭 fd。
三、 代码实战:完整的问候系统
我们来实现一个简单的业务:客户端发送自己的名字,服务器回复 “Hello, [名字]”。
1. 服务器端代码 (server.c)
#include
#include
#include
#include
int main() {
// 1. 创建监听套接字
int lfd = socket(AF_INET, SOCK_STREAM, 0);
// 2. 绑定地址
struct sockaddr_in addr;
addr.sin_family = AF_IN









