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

Socket编程中recv()函数出现无效参数错误(errno=22)求助

Socket读取函数调试问题

问题核心

第二次调用handle_read_socket()时,recv()返回-1且errno=22(EINVAL,无效参数),无法读取剩余的1字节数据。

代码问题分析

1. recv返回0时的错误逻辑

readsize == 0分支中,if (errno == EOF)是完全错误的:

  • EOF不是errno的合法取值(errno为正整数错误码,EOF定义为-1)。
  • recv()返回0本身就表示对端正常关闭连接,此时errno的值是未定义的,不能用于判断。

2. 语法错误导致运行异常

LOG_ERROR("Could not read from client and Error happened.")语句末尾缺少分号,会导致编译错误,进而引发不可预测的运行时行为。

3. 阻塞模式下的循环逻辑问题

在阻塞模式下,当读取部分数据(如第二次调用时读取1字节,未填满缓冲区),函数会持续调用recv()阻塞等待更多数据,但单元测试中没有后续数据发送,这会导致函数挂起而非返回。

修复方案

修复后的handle_read_socket()函数

#include <string.h> // 用于strerror

int
handle_read_socket(struct conn *client) {
    int total_read = 0;
    int readsize = 0;

    while (1) {
        readsize = recv(client->pfd.fd, client->client_buff + total_read,
                        BUFFSIZE - total_read, 0);

        if (readsize > 0) {
            total_read += readsize;

            if (total_read == BUFFSIZE) {
                // 缓冲区已满,退出循环
                break;
            }
        } else if (readsize == 0) {
            // 对端关闭连接,返回错误
            LOG_ERROR("Client closed connection.");
            return -1;
        } else {
            // 读取错误处理
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // 非阻塞模式下无更多数据,退出循环返回已读字节数
                break;
            }
            // 其他错误,打印错误信息并返回-1
            LOG_ERROR("Could not read from client: %s", strerror(errno));
            return -1;
        }
    }
    return total_read;
}

调整单元测试(启用非阻塞模式)

将socket设置为非阻塞模式,确保第二次调用时读取剩余1字节后,因无更多数据退出循环并返回:

#define BUFFSIZE 2

void
test_handle_read_socket() {
    /* Arrangement */
    struct conn sender;
    int sockfd[2];

    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) == -1) {
        perror("Failed creating pair sockets.");
        return;
    }

    // 启用非阻塞模式
    int flags = fcntl(sockfd[0], F_GETFL, 0);
    fcntl(sockfd[0], F_SETFL, flags | O_NONBLOCK);

    // 写入"123"到socket
    sender.pfd.fd = sockfd[0];
    send(sockfd[1], "123", 3, 0);

    eqint(2, handle_read_socket(&sender));
    eqnstr("12", sender.client_buff, 2);
    eqint(1, handle_read_socket(&sender)); // 现在会正确返回1
    eqnstr("3", sender.client_buff, 1);

    /* Teardown */
    close(sockfd[1]);
    close(sockfd[0]);
}

修复说明

  1. 修正了recv()返回0时的错误处理逻辑,直接判断连接关闭并返回-1。
  2. 补全了LOG_ERROR语句的分号,修复语法错误。
  3. 启用非阻塞模式后,当socket无更多数据时,recv()返回EAGAIN/EWOULDBLOCK,函数退出循环并返回已读取的字节数,符合单元测试的期望。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 16:12:10