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

Socket通信中服务端发"-1"客户端recv()仅收1字节问题咨询

问题根因

  • send后立即close触发RST丢包:服务端调用send之后立刻执行了close(new_sockfd),如果此时内核发送缓冲区还有未完成发送的数据,系统会直接丢弃剩余数据并向客户端发送TCP RST重置包,而非走正常的FIN四次挥手流程。你遇到的只收到1字节的情况,就是第一字节已经发到客户端缓冲区,后续数据被RST逻辑丢弃导致。
  • 未校验send的实际发送长度:当前仅判断send返回值是否为-1,但send的返回值代表实际成功发送的字节数,受内核发送缓冲区大小限制,即使是阻塞socket也可能只发送部分数据,没有做补发逻辑也可能导致客户端只收到部分内容。
  • 打印乱码是用法错误:直接将字符数组指针用%d打印,输出的是buf数组的内存地址数值,而非buf存储的内容,自然会出现无意义的大数。

修复方案

服务端修改

  1. 新增循环发送逻辑,确保目标内容全部发送完成
  2. 发送完成后先关闭写端等待优雅挥手,避免直接close触发RST
    修改后代码示例:
if(get_fd(buf, fd, stat_buf) == -1){    // invalid file number
    printf("client has given an invalid file number\n\n");
    const char* err_flag = "-1";
    int to_send = 2; // 仅发送'-'和'1'两个字符即可,不需要带末尾'\0'可减少传输量
    int sent = 0;
    while(sent < to_send) {
        int ret = send(new_sockfd, err_flag + sent, to_send - sent, 0);
        if(ret == -1) {
            perror("server: send");
            break;
        }
        sent += ret;
    }
    // 优雅关闭逻辑,避免RST丢包
    shutdown(new_sockfd, SHUT_WR);
    char dummy[16];
    // 等待客户端 FIN 后再关闭
    recv(new_sockfd, dummy, sizeof(dummy), 0);
    close(new_sockfd);
    exit(1);
} else {
    /* code */
}

客户端修改

如果需要将收到的标识转为整数,需要用atoi函数解析字符串,不要直接打印指针地址,修改打印逻辑如下:

std::memset(&buf, 0, MAXDATASIZE);    // clear the buffer for it has been used previously
if((numbyte = recv(sockfd, buf, MAXDATASIZE-1, 0))==-1){
    perror("client: recv");
    exit(1);
}
buf[numbyte] = '\0';
// 解析字符串为整数后打印
printf("numbyte: %d, received string: %s, parsed number: %d\n\n", numbyte, buf, atoi(buf));

如果需要确保收到完整标识,可以新增循环recv逻辑,直到收到预期的2字节内容再做处理。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 10:36:05