Windows上的C套接字,随机获得recv错误,但errno为0?

y0u0uwnf  于 2023-06-21  发布在  Windows
关注(0)|答案(1)|浏览(203)

我有一个客户端和一个服务器在Windows上使用套接字。我在客户端之前启动服务器,等待它挂起,然后启动客户端。这样做,对recv()的调用将随机(一半的时间)返回-1,当我打印errno时,它是0(无错误)...另一半时间它会收到信息并正常打印,然后关闭...这个代码有什么问题吗?

client.c

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <errno.h>

#define BUFFER_LEN 200

int main()
{
    WSADATA WSAData;
    WSAStartup(MAKEWORD(2,0), &WSAData);
    
    SOCKET sock;
    SOCKADDR_IN address;
    // address.sin_addr.s_addr = inet_addr("127.0.0.1");
    InetPton(AF_INET, "127.0.0.1", &address.sin_addr.s_addr);
    address.sin_family = AF_INET;
    address.sin_port = htons(8888);
    
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        printf("Erreur lors de la création du socket. %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    if ((connect(sock, (SOCKADDR *)&address, sizeof(address))) == -1) {
        sprintf("Erreur lors de la connexion au socket. %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    char *msg = "Coucou\n";
    printf("Envoi de coucou\n");
    int bytesSent;

    if ((bytesSent = send(sock, msg, strlen(msg), 0)) == -1) {
        sprintf("Erreur lors l'envoi du message. %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

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

    WSACleanup();
    
    return 0;
}

server.c

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#define BACKLOG 3 // taille de la file d'attente
#define BUFFER_LEN 200 // taille du buffer de lecture

int main()
{
    WSADATA WSAData;
    WSAStartup(MAKEWORD(2,0), &WSAData);
    
    SOCKET sockfd;
    SOCKADDR_IN address;
    // address.sin_addr.s_addr = inet_addr("127.0.0.1");
    address.sin_addr.s_addr = htonl(INADDR_ANY);  
    address.sin_family = AF_INET;
    address.sin_port = htons(8888); // host to network short (conversion de host byte order en network byte order)
    
    printf("Démarrage du serveur\n");

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        printf("Erreur lors de la création du socket. %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    if ((bind(sockfd, (SOCKADDR *)&address, sizeof(address))) == -1) {
        printf("Erreur lors de l'ouverture du socket. %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    if ((listen(sockfd, BACKLOG)) == -1) {
        printf("Erreur lors de l'écoute du socket. %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    SOCKET clientSocket;
    SOCKADDR_IN clientAddress;
    int addrLen = sizeof(clientAddress);
    if ((clientSocket = accept(sockfd, (struct sockaddr *) &clientAddress, &addrLen)) == -1) {
        printf("Erreur lors de l'acceptation de la connexion. %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    // Convertion de l'IP en texte
    char ip[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, &(clientAddress.sin_addr), ip, INET_ADDRSTRLEN);
    printf("Connexion de %s:%i\n", ip, clientAddress.sin_port);

    char buffer[BUFFER_LEN];
    int len = recv(clientSocket, buffer, BUFFER_LEN, 0);

    if (len == -1 && errno != EAGAIN) {
        printf("Erreur lors de la réception du message. %s (%d)\n", strerror(errno), errno);
        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) {
        printf("Message reçu : %s\n", buffer);
    }

    closesocket(clientSocket);
    closesocket(sockfd);

    WSACleanup();

    return 0;
}

我还应该提到我使用gcc main.c -lws2_32 -g -Wall编译

gab6jxml

gab6jxml1#

首先要注意的是,当客户端返回对send()的调用时,这并不意味着任何数据已经发送到服务器。这只是意味着数据已经排队等待发送。
然后,客户端立即调用WSACleanup()并退出。看起来这只是在它有机会发送任何东西之前立即破坏了你的插座。
您应该在发送数据和调用WSACleanup()之间添加closesocket(sock)。这将允许有序地关闭套接字,包括刷新已排队的任何数据。
正如@Hans所指出的,阅读errno并不是获得套接字错误的正确方法,你应该使用WSAGetLastError()

相关问题