多线程(C)时recvfrom()返回错误10022

时间:2018-12-22 11:00:59

标签: c multithreading sockets udp pthreads

我是套接字编程和多线程的新手,我仍在学习它,但是我有一个无法解决的问题,在其他一些主题上,我找到了一些答案,但看起来却没有和我一样的问题。

我想创建一个UDP客户端。该客户端应该能够发送(sendto())和接收(recvfrom())。

我正在对发送和接收函数进行多线程处理,但是当我调用recvfrom()WSAGetLastError()返回错误10022。

我正在使用librairy pthread.h进行多线程操作,而winsock2.h用于套接字。

当我不使用多线程时,没有问题。

我的代码:

    #include <sys/types.h>
    #include <winsock2.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <pthread.h>

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

    #define SERVER "127.0.0.1"
    #define PORT 8888
    #define MAXBUFFER 1024

    void Sending(void *VarThread);
    void Receiving(void *VarThread);

    int main(int argc, char **argv)
    {
        int sock;
        pthread_t Thread_ID_1;
        pthread_t Thread_ID_2;

        WSADATA WSAData;
        WSAStartup(MAKEWORD(2, 0), &WSAData);


        sock = socket(AF_INET, SOCK_DGRAM, 0);
        if (sock == -1)
        {
            perror("\nsocket()");
            printf("%d", WSAGetLastError());
            exit(0);
        }

        pthread_create(&Thread_ID_1, NULL, Sending, (void *)&sock);
        pthread_create(&Thread_ID_2, NULL, Receiving, (void *)&sock);

        pthread_join(Thread_ID_1, NULL);
        pthread_join(Thread_ID_2, NULL);

        close(sock);
        WSACleanup();
        return 0;
    }

    void Sending(void *VarThread)
    {
        int sock = *(int *)VarThread;
        int i;

        struct sockaddr_in si;
        si.sin_family = AF_INET;
        si.sin_addr.s_addr = inet_addr(SERVER);
        si.sin_port = htons(PORT);

        char buff[MAXBUFFER];
        ssize_t message;

        while(1)
        {
            fgets(buff, MAXBUFFER, stdin);
            for(i = 1; i < MAXBUFFER; i++) // delete the last '\n'
            {
                if(buff[i] == '\0')
                {
                    buff[i - 1] = '\0';
                    i = MAXBUFFER;
                }
            }
            message = sendto(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&si, sizeof(si));
            if (message == -1)
            {
                perror("\nsendto()");
                printf("%d", WSAGetLastError());
            }
        }
    }


    void Receiving(void *VarThread)
    {
        int sock = *(int *)VarThread;
        char buff[MAXBUFFER];
        ssize_t recu;

        while(1)
        {
            recu = recvfrom(sock, buff, MAXBUFFER, 0, NULL, 0);
            if(recu == -1)
            {
                perror("\n\nError recvfrom ");
                printf("Error Code : %d", WSAGetLastError());
            }
            else
            {
                printf("message = %s\n", buff);
            }
        }
    }

(我的机器上还运行着一个乒乓服务器来测试代码)

当我启动此应用程序时,recvfrom()不会被阻止,并返回错误10022,直到我使用Sending()函数。正是当我使用fgets()时,recvfrom()停止返回错误。

如何阻止此错误的发生?

P.S .:我的机器在Windows 10下。

编辑:

我尝试了其他操作,我在函数bind()中使用了Receiving(),但是它不起作用,这是我的代码:

void *Receiving(void *VarThread)
{
    int sock = *(int *)VarThread;
    struct sockaddr_in SockRecv;
    int slen = sizeof(SockRecv);
    char buff[MAXBUFFER];
    ssize_t recu;




    memset((char *)&SockRecv, 0, sizeof(SockRecv));
    SockRecv.sin_family = AF_INET;
    SockRecv.sin_addr.s_addr = htonl(SERVER); 
    SockRecv.sin_port = htons(PORT);

    if(bind(sock, (struct sockaddr *)&SockRecv, sizeof(SockRecv)) == -1)
    {
        perror("\n\nbind()");
        printf("Error Code : %d", WSAGetLastError());
        exit(0);
    }




    while(1)
    {
        recu = recvfrom(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&SockRecv, &slen);
        if(recu == -1)
        {
            perror("\n\nError recvfrom()");
            printf("Error Code : %d", WSAGetLastError());
        }
        else
        {
            printf("Message = %s\n", buff);
        }
    }
}

3 个答案:

答案 0 :(得分:0)

错误10022为WSAEINVALThe microsoft documentation of recvfrom指定由该功能(强调我的功能)引起的含义:

  

