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
相关产品推荐
相关产品推荐

