You need to enable JavaScript to run this app. C语言TCP socket传输RSA加密数据大小不一致问题
优惠活动
大模型
产品
解决方案
定价
更多

C语言TCP socket传输RSA加密数据大小不一致问题

问题根因
  • 核心错误:对RSA加密后的二进制密文使用strlen计算长度。RSA加密输出的是任意分布的二进制字节流,内部可能随机出现ASCII码为0的空字节,strlen的逻辑是碰到第一个空字节就终止计数,因此只要密文里空字节的位置不同,算出的长度就会在1~256之间随机波动——这部分和TCP传输逻辑完全无关,是计数方式的根本性错误。
  • 设计缺陷:没有适配TCP的流传输特性。TCP是面向字节流的协议,没有内置的消息边界,单次write/read调用都可能出现“短写”“短读”的情况:即调用一次写/读,只完成了部分数据的传输,不会保证一次性把所有指定长度的数据发完/收完。
  • 流程缺失:没有在传输前约定消息边界。接收端不知道对端总共要发多少长度的数据,无法判断什么时候才算接收完成,容易读入不完整的分片数据。
具体解决步骤
  • 废弃所有针对加密二进制数据的strlen操作
    所有加密数据的长度必须使用RSA接口返回的实际二进制长度值,绝对不能对密文缓冲区使用字符串处理函数。你之前在服务端用strlen(buffer[0])打印长度的写法,从原理上就无法正确统计二进制数据的长度。
  • 增加固定长度的消息头,明确数据边界
    客户端发送加密密文前,先把本次要发送的密文总长度,通过固定长度的网络序整数(一般用4字节uint32_t)发送给服务端。服务端先读满这个长度头,拿到要接收的总密文长度后,再读取对应长度的密文内容。
    长度值必须用htonl()/ntohl()在网络字节序和主机字节序之间转换,避免不同硬件架构下字节序不一致导致的长度解析错误。
  • 封装可靠的循环读写逻辑
    不能只调用一次write/read就认为传输完成,必须通过循环累计已传输的字节数,直到把约定长度的所有数据全部发完/收完,处理TCP的短写、短读场景。
    • 客户端发送时:循环写长度头、再循环写实际密文,直到所有字节全部发送成功。
    • 服务端接收时:循环读满长度头、再循环读满对应长度的密文,直到所有字节全部接收成功。
参考核心代码修改

客户端发送逻辑替换

// 先发送加密数据长度(转网络字节序)
uint32_t net_len = htonl(encrypted_len);
int sent_total = 0;
// 循环写长度头,确保4字节长度全部发完
while(sent_total < sizeof(net_len)) {
    n = write(sockfd, (char*)&net_len + sent_total, sizeof(net_len) - sent_total);
    if(n < 0) {
        printf("Error writing message length\n");
        return 1;
    }
    sent_total += n;
}
// 循环写实际加密数据,确保全部发完
sent_total = 0;
while(sent_total < encrypted_len) {
    n = write(sockfd, encrypt + sent_total, encrypted_len - sent_total);
    if(n < 0) {
        printf("Error writing encrypted data\n");
        return 1;
    }
    sent_total += n;
}

服务端接收逻辑替换

// 先读满4字节长度头
uint32_t net_len;
int recv_total = 0;
while(recv_total < sizeof(net_len)) {
    n = read(newsockfd[0], (char*)&net_len + recv_total, sizeof(net_len) - recv_total);
    if(n <= 0) {
        printf("Error reading message length\n");
        return 1;
    }
    recv_total += n;
}
// 转为主机字节序,得到实际需要接收的密文长度
uint32_t actual_len = ntohl(net_len);
// 循环读满对应长度的密文
recv_total = 0;
while(recv_total < actual_len) {
    n = read(newsockfd[0], buffer[0] + recv_total, actual_len - recv_total);
    if(n <= 0) {
        printf("Error reading encrypted data\n");
        return 1;
    }
    recv_total += n;
}
// 直接打印实际接收的长度,完全不需要strlen
printf("Received encrypted data length: %u\n", actual_len);

内容的提问来源于stack exchange,提问作者laser

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.23 20:45:05