c 中的 IPv6 服务器 - recvfrom 失败

IPv6 Server in c - recvfrom failed

我用 winsock2.h 为 IPv6 服务器编写了一个小的 c 程序当我 运行 Visual Studio 中的程序时,我一直收到以下消息:recvfrom 失败

我只是找不到recvfrom函数中的错误。也许有人可以看出为什么我的程序此时无法运行,谢谢! :-)

此致, 肯

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma comment(lib, "Ws2_32.lib")

int main(int argc, char* argv[]) {

    SOCKET server_socket;
    struct sockaddr_in6 server_addr, client_addr;
    socklen_t client_len;
    char buf[1024];
    char clientIP[256];

    WSADATA data;
    WORD version = MAKEWORD(2, 2);
    if (WSAStartup(version, &data) == SOCKET_ERROR) {

        printf("WSASStartup failed\n");
        WSACleanup();
        exit(EXIT_FAILURE);
    }

    server_socket = socket(AF_INET6, SOCK_DGRAM, 0);
    if (server_socket == -1) {

        printf("creating socket failed\n");
        WSACleanup();
        exit(EXIT_FAILURE);
    }
    else {

        printf("creating socket successful\n");
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin6_addr = in6addr_any;
    server_addr.sin6_family = AF_INET6;
    server_addr.sin6_port = htons(5001);

    if (bind(server_socket, (const struct sockaddr*) & server_addr,
        sizeof(server_addr)) == -1) {

        printf("bind socket failed\n");
        WSACleanup();
        exit(EXIT_FAILURE);
    }
    else {

        printf("bind socket successful\n");
    }

    while (1) {

        memset(&client_addr, 0, sizeof(client_addr));
        memset(buf, 0, sizeof(buf));

        if (recvfrom(server_socket, (char*)buf, 1024, 0,
            (struct sockaddr*) & client_addr,
            sizeof(client_addr)) == -1) {

            printf("recvfrom failed\n");
            WSACleanup();
            exit(EXIT_FAILURE);
        }
        else {

            printf("recvfrom successful");
        }

        printf("%s\n", buf);
        printf("IP: %s\n", inet_ntop(AF_INET6, &client_addr.sin6_addr,
            clientIP, 256));
    }

    closesocket(server_socket);

    WSACleanup();

    return 0;
}

您在滥用 recvfrom()fromlen 参数期望收到一个指向 intint* 指针,它在输入时指定 sockaddr 缓冲区的字节大小被传递到 from 参数,并在输出上接收写入 from 缓冲区的 sockaddr 的字节大小。

您的代码中还有其他一些小错误:

  • WSAStartup() 不会 return SOCKET_ERROR 失败,它 return 是一个实际的错误代码。

  • 您忽略了 recvfrom() 的 return 值,它告诉您实际写入了 buf 的字节数。您假设 buf 在将其传递给 printf("%s") 时始终以 null 结尾,但这并不能保证。您正在将 buf 清零以使用空终止符对其进行初始化,如果 recvfrom() 接收到包含少于 1024 字节的数据报,这很好。但是,如果它接收到一个正好有 1024 字节的数据报,那么所有的空终止符都将被覆盖,并且 printf() 将找不到任何终止符(如果 recvfrom() 接收到一个超过 1024 字节的数据报,它会因 WSAEMSGSIZE 错误而失败,这不是致命错误,但您将其视为致命错误)。您可以将 recvfrom() 的 return 值传递给 printf() 作为缓冲区大小,而不是完全依赖任何空终止符。无需浪费开销将 recvfrom() 将覆盖的内容清零。

试试这个:

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma comment(lib, "Ws2_32.lib")

int main(int argc, char* argv[]) {

    SOCKET server_socket;
    struct sockaddr_in6 server_addr, client_addr;
    int client_len, num_recvd;
    char buf[1024];
    char clientIP[256];

    WSADATA data;
    WORD version = MAKEWORD(2, 2);

    int errCode = WSAStartup(version, &data);
    if (errCode != 0) {
        printf("WSAStartup failed, error %d\n", errCode);
        WSACleanup();
        return EXIT_FAILURE;
    }

    server_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
    if (server_socket == INVALID_SOCKET) {
        errCode = WSAGetLastError();
        printf("creating socket failed, error %d\n", errCode);
        WSACleanup();
        return EXIT_FAILURE;
    }

    printf("creating socket successful\n");

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin6_addr = in6addr_any;
    server_addr.sin6_family = AF_INET6;
    server_addr.sin6_port = htons(5001);

    if (bind(server_socket, (struct sockaddr*) &server_addr, sizeof(server_addr)) == SOCKET_ERROR) {
        errCode = WSAGetLastError();
        printf("bind socket failed, error %d\n", errCode);
        closesocket(server_socket);
        WSACleanup();
        return EXIT_FAILURE;
    }

    printf("bind socket successful\n");

    while (1) {

        client_len = sizeof(client_addr);

        num_recvd = recvfrom(server_socket, buf, sizeof(buf), 0, (struct sockaddr*) &client_addr, &client_len);
        if (num_recvd == SOCKET_ERROR) {
            errCode = WSAGetLastError();
            if (errCode != WSAEMSGSIZE) {
                printf("recvfrom failed, error %d\n", errCode);
                closesocket(server_socket);
                WSACleanup();
                return EXIT_FAILURE;
            }
            printf("recvfrom truncated a datagram larger than %u bytes!\n", sizeof(buf));
            num_recvd = sizeof(buf);
        }
        else {
            printf("recvfrom successful\n");
        }

        printf("%.*s\n", num_recvd, buf);
        printf("IP: %s\n", inet_ntop(AF_INET6, &client_addr.sin6_addr, clientIP, 256));
    }

    closesocket(server_socket);
    WSACleanup();

    return 0;
}