TCP套接字通信核心要点
通信模型架构
客户端-服务端模型
- CS架构:客户端发起请求,服务端响应和处理请求
- 双向通道:建立连接后实现全双工通信
服务端搭建流程
核心步骤
-
创建套接字
int server = socket(AF_INET, SOCK_STREAM, 0);
- 参数说明:
AF_INET
(IPv4)、SOCK_STREAM
(TCP)、协议自动选择
- 参数说明:
-
绑定地址
struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(port), .sin_addr.s_addr = INADDR_ANY }; bind(server, (struct sockaddr*)&addr, sizeof(addr));
- 关键操作:字节序转换(
htons
)、IP绑定策略(INADDR_ANY
)
- 关键操作:字节序转换(
-
监听连接
listen(server, 10); // 监听队列长度=10
-
接受连接
int client = accept(server, (struct sockaddr*)&client_addr, &client_len);
- 获取客户端地址:
inet_ntop
转换IP,ntohs
转换端口
- 获取客户端地址:
-
数据交互
- 读取数据:
read()
或recv()
- 终止条件:返回值为0时表示客户端断开
- 读取数据:
客户端搭建流程
核心步骤
-
创建套接字
int client = socket(AF_INET, SOCK_STREAM, 0);
-
设置服务端地址
struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(server_port), .sin_addr.s_addr = inet_addr("192.168.1.1") };
-
建立连接
connect(client, (struct sockaddr*)&addr, sizeof(addr));
-
发送数据
write(client, buffer, sizeof(buffer));
协议包设计
结构体定义
typedef struct Pack {
int packsize; // 总字节数(含包头)
char buf[4096]; // 数据缓冲区
int used; // 已使用字节数
} pack_t;
关键操作
-
数据封装
void append(pack_t* pack, const char* str) { short len = strlen(str); *(short*)(pack->buf + pack->used) = len; // 写入长度 memcpy(pack->buf + pack->used + 2, str, len); // 写入内容 pack->used += (len + 2); pack->packsize = 4 + pack->used; // 更新总大小(含4字节包头) }
-
数据解析
char** analysis(pack_t* pack) { char* buf = pack->buf; char** list = calloc(20, 8); // 存储解析后的字段 int readed_size = 0; while (*(short*)(buf + readed_size) != 0) { short len = *(short*)(buf + readed_size); readed_size += 2; memcpy(temp, buf + readed_size, len); list[i++] = strdup(temp); // 动态分配存储 } return list; }
关键问题处理
粘包与拆包
- 粘包:多次发送的小数据包合并传输
- 拆包:大数据包拆分发送(如超过1500字节限制)
- 解决方案:协议包头声明数据长度,接收方按长度解析
连接管理
- 服务端维护:通过
accept()
返回的客户端描述符管理多个连接 - 异常断开检测:
read()
返回0时表示客户端主动关闭
代码实践要点
- 错误处理:检查
socket()/bind()/listen()/connect()
的返回值 - 资源释放:
close()
关闭套接字,free()
释放动态内存 - 字节序转换:端口号使用
htons/ntohs
,IP使用inet_ntop/pton
总结:TCP套接字通信围绕地址绑定、连接管理、协议设计展开,需掌握服务端/客户端搭建流程、粘包处理及协议包解析方法,结合错误处理实现稳定通信。