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

TCP套接字编程中客户端接收模块工作异常问题咨询

TCP套接字通信接收侧故障排查

项目整体链路

当前开发的TCP通信程序业务流程为:

  • 客户端第一步从服务端拉取目标路径下的所有文件列表
  • 客户端向服务端发送需要下载的指定文件名
  • 客户端接收服务端返回的对应文件内容
    目前已经通过服务端日志校验,所有发送流程均按代码逻辑执行完成、所有数据包均已推送至内核发送缓冲区,问题完全集中在客户端接收逻辑与发送/接收协议的适配层。

故障1:文件列表接收循环无法退出

现象

服务端文件列表的发送循环已执行完毕,所有文件名均序列化后通过write接口推送完成,但客户端的接收循环始终无法终止。

对应代码

客户端接收逻辑:

while ((read_cnt=read(sd, buf, BUF_SIZE)) != 0) {
    read_cnt=read(sd, buf, BUF_SIZE);
    printf("%s\n", buf);
}

服务端列表发送逻辑:

while ((entry=readdir(dir)) != NULL) {
    sprintf(buf, "%s\n", entry->d_name);
    write(clnt_sd, buf, strlen(buf));
}

原因定位

  • 循环内重复调用两次read:循环入口先执行一次read拿到数据做循环判断,进入循环块后又立刻执行第二次read。第一次读到的内容直接被丢弃,第二次读到的内容才会被打印,数据读取逻辑完全错位。
  • 未正确适配TCP流的结束判定规则:TCP是面向字节流的协议,本身没有消息边界,只有对端主动关闭连接、发送FIN包完成流终止流程时,阻塞状态下的read才会返回0。服务端发完所有列表数据后没有主动关闭连接,也没有发送流结束标识,read会一直阻塞等待新数据,永远不会触发循环退出条件。
  • 未处理读异常分支:当前循环判断仅校验read_cnt != 0,没有处理read返回-1的系统调用异常场景(比如连接被重置、网络中断)。一旦返回-1,循环条件依然成立,会陷入异常循环。

故障2:消息接收不全、文件传输量不匹配、结束标识失效

现象

  • 服务端累计推送17条消息,客户端仅收到15条
  • 预设的收到"fin"标识后退出接收循环的逻辑未触发
  • 进入文件接收阶段后,服务端已完成全部文件内容发送,客户端统计的接收总字节数和服务端实际发送总量始终不匹配,循环无法正常终止

对应代码

客户端文件接收逻辑:

while (1) {
    read_cnt=read(sd, buf, BUF_SIZE);
    fwrite((void*)buf, 1, read_cnt, fp);
    printf("%s\n", buf);
    if (strstr(buf, "fin") != NULL) {
        break;  
    }
    total_read += read_cnt;
    pcnt = ((total_read/ file_size) * 100.0)/10;
    printf("(%.0d %%) Send %.0f / %.0f bytes.\n", pcnt*10, total_read, file_size);
}

服务端文件发送逻辑:

FILE *fp;
fp = fopen(file_name, "r");
if (fp == NULL) {
    printf("File not Exist");
    exit(1);
}

fseek(fp, 0, SEEK_END);    
int file_size = ftell(fp); 
sprintf(buf, "%d", file_size);
write(clnt_sd, buf, read_cnt);
fseek(fp, 0, SEEK_SET);
        
while (feof(fp) == 0) {
    read_cnt = fread((void*)buf, 1, BUF_SIZE, fp);
    write(clnt_sd, buf, read_cnt);
}
fclose(fp);

原因定位

  • 文件大小包头发送长度错误:服务端把文件大小转成字符串写入缓冲区后,调用write时的长度参数错误使用了变量read_cnt(此时该变量存的是上一次操作的残留值,并非当前包头的实际长度),没有用strlen(buf)计算真实的包头长度,导致客户端收到的文件大小基准值完全随机错位,后续所有基于文件大小的进度计算、传输终止判断从源头就是错的。
  • 结束标识检测未适配TCP粘包拆包特性:客户端每收到一次read返回的缓冲区数据就调用strstr匹配"fin",但TCP是流协议,没有消息边界,"fin"字符串可能被拆分到两次连续的read返回结果中(比如第一次读到"fi",第二次读到"n"),单次缓冲区扫描永远匹配不到完整的标识;如果文件本身的内容里包含"fin"字符串,还会出现提前退出的误判。
  • 服务端文件循环发送逻辑存在偏差:用feof(fp)做循环判断的时机错位,会比预期多读一次满缓冲区的数据才退出循环,导致客户端实际收到的字节数比文件真实大小多。
  • 传输结束后没有明确的终止信号:服务端发完所有文件内容后,没有和客户端同步约定结束标识,也没有关闭连接,read会一直阻塞在等待数据的状态,根本走不到终止分支。
  • 之前尝试用memset、bzero清空接收缓冲区没有效果,因为故障根源根本不是缓冲区残留脏数据,是代码逻辑错位、没有适配TCP流的传输特性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.25 10:36:04