Ошибка 10022 возвращается функцией recvfrom () при многопоточности (C) - PullRequest
0 голосов
/ 22 декабря 2018

Я новичок в программировании сокетов и многопоточности, я все еще учусь этому, но у меня есть проблема, которую я не могу решить, по некоторым другим темам я нашел некоторые ответы, но они, кажется, не имеютта же проблема, что и у меня.

Я хотел бы создать UDP-клиент.Этот клиент должен иметь возможность отправлять (sendto()) и получать (recvfrom()).

Я использую многопоточность функции отправки и получения, но recvfrom() возвращает ошибку 10022 при вызовеWSAGetLastError().

Я использую библиотеку 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() isn '• блокировать и возвращать ошибку 10022, пока я не использую функцию Sending().Именно тогда, когда я использую fgets(), recvfrom() перестает возвращать ошибку.

Как я могу предотвратить возникновение этой ошибки?

PS: моя машина работает под 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 голосов
/ 22 декабря 2018

Функция получения

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);
        }
    }
}
0 голосов
/ 22 декабря 2018

Вот окончательный код, благодаря @ 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);
        }
    }
}
0 голосов
/ 22 декабря 2018

Ошибка 10022 - WSAEINVAL. В документации Microsoft для recvfrom указано, что это означает, когда она вызвана этой функцией (выделено мое):

Сокет не был связан с bind либо был указан неизвестный флаг, либо был указан MSG_OOB для сокета с включенным SO_OOBINLINE, либо (только для сокетов в стиле байтового потока) len было равно нулю или отрицательно.

Ваша попытка связать его ввторой фрагмент кода имеет другую проблему.Вы должны связать сокет перед запуском любого из потоков, чтобы избежать условия состязания между связыванием в принимающем потоке и неявным связыванием, которое является частью отправки.

Хотя вы не указали четко, как вы используетеиз-за сбоя связывания, я предполагаю, что добавление кода связывания задержало получателя на достаточно долгое время, чтобы позволить отправителю выполнить связывание первым, после чего связывание получателя не удалось, потому что вы не можете связать сокет дважды.

...