C语言Socket TCP循环发送整型数组到服务器并回传的实现问题
核心问题说明
- TCP是字节流协议,
read()不保证一次返回你请求的完整字节长度,你当前代码直接用read(csock, values, sizeof(values))的返回值做判断,很可能出现粘包、半读的问题,拿到残缺的数组数据。 - 你客户端是死循环发送逻辑,永远不会主动断开连接,所以服务端的
read()不会收到EOF返回0,只有你手动关闭客户端进程时连接才会断开,服务端才能退出循环。 - 缺少服务端回传结果、客户端接收结果的逻辑,也没有约定传输结束的标识。
修正实现方案
我们约定通信规则:
- 客户端每次输入5个整数,发送给服务端
- 服务端收满完整的5个int后做排序/计算,再把结果回传给客户端
- 客户端输入
0 0 0 0 0时,主动关闭连接,触发服务端的EOF,服务端结束读取循环
修正后服务端代码
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> // 循环读取指定长度的字节,确保读满 int read_full(int fd, void *buf, size_t len) { size_t total = 0; ssize_t n; while (total < len) { n = read(fd, (char*)buf + total, len - total); if (n <= 0) return n; // 出错或者EOF total += n; } return total; } int main(int argc, char const *argv[]) { struct sockaddr_in server, client; int sock, csock, addressSize; bzero(&server, sizeof(server)); server.sin_family = PF_INET; server.sin_addr.s_addr = inet_addr("127.0.0.1"); server.sin_port = htons(5999); sock = socket(PF_INET, SOCK_STREAM, 0); bind(sock, (struct sockaddr*)&server, sizeof(server)); listen(sock, 5); addressSize = sizeof(client); csock = accept(sock, (struct sockaddr *)&client, &addressSize); int values[5]; int ret; while ((ret = read_full(csock, values, sizeof(values))) > 0) { // 排序逻辑示例:升序排序 for (int i = 0; i < 4; i++) { for (int j = 0; j < 4 - i; j++) { if (values[j] > values[j+1]) { int tmp = values[j]; values[j] = values[j+1]; values[j+1] = tmp; } } } // 打印接收到的原始数据 printf("接收到的数组: "); for (int i = 0; i < 5; i++) { printf("%d ", values[i]); } printf("\n"); // 把处理后的结果回传给客户端 write(csock, values, sizeof(values)); } close(csock); close(sock); return 0; }
修正后客户端代码
#include <stdio.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> // 循环读取指定长度的字节,确保读满 int read_full(int fd, void *buf, size_t len) { size_t total = 0; ssize_t n; while (total < len) { n = read(fd, (char*)buf + total, len - total); if (n <= 0) return n; total += n; } return total; } int main(int argc, char const *argv[]) { struct sockaddr_in server; int sock; bzero(&server, sizeof(server)); server.sin_family = PF_INET; server.sin_addr.s_addr = inet_addr("127.0.0.1"); server.sin_port = htons(5999); sock = socket(PF_INET, SOCK_STREAM, 0); connect(sock, (struct sockaddr *)&server, sizeof(server)); while (1) { int values[5] = {0}; printf("请输入5个整数(输入五个0退出): "); for (int i = 0; i < 5; i++) scanf("%d", &values[i]); // 输入五个0则退出,关闭连接触发服务端EOF int is_exit = 1; for (int i = 0; i <5; i++) { if (values[i] != 0) { is_exit = 0; break; } } if (is_exit) break; write(sock, values, sizeof(values)); // 等待接收服务端返回的处理结果 int res[5]; if (read_full(sock, res, sizeof(res)) <=0) break; printf("服务端返回的排序结果: "); for (int i =0; i<5; i++) { printf("%d ", res[i]); } printf("\n"); } close(sock); return 0; }
额外注意
如果你的程序需要跨不同字节序的平台运行,发送整数前需要先转成网络字节序htonl(),接收后转成本地字节序ntohl(),同架构本地测试不需要处理也能正常运行。
内容的提问来源于stack exchange,提问作者Bryce Chan
相关产品推荐
相关产品推荐

