2

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

我只是在 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;
}
4

1 回答 1

1

你在滥用recvfrom(). 该fromlen参数期望接收一个int*指向 的指针,该指针int在输入时指定参数sockaddr中传递的缓冲区的字节大小from,在输出时接收sockaddr写入from缓冲区的字节大小。

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

  • WSAStartup()失败时不返回SOCKET_ERROR,它返回一个实际的错误代码。

  • 您忽略了 的返回值recvfrom(),它告诉您实际写入了多少字节buf。您假设buf将其传递给时始终为空终止printf("%s"),但这不能保证。您正在清零buf以使用空终止符对其进行初始化,如果recvfrom()接收到包含少于 1024 个字节的数据报,这很好。但是,如果它接收到一个正好 1024 字节的数据报,那么所有空终止符都将被覆盖,并且没有终止符可供printf()查找(如果recvfrom()接收到超过 1024 字节的数据报,它将失败并出现WSAEMSGSIZE错误,这不是一个致命错误,但您将其视为已处理)。您可以传递返回值,而不是完全依赖任何空终止符recvfrom()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;
}
于 2020-01-14T00:47:05.180 回答