Winsock2 线程参数引发异常访问冲突

Winsock2 thread arguments throw exception access violation

我正在使用 WinSock2.h 编写 UDP 服务器-客户端程序,其中各个线程所需的参数(SOCKETsockaddr_in)通过结构传递给线程。

我的接收函数在到达 recvfrom() 部分时一直抛出异常,但只有在我调试程序时才会抛出异常。如果我在没有调试器的情况下启动它,它不会显示任何错误也不会停止程序 运行。此异常仅发生在 服务器 端。此外,recvfrom() 错误检查不断在客户端抛出错误 10022,但据我了解,这是由于客户端没有 bind() 造成的。

服务器端是否存在 bind() 在另一个函数中的问题,或者我的指针哪里有问题?我不知道为什么它只在服务器端抛出异常。

typedef struct thread_args {
    struct sockaddr_in sockaddr;
    SOCKET socket;
    int keep_alive_count; 
}THREAD_ARG;

void* receive_packets(void* arguments) {
    THREAD_ARG* args = (THREAD_ARG*)arguments;
    struct sockaddr_in* from;
    char buffer[MAX_FRAGMENTATION + sizeof(HEADER)];
    HEADER* message;

    while (1) {
        memset(buffer, "[=10=]", MAX_FRAGMENTATION + sizeof(HEADER));

        //this is where I get the exception thrown
        if (recvfrom(args->socket, buffer, sizeof(buffer), 0, (struct sockaddr*) & from, sizeof(from)) == SOCKET_ERROR) { 
            printf("recvfrom() failed, error code: %d\n", WSAGetLastError());
            exit(RECVFAIL);
        }

        message = (HEADER*)buffer;
        char flag = message->flags;

        }
    }
    return 0;
}

int client(THREAD_ARG* args) {
    u_short port;
    char ip[50];
    struct sockaddr_in client_sock;
    void* return_value1, *return_value2;

    getchar();

    printf("Please enter the IP address you would like to communicate with:\n");
    gets(IP);

    printf("Please enter the port number you would like to communicate with:\n");
    scanf("%hu", &port);

    client_sock.sin_family = AF_INET;
    client_sock.sin_addr.s_addr = inet_addr(IP);
    client_sock.sin_port = htons(port);

    args->sockaddr = client_sock;

    pthread_t send_thread, receive_thread, keep_alive_thread;

    pthread_create(&send_thread, NULL, send_packets, args);
    pthread_create(&receive_thread, NULL, receive_packets, args);
    pthread_create(&keep_alive_thread, NULL, keep_alive, args);

    pthread_join(send_thread, &return_value1);
    pthread_join(receive_thread, &return_value2);
    pthread_join(keep_alive_thread, NULL);

    return 0;
}

int server(THREAD_ARG* args) {
    u_short port;
    int valid;
    struct sockaddr_in server_sock;
    void* return_value1, * return_value2;

    printf("Please enter the port number you would like to listen on:\n");
    scanf("%hu", &port);

    server_sock.sin_family = AF_INET;
    server_sock.sin_addr.s_addr = INADDR_ANY;
    server_sock.sin_port = htons(port);

    if(bind(args->socket, (struct sockaddr_in*) & server_sock, sizeof(server_sock)) == SOCKET_ERROR) {
        printf("Bind failed, error code: %d\n", WSAGetLastError());
        return 1;
    }
    printf("Bind done\n");

    args->sockaddr = server_sock;

    pthread_t receive_thread;
    pthread_create(&receive_thread, NULL, receive_packets, args);
    pthread_join(receive_thread, &return_value2);

}

int main() {
    WSADATA was;
    SOCKET sock;
    char choice;
    THREAD_ARG* args;

    printf("WinSock initialisation.\n");
    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
        printf("WinSock initialisation failed. Error code: %d\n", WSAGetLastError());
        return 1;
    }
    printf("WinSock initialised.");

    if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
        printf("Couldn't create socket: %d\n", WSAGetLastError());
    }
    printf("Socket created.\n");

    printf("Would you like to be a server or a client?\n");
    printf("1 - Server\n");
    printf("2 - Client\n");
    printf("0 - Exit\n");

    args = (THREAD_ARG*)malloc(sizeof(THREAD_ARG));
    args->socket = sock;

    switch (choice = getchar())
    {
        case '0':
            return 0;
        case '1':
            server(args);
            break;
        case '2':
            client(args);
            break;
        default:
            printf("Please choose from above\n");
    }

    return 0;
}
    struct sockaddr_in* from;
    char buffer[MAX_FRAGMENTATION + sizeof(HEADER)];
    HEADER* message;

你这里有问题。你只分配了一个sockaddr_in*。但是你需要一个实际的 sockaddr_in 来保存地址。

    while (1) {
         memset(buffer, "[=11=]", MAX_FRAGMENTATION + sizeof(HEADER));

这里,memset的第二个参数是错误的。它应该是要设置的值,而不是指向值的指针。

        if (recvfrom(args->socket, buffer, sizeof(buffer), 0, (struct sockaddr*) & from, sizeof(from)) == SOCKET_ERROR) { 

在这里,您将 struct sockaddr_in ** 转换为 struct sockaddr *,丢掉了一个间接级别。那没有任何意义。最后一个参数 sizeof(from) 指针 的大小。这是不对的。

    THREAD_ARG* args;

    ...

    args = (THREAD_ARG*)malloc(sizeof(THREAD_ARG));
    args->socket = sock;

为什么这个奇怪的间接?为什么不只是 THREAD_ARD args; 并摆脱 malloc-> 东西?