Socket通信中服务端发"-1"客户端recv()仅收1字节问题咨询
问题根因
- send后立即close触发RST丢包:服务端调用send之后立刻执行了
close(new_sockfd),如果此时内核发送缓冲区还有未完成发送的数据,系统会直接丢弃剩余数据并向客户端发送TCP RST重置包,而非走正常的FIN四次挥手流程。你遇到的只收到1字节的情况,就是第一字节已经发到客户端缓冲区,后续数据被RST逻辑丢弃导致。 - 未校验send的实际发送长度:当前仅判断send返回值是否为-1,但send的返回值代表实际成功发送的字节数,受内核发送缓冲区大小限制,即使是阻塞socket也可能只发送部分数据,没有做补发逻辑也可能导致客户端只收到部分内容。
- 打印乱码是用法错误:直接将字符数组指针用
%d打印,输出的是buf数组的内存地址数值,而非buf存储的内容,自然会出现无意义的大数。
修复方案
服务端修改
- 新增循环发送逻辑,确保目标内容全部发送完成
- 发送完成后先关闭写端等待优雅挥手,避免直接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
相关产品推荐
相关产品推荐

