首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >多线程时由recvfrom()返回的错误10022 (C)

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

Stack Overflow用户
提问于 2018-12-22 03:00:58
回答 3查看 620关注 0票数 0

我对套接字编程和多线程还很陌生,我还在学习它,但是我有一个我无法解决的问题,在其他一些主题上,我找到了一些答案,但它们看起来与我没有相同的问题。

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

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

我将librairy pthread.h用于多线程,winsock2.h用于套接字。

当我没有多线程时,就没有问题了。

我的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    #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()停止返回错误。

我怎样才能阻止这个错误的发生?

我的机器在Windows 10下。

编辑:

我尝试过其他方法,我在函数bind()中使用了Receiving(),但它不起作用,下面是我的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);
        }
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-12-22 07:10:07

错误10022是WSAEINVAL的microsoft文档指定了由该函数引起时的含义(强调“我的”):

没有用绑定绑定套接字,或者指定了未知标志,或者为启用SO_OOBINLINE的套接字指定了MSG_OOB,或者(仅用于字节流类型的套接字) len为零或负。

在第二个代码片段中绑定它的尝试有一个不同的问题。您应该在启动任何一个线程之前绑定套接字,以避免在接收线程中的绑定与作为发送的一部分的隐式绑定之间存在争用条件。

虽然您没有明确说明如何使用bind失败,但我的猜测是,添加bind代码会使接收方延迟足够长的时间,以便先让发送方绑定,然后接收方的bind失败,因为不能绑定两次套接字。

票数 0
EN

Stack Overflow用户

发布于 2018-12-22 07:22:15

接收功能

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
EN

Stack Overflow用户

发布于 2018-12-22 07:34:53

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53895036

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文