char*类型共享内存收发数据量异常问题排查
共享内存传输文件数据量不符的解决方法
共享内存段类型为char*,发送端读取文件并将内容复制到共享内存地址current_channel.data,但出现发送端中strlen(data)远小于batch_read,导致收发数据量不符的问题。已确认其他变量正常,仅数据量获取存在问题。
发送端原代码
char data[GLOB_SEGSIZE]; char filesize[21]; batch_read = 0, start_point = 0; while ((int)(batch_read = pread(fd, data, GLOB_SEGSIZE, start_point)) > 0) { sem_wait(current_channel.writer_sem); strncpy(current_channel.data, data, (size_t)GLOB_SEGSIZE); start_point += batch_read; printf("%zu of %s\n", strlen(data), filesize); sem_post(current_channel.reader_sem); }
接收端原代码
int curr_received = 0; size_t filesize; // File size is received in the shared mem before the file transfer begins while (curr_received < (int)filesize) { sem_wait(current_channel.reader_sem); curr_received += strlen(current_channel.data); gfs_send(ctx, current_channel.data, strlen(current_channel.data)); printf("%zu of %zu\n", strlen(current_channel.data), filesize); sem_post(current_channel.writer_sem); }
问题原因
strlen的局限性:strlen通过查找字符串结束符\0计算长度,若文件是二进制格式(包含\0字节),会提前终止计数;即使是文本文件,pread读取的原始数据不会自动添加\0,strlen会越界读取,结果完全不可靠。strncpy的隐患:strncpy遇到\0会停止复制,无法完整传输包含\0的二进制数据。
解决方法
1. 扩展共享内存结构
在current_channel中新增size_t batch_size字段,用于存储当前批次的有效字节数:
typedef struct { char data[GLOB_SEGSIZE]; size_t batch_size; // 新增:记录当前批次实际数据长度 sem_t writer_sem; sem_t reader_sem; } Channel;
2. 修改发送端代码
- 用
memcpy替代strncpy,保证按字节完整复制数据 - 直接使用
batch_read(pread返回的实际读取字节数)作为有效长度,存入共享内存的batch_size字段 - 打印和进度更新时不再依赖
strlen
修改后代码:
char data[GLOB_SEGSIZE]; char filesize[21]; ssize_t batch_read = 0; off_t start_point = 0; while ((batch_read = pread(fd, data, GLOB_SEGSIZE, start_point)) > 0) { sem_wait(¤t_channel.writer_sem); memcpy(current_channel.data, data, (size_t)batch_read); current_channel.batch_size = (size_t)batch_read; // 写入实际数据长度 start_point += batch_read; printf("%zd of %s\n", batch_read, filesize); sem_post(¤t_channel.reader_sem); }
3. 修改接收端代码
- 从共享内存的
batch_size字段获取当前批次的有效字节数 - 传输数据和更新接收进度时,使用该
batch_size代替strlen
修改后代码:
int curr_received = 0; size_t filesize; // 文件大小已在传输前通过共享内存获取 while (curr_received < (int)filesize) { sem_wait(¤t_channel.reader_sem); size_t curr_batch_size = current_channel.batch_size; curr_received += (int)curr_batch_size; gfs_send(ctx, current_channel.data, curr_batch_size); printf("%zu of %zu\n", curr_batch_size, filesize); sem_post(¤t_channel.writer_sem); }
内容的提问来源于stack exchange,提问作者Josh Voytek
相关产品推荐
相关产品推荐

