当前位置:  开发笔记 > 编程语言 > 正文

我是否必须在客户端程序中绑定UDP套接字才能接收数据?(我总是得到WSAEINVAL)

如何解决《我是否必须在客户端程序中绑定UDP套接字才能接收数据?(我总是得到WSAEINVAL)》经验,为你挑选了2个好方法。

我创建一个UDP套接字(AF_INET,SOCK_DGRAM,IPPROTO_UDP通过Winsock的),并试图recvfrom在此套接字上,但它总是返回-1,我得到WSAEINVAL(10022).为什么?

当我bind()的端口,这不会发生,但我已经读到绑定客户端的套接字是非常蹩脚的.

我正在向我的服务器发送数据,该服务器回答或至少尝试过.

Inc::STATS CConnection::_RecvData(sockaddr* addr, std::string &strData)
{
    int ret;            // return code
    int len;            // length of the data
    int fromlen;        // sizeof(sockaddr)
    char *buffer;       // will hold the data
    char c;

    //recv length of the message
    fromlen = sizeof(sockaddr);
    ret = recvfrom(m_InSock, &c, 1, 0, addr, &fromlen);
    if(ret != 1)
    {
#ifdef __MYDEBUG__
        std::stringstream ss;
        ss << WSAGetLastError();
        MessageBox(NULL, ss.str().c_str(), "", MB_ICONERROR | MB_OK);
#endif
        return Inc::ERECV;
    }
    ...

这是我刚才写的一个工作示例,它bind()在没有客户端调用的情况下工作:

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

#define WIN32_LEAN_AND_MEAN

#include 
#include 
#include 

using namespace std;

int main()
{
    SOCKET sock;
    addrinfo* pAddr;
    addrinfo hints;
    sockaddr sAddr;
    int fromlen;
    const char czPort[] = "12345";
    const char czAddy[] = "some ip";

    WSADATA wsa;
    unsigned short usWSAVersion = MAKEWORD(2,2);

    char Buffer[22] = "TESTTESTTESTTESTTEST5";
    int ret;

    //Start WSA
    WSAStartup(usWSAVersion, &wsa);

    //Create Socket
    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    //Resolve host address
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_protocol = IPPROTO_UDP;
    hints.ai_socktype = SOCK_DGRAM;

    if(getaddrinfo(czAddy, czPort, &hints, &pAddr))
    {
        std::cerr << "Could not resolve address...\n";
        std::cin.get();
        return 1;
    }

    //Start Transmission
    while(1)
    {
        ret = sendto(sock, Buffer, sizeof(Buffer), 0, pAddr->ai_addr,
                     pAddr->ai_addrlen);
        if(ret != sizeof(Buffer))
        {
            std::cerr << "Could not send data\n";
            std::cin.get();
            return 1;
        }

        fromlen = sizeof(SOCKADDR);
        ret = recvfrom(sock, Buffer, sizeof(Buffer), 0, &sAddr, &fromlen);
        if(ret != sizeof(Buffer))
        {
            std::cout << "Could not receive data -  error: " << 
                          WSAGetLastError() << std::endl;
            std::cin.get();
            return 1;
        }

        Buffer[ret-1] = '\0';
        std::cout << "Received: " << Buffer << std::endl;
    }
    return 0;
}

Warren Young.. 42

使用UDP,您必须bind()使用客户端中的套接字,因为UDP是无连接的,因此堆栈无法知道将数据报传递给特定端口的程序.

如果recvfrom()没有bind(),你基本上要求堆栈为你的程序提供发送到该计算机的所有UDP数据报.由于堆栈只向一个程序提供数据报,这将破坏DNS,Windows的网络邻居,网络时间同步....

您可能已经在网上某处读过客户端绑定很蹩脚,但该建议仅适用于TCP连接.



1> Warren Young..:

使用UDP,您必须bind()使用客户端中的套接字,因为UDP是无连接的,因此堆栈无法知道将数据报传递给特定端口的程序.

如果recvfrom()没有bind(),你基本上要求堆栈为你的程序提供发送到该计算机的所有UDP数据报.由于堆栈只向一个程序提供数据报,这将破坏DNS,Windows的网络邻居,网络时间同步....

您可能已经在网上某处读过客户端绑定很蹩脚,但该建议仅适用于TCP连接.


没有看到您的代码,我只能猜测,但是我认为您是将端口号放入传递给“ from”参数的结构中。那没有帮助。该参数不会被堆栈读取,只会被写入,因此您的程序可以知道谁发送了数据报。请注意,它是可选的,因此您可以在此处传递0,因此您又回到了以前的情况,在该情况下,堆栈必须有某种方式来仅根据传入的端口号来知道将数据报传递到哪个程序在上。这就是bind()的作用:它将程序与端口相关联。
我不会说sendto()绑定了套接字,但的确,您不必bind()即可使用sendto()。由于UDP的无连接性质,recvfrom()是不同的。本质上,即使您将recvfrom()视为客户端,使用recvfrom()的程序也是“服务器”,因为像TCP服务器一样,调用recvfrom()的程序必须坐在等待来自任何可能发件人的数据的位置。

2> Mecki..:

您的其他代码示例有效,因为您sendto之前使用过recvfrom.如果UDP套接字未绑定且已在其上调用sendto或被connect调用,则系统将自动为您绑定它,因此recvfrom稍后调用将成功.recvfrom不会绑定套接字,因为此调用期望套接字已被绑定,否则将引发错误.

推荐阅读
135369一生真爱_890
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有