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

Linux下C语言服务器与客户端send()/recv()安全数据传输异常问题排查

Linux下C语言服务器与客户端send()/recv()安全数据传输异常问题排查

嘿,我看了你的问题和代码,首先得明确:你遇到的问题根本不是send/recv的flags能解决的——核心原因是你误解了TCP协议的特性,它是字节流协议,不是消息流协议,没法保证你send一次的数据,recv就能原封不动一次收到。

先给你拆解下问题出在哪:

  • 你服务器每次send 14字节的一行数据,但TCP会把这些字节当成连续的流来传输,客户端的recv可能一次只收到一部分(比如某次收了10字节,剩下4字节和下一行的前10字节粘在一起),也可能一次收到多行的内容。而你现在客户端每次循环只调用一次recv就直接把buffer当成完整一行处理,这自然会出现字符串移位、错乱的情况。
  • 另外,你还忽略了send的返回值——send不一定能把14字节全部发出去,比如当内核缓冲区满的时候,send只会发送一部分字节,剩下的需要你循环发送,否则数据就丢了。

为什么flags救不了你?

比如你可能想到用MSG_WAITALL flag让recv一直等到收到指定长度,但这个flag有局限性:如果连接中途断开、或者出现网络错误,它的行为可能不符合预期,而且不是所有系统都能完美支持,本质上还是绕开了字节流的问题,不是可靠的解决方案。

正确的解决思路:处理应用层消息边界

因为你的每行数据是固定14字节的,最适合的方案就是固定长度消息传输——不管send/recv分多少次,我们确保每次凑够完整的14字节再处理。

先改服务器端的send逻辑:

你原来直接调用send,没有处理部分发送的情况,改成循环send直到全部字节发送完成:

void signal_data_generator( int connfd ) {
    // ... 你的原有代码 ...
    str_line[13] = '\0';
    printf("%s\n", str_line);

    // 替换原来的send,确保14字节全部发送
    ssize_t total_sent = 0;
    ssize_t sent_bytes;
    const char* send_buf = str_line;
    int total_len = 14;

    while (total_sent < total_len) {
        sent_bytes = send(connfd, send_buf + total_sent, total_len - total_sent, 0);
        if (sent_bytes == -1) {
            perror("send failed");
            close(connfd);
            return;
        }
        total_sent += sent_bytes;
    }
}

再改客户端的recv逻辑:

客户端需要循环recv,直到凑够完整的14字节再处理:

// 客户端循环部分修改
char buffer[15]; // 留一个位置放终止符
for( idx =0; idx < 1024; idx++) {
    ssize_t total_recv = 0;
    ssize_t recvd_bytes;

    while (total_recv < 14) {
        recvd_bytes = recv(client_fd, buffer + total_recv, 14 - total_recv, 0);
        if (recvd_bytes == -1) {
            perror("recv failed");
            close(client_fd);
            exit(EXIT_FAILURE);
        } else if (recvd_bytes == 0) {
            // 服务器主动关闭连接了
            printf("Server closed connection prematurely\n");
            close(client_fd);
            exit(EXIT_SUCCESS);
        }
        total_recv += recvd_bytes;
    }
    buffer[14] = '\0'; // 确保字符串以'\0'结尾
    puts(buffer);
}

额外提两个小问题:

  1. 服务器里的srand(time(NULL)):你每次调用signal_data_generator都调用它,但time(NULL)是秒级的,同一秒内的多次调用会重置随机数种子,导致生成的随机数完全一样。应该把srand放在程序启动时(比如main函数开头)只调用一次。
  2. 你的formatXData/formatYData函数里的条件判断有冗余,比如num < DIGIT1和num < DIGIT2的分支都是sprintf( temp_str," %d",num);,可以合并,不过这不是传输问题的根源,只是代码优化点。

总结

TCP字节流的特性决定了我们必须在应用层处理消息边界,要么用固定长度,要么用分隔符(比如换行符),而不是依赖send/recv的flags。只要保证每次处理的是完整的消息单元,你看到的字符串移位问题就会消失。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 08:38:14