You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言Socket TCP循环发送整型数组到服务器并回传的实现问题

核心问题说明

  • TCP是字节流协议,read() 不保证一次返回你请求的完整字节长度,你当前代码直接用read(csock, values, sizeof(values))的返回值做判断,很可能出现粘包、半读的问题,拿到残缺的数组数据。
  • 你客户端是死循环发送逻辑,永远不会主动断开连接,所以服务端的read()不会收到EOF返回0,只有你手动关闭客户端进程时连接才会断开,服务端才能退出循环。
  • 缺少服务端回传结果、客户端接收结果的逻辑,也没有约定传输结束的标识。

修正实现方案

我们约定通信规则:

  1. 客户端每次输入5个整数,发送给服务端
  2. 服务端收满完整的5个int后做排序/计算,再把结果回传给客户端
  3. 客户端输入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 01:18:03