一、TCP通信基础原理
1.1 通信流程概述
TCP通信采用客户端-服务器模型,核心流程如下:
服务器端:
-
创建套接字(Socket)
-
绑定地址和端口(Bind)
-
开始监听(Listen)
-
接受连接(Accept)
-
数据交互(Send/Recv)
-
关闭连接(Close)
客户端:
-
创建套接字(Socket)
-
连接服务器(Connect)
-
数据交互(Send/Recv)
-
关闭连接(Close)
1.2 网络字节序
使用htonl()、htons()等函数处理端口和地址转换,保证不同架构设备间的兼容性。
二、服务器端实现
2.1 完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int server_fd, client_fd;
struct sockaddr_in address;
int opt = 1;
socklen_t addrlen = sizeof(address);
char buffer[BUFFER_SIZE];
// 创建TCP套接字
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 设置套接字选项
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 绑定地址
if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 开始监听
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", PORT);
// 接受连接
if ((client_fd = accept(server_fd, (struct sockaddr*)&address, &addrlen)) < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
// 接收数据
ssize_t bytes_read = recv(client_fd, buffer, BUFFER_SIZE, 0);
if (bytes_read > 0) {
buffer[bytes_read] = '\0';
printf("Received: %s\n", buffer);
// 发送响应
const char* response = "Message received";
send(client_fd, response, strlen(response), 0);
}
close(client_fd);
close(server_fd);
return 0;
}
2.2 关键代码解析
-
套接字创建:
socket(AF_INET, SOCK_STREAM, 0)
-
AF_INET:IPv4协议 -
SOCK_STREAM:TCP协议类型
-
-
地址重用选项:
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))
避免"Address already in use"错误
-
绑定地址:
bind(server_fd, (struct sockaddr*)&address, sizeof(address))
-
INADDR_ANY表示绑定所有网络接口
-
三、客户端实现
3.1 完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define SERVER_IP "127.0.0.1"
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int sock;
struct sockaddr_in serv_addr;
char buffer[BUFFER_SIZE];
// 创建套接字
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// 转换IP地址
if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {
perror("invalid address");
exit(EXIT_FAILURE);
}
// 连接服务器
if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("connection failed");
exit(EXIT_FAILURE);
}
// 发送数据
const char* message = "Hello Server!";
send(sock, message, strlen(message), 0);
printf("Sent: %s\n", message);
// 接收响应
ssize_t bytes_received = recv(sock, buffer, BUFFER_SIZE, 0);
if (bytes_received > 0) {
buffer[bytes_received] = '\0';
printf("Response: %s\n", buffer);
}
close(sock);
return 0;
}
3.2 关键代码解析
-
地址转换:
inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr)
将点分十进制IP转换为二进制格式
-
连接超时处理:
实际项目中建议添加超时设置:struct timeval timeout = {5, 0}; // 5秒超时 setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
四、编译与测试
4.1 编译方法
# 编译服务器 gcc server.c -o server # 编译客户端 gcc client.c -o client
4.2 运行测试
# 服务器端 ./server # 客户端(另启终端) ./client
4.3 预期输出
服务器端:
Server listening on port 8080... Received: Hello Server!
客户端:
Sent: Hello Server! Response: Message received
五、进阶开发指南
5.1 多客户端支持
使用多线程处理并发连接:
#include <pthread.h>
void* client_handler(void* arg) {
int client_fd = *(int*)arg;
// 处理客户端请求
close(client_fd);
pthread_exit(NULL);
}
// 在accept循环中
while(1) {
int client_fd = accept(...);
pthread_t thread;
pthread_create(&thread, NULL, client_handler, &client_fd);
pthread_detach(thread);
}
5.2 数据完整性保障
-
添加包头校验:
struct packet_header {
uint32_t magic; // 固定标识 0xDEADBEEF
uint32_t length; // 数据长度
uint16_t checksum; // CRC校验
};
-
使用循环接收确保完整数据:
size_t total_received = 0;
while(total_received < expected_len) {
ssize_t n = recv(fd, buffer+total_received, expected_len-total_received, 0);
if(n <= 0) break;
total_received += n;
}
5.3 性能优化技巧
-
禁用Nagle算法:
int flag = 1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
-
调整缓冲区大小:
int buf_size = 1024 * 1024; // 1MB setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(int));
六、常见问题排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| Connection refused | 服务器未启动/端口未开放 | 检查服务状态和防火墙设置 |
| Address already in use | 端口被占用 | 设置SO_REUSEADDR选项 |
| 数据不完整 | 未处理部分发送/接收 | 使用循环发送接收逻辑 |
| 连接超时 | 网络不通/服务器无响应 | 使用telnet测试端口连通性 |
| 数据乱码 | 未正确处理字符串终止符 | 确保接收缓冲区添加'\0' |
七、扩展应用场景
-
文件传输工具:实现文件分块传输和校验
-
即时通讯系统:支持多用户文本消息传递
-
远程监控系统:实时传输传感器数据
-
分布式计算节点:任务分配与结果收集
通过本指南,开发者可以快速搭建基础的TCP通信测试环境,并根据实际需求进行功能扩展。建议结合Wireshark等网络分析工具进行协议级调试,以深入理解TCP通信机制。





