套接字尚未与bind绑定,或者指定了未知标志,   为启用了SO_OOBINLINE的套接字指定了MSG_OOB,或者   (仅适用于字节流样式的套接字)len为零或负。

您尝试将其绑定到第二个代码片段中时遇到了另一个问题。您应该在启动任何一个线程之前绑定套接字,以避免接收线程中的绑定与作为发送一部分的隐式绑定之间发生竞争。

尽管您没有明确说明绑定的使用失败方式,但我的猜测是添加绑定代码会使接收方延迟足够长的时间,使发送方首先绑定,此后接收方的绑定失败,因为您无法两次绑定套接字

答案 1 :(得分:0)

接收功能

void *Receiving(void *VarThread)
{
    int sock = *(int *)VarThread;
    struct sockaddr_in AddrRecv;
    struct sockaddr_in AddrSend;
    int LenAddrSend = sizeof(AddrSend);
    char buff[MAXBUFFER];
    ssize_t recu;

    memset((char *)&AddrRecv, 0, sizeof(AddrRecv));
    AddrRecv.sin_family = AF_INET;
    AddrRecv.sin_addr.s_addr = htonl(INADDR_ANY); //inet_addr(SERVER);
    AddrRecv.sin_port = htons(PORT);

    if(bind(sock, (struct sockaddr *)&AddrRecv, sizeof(AddrRecv)) != 0)
    {
        perror("\n\nbind()");
        printf("Error Code : %d", WSAGetLastError());
        exit(0);
    }




    while(1)
    {
        recu = recvfrom(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&AddrSend, &LenAddrSend);
        if(recu == -1)
        {
            perror("\n\nError recvfrom()");
            printf("Error Code : %d", WSAGetLastError());
        }
        else
        {
            printf("Message = %s\n", buff);
        }
    }
}

答案 2 :(得分:0)

这是最后的代码,这要感谢@ Griffon26和@Gerhardh

#include <sys/types.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

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

#define SERVER "127.0.0.1"
#define PORT 8888
#define MAXBUFFER 1024

void *Sending(void *VarThread);
void *Receiving(void *VarThread);

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

    int sock;
    int i;

    pthread_t Thread_ID_1;
    pthread_t Thread_ID_2;

    WSADATA WSAData;
    WSAStartup(MAKEWORD(2, 0), &WSAData);


    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock == INVALID_SOCKET)
    {
        perror("\nsocket()");
        printf("%d", WSAGetLastError());
        exit(0);
    }


    struct sockaddr_in AddrRecv;

    memset((char *)&AddrRecv, 0, sizeof(AddrRecv));
    AddrRecv.sin_family = AF_INET;
    AddrRecv.sin_addr.s_addr = htonl(INADDR_ANY);
    AddrRecv.sin_port = htons(PORT);

    if(bind(sock, (struct sockaddr *)&AddrRecv, sizeof(AddrRecv)) != 0)
    {
        perror("\n\nbind()");
        printf("Error Code : %d", WSAGetLastError());
        exit(0);
    }


    pthread_create(&Thread_ID_1, NULL, Sending, (void *)&sock);
    pthread_create(&Thread_ID_2, NULL, Receiving, (void *)&sock);

    pthread_join(Thread_ID_1, NULL);
    pthread_join(Thread_ID_2, NULL);

    close(sock);
    WSACleanup();
    return 0;
}

void *Sending(void *VarThread)
{
    int sock = *(int *)VarThread;
    int i;

    struct sockaddr_in si;
    si.sin_family = AF_INET;
    si.sin_addr.s_addr = inet_addr(SERVER);
    si.sin_port = htons(PORT);

    char buff[MAXBUFFER];
    ssize_t message;

    while(1)
    {
        fgets(buff, MAXBUFFER, stdin);
        for(i = 1; i < MAXBUFFER; i++)
        {
            if(buff[i] == '\0')
            {
                buff[i - 1] = '\0';
                i = MAXBUFFER;
            }
        }
        message = sendto(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&si, sizeof(si));
        if (message == -1)
        {
            perror("\nsendto()");
            printf("%d", WSAGetLastError());
        }
    }
}


void *Receiving(void *VarThread)
{
    int sock = *(int *)VarThread;
    struct sockaddr_in AddrSend;
    int LenAddrSend = sizeof(AddrSend);
    char buff[MAXBUFFER];
    ssize_t recu;

    while(1)
    {
        recu = recvfrom(sock, buff, MAXBUFFER, 0, (struct sockaddr *)&AddrSend, &LenAddrSend);
        if(recu == -1)
        {
            perror("\n\nError recvfrom()");
            printf("Error Code : %d", WSAGetLastError());
        }
        else
        {
            printf("Message = %s\n", buff);
        }
    }
}