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

Windows下C Socket调用recv()随机返回-1但errno为0问题排查

问题分析与修复方案

你的代码存在几个关键问题,导致recv()出现返回-1但errno为0的异常情况,以下是具体问题和修复方式:

1. Windows下Winsock错误处理误用errno

Winsock API的错误码不能通过errno获取,必须使用WSAGetLastError()函数。errno是POSIX标准的错误机制,Windows下Winsock有独立的错误体系,当Winsock函数返回SOCKET_ERROR(即-1)时,要调用WSAGetLastError()获取真实错误码,而非读取errno。你代码中所有依赖errno的错误判断都是错误的,这直接导致了错误信息异常、errno为0的情况。

修复示例:
服务器中recv的错误判断修改为:

int len = recv(clientSocket, buffer, BUFFER_LEN, 0);
if (len == SOCKET_ERROR) {
    int err = WSAGetLastError();
    // 排除非阻塞模式的WSAEWOULDBLOCK(对应POSIX的EAGAIN)
    if (err != WSAEWOULDBLOCK) {
        printf("Erreur lors de la réception du message. Code d'erreur: %d\n", err);
        exit(EXIT_FAILURE);
    }
}

客户端创建socket的错误处理修改为:

if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) {
    int err = WSAGetLastError();
    printf("Erreur lors de la création du socket. Code d'erreur: %d\n", err);
    exit(EXIT_FAILURE);
}

2. 客户端未正确关闭socket就退出

客户端调用send()后直接执行WSACleanup()并退出,未调用closesocket(sock)关闭套接字。这会导致操作系统强制终止连接,服务器端recv()可能收到连接提前关闭的信号,表现为异常返回。

修复:在客户端的WSACleanup()之前添加:

closesocket(sock);

3. 客户端sprintf调用参数非法

客户端中connect和send的错误处理里,sprintf的第一个参数是字符串常量"Erreur...",这属于非法操作——sprintf的第一个参数必须是可写的缓冲区,否则会引发内存访问错误,导致未定义行为。

修复:定义缓冲区存储错误信息,示例:

char err_buf[256];
if ((connect(sock, (SOCKADDR *)&address, sizeof(address))) == SOCKET_ERROR) {
    int err = WSAGetLastError();
    sprintf(err_buf, "Erreur lors de la connexion au socket. Code d'erreur: %d\n", err);
    printf("%s", err_buf);
    exit(EXIT_FAILURE);
}

4. 服务器recv后未添加字符串终止符

recv()接收到的字节流不会自动添加\0终止符,直接用printf("%s", buffer)会打印到内存中第一个\0为止,大概率出现乱码。

修复:recv成功后手动添加终止符,同时预留一个字节的缓冲区空间:

char buffer[BUFFER_LEN];
// 留一个字节给终止符,避免越界
int len = recv(clientSocket, buffer, BUFFER_LEN - 1, 0);

// ... 错误判断 ...

else if (len > 0) {
    buffer[len] = '\0'; // 确保字符串终止
    printf("Message reçu : %s\n", buffer);
}

关键修正后的代码片段

修正后的client.c核心部分

// ... 其他代码 ...
if ((connect(sock, (SOCKADDR *)&address, sizeof(address))) == SOCKET_ERROR) {
    char err_buf[256];
    int err = WSAGetLastError();
    sprintf(err_buf, "Erreur lors de la connexion au socket. Code d'erreur: %d\n", err);
    printf("%s", err_buf);
    exit(EXIT_FAILURE);
}

// ... 发送代码 ...

printf("Bytes envoyés : %d\n", bytesSent);

closesocket(sock); // 新增关闭socket
WSACleanup();

return 0;

修正后的server.c核心部分

// ... accept之后的代码 ...
char buffer[BUFFER_LEN];
int len = recv(clientSocket, buffer, BUFFER_LEN - 1, 0);

if (len == SOCKET_ERROR) {
    int err = WSAGetLastError();
    if (err != WSAEWOULDBLOCK) {
        printf("Erreur lors de la réception du message. Code d'erreur: %d\n", err);
        exit(EXIT_FAILURE);
    }
} else if (len == 0) {
    printf("Le client s'est déconnecté (extrémité de la socket fermée)\n");
    exit(EXIT_FAILURE);
} else if (len > 0) {
    buffer[len] = '\0';
    printf("Message reçu : %s\n", buffer);
}

// ... 关闭socket代码 ...

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 06:22:04