简体   繁体   English

C ++ UDP。 为什么recvfrom()没有阻止?

[英]C++ UDP. Why is recvfrom() is not blocking?

I am writing some simple client/server code using UDP. 我正在使用UDP编写一些简单的客户端/服务器代码。 The program works fine, but if I only start the client, the recvfrom method does not block. 该程序运行良好,但是如果我仅启动客户端,则recvfrom方法不会阻塞。 However, when I remove the sendto method, recvfrom starts to block. 但是,当我删除sendto方法时,recvfrom开始阻塞。 Any idea of what is going on? 有什么想法吗?

Here is the client side code: 这是客户端代码:

    int server_length;                      /* Length of server struct */
    char send_buffer[256] = "hi";           /* Data to send */
    time_t current_time;                    /* Time received */

    while(true)
    {

        /* Tranmsit data to get time */
        server_length = sizeof(struct sockaddr_in);
        if (sendto(m_oSocket, send_buffer, (int)strlen(send_buffer) + 1, 0, (struct sockaddr *)&m_oServer, server_length) == -1)
        {
            fprintf(stderr, "Error transmitting data.\n");
            continue;
        }

        /* Receive time */

        if (recvfrom(m_oSocket, (char *)&current_time, (int)sizeof(current_time), 0, (struct sockaddr *)&m_oServer, &server_length) < 0)
        {
            fprintf(stderr, "Error receiving data.\n");
            continue;
        }

        /* Display time */
        printf("Current time: %s\n", ctime(&current_time));

        Sleep(1000);
    }

And here is the initialization: 这是初始化:

unsigned short m_iPortnumber;
struct sockaddr_in m_oServer;
struct sockaddr_in m_oClient;
SOCKET m_oSocket;
WSADATA w;                              /* Used to open Windows connection */
    int a1, a2, a3, a4;                     /* Server address components in xxx.xxx.xxx.xxx form */

    a1 = 192;
    a2 = 168;
    a3 = 2;
    a4 = 14;
    m_iPortnumber = 52685;

    /* Open windows connection */
    if (WSAStartup(0x0101, &w) != 0)
    {
        fprintf(stderr, "Could not open Windows connection.\n");
        exit(0);
    }

    /* Open a datagram socket */
    m_oSocket = socket(AF_INET, SOCK_DGRAM, 0);
    if (m_oSocket == INVALID_SOCKET)
    {
        fprintf(stderr, "Could not create socket.\n");
        WSACleanup();
        exit(0);
    }

    /* Clear out server struct */
    memset((void *)&m_oServer, '\0', sizeof(struct sockaddr_in));

    /* Set family and port */
    m_oServer.sin_family = AF_INET;
    m_oServer.sin_port = htons(m_iPortnumber);

    /* Set server address */
    m_oServer.sin_addr.S_un.S_un_b.s_b1 = (unsigned char)a1;
    m_oServer.sin_addr.S_un.S_un_b.s_b2 = (unsigned char)a2;
    m_oServer.sin_addr.S_un.S_un_b.s_b3 = (unsigned char)a3;
    m_oServer.sin_addr.S_un.S_un_b.s_b4 = (unsigned char)a4;

    /* Clear out client struct */
    memset((void *)&m_oClient, '\0', sizeof(struct sockaddr_in));

    /* Set family and port */
    m_oClient.sin_family = AF_INET;
    m_oClient.sin_addr.s_addr=INADDR_ANY;
    m_oClient.sin_port = htons(0);

    /* Bind local address to socket */
    if (bind(m_oSocket, (struct sockaddr *)&m_oClient, sizeof(struct sockaddr_in)) == -1)
    {
        fprintf(stderr, "Cannot bind address to socket.\n");
        closesocket(m_oSocket);
        WSACleanup();
        exit(0);
    }

There are a variety of ways that sendto can fail. sendto可能有多种失败方式。 Some, such as arp failure, will cause an error during sendto . 某些错误(例如arp故障)将在sendto期间导致错误。 Other, such as ICMP port unreachable , may be reported when you next use the socket. 下次使用套接字时,可能会报告其他信息,例如ICMP port unreachable

Your recvfrom call could actually be fetching the ICMP packet sent in response to your outgoing packet. 您的recvfrom调用实际上可能是在获取响应您的传出数据包而发送的ICMP数据包。

Does a second recvfrom block as expected? 第二个recvfrom是否按预期阻止了?

Socket required to be set BLOCKING/NON-BLOCKING. 套接字需要设置为“阻止/非阻止”。

  1. Set BLOCKING 设定封锁

      int nMode = 0; // 0: BLOCKING if (ioctlsocket (objSocket, FIONBIO, &nMode) == SOCKET_ERROR) { closesocket(SendingSocket); WSACleanup(); return iRet; } 
  2. Set NON-BLOCKING 设置为非阻塞

      int nMode = 1; // 1: NON-BLOCKING if (ioctlsocket (objSocket, FIONBIO, &nMode) == SOCKET_ERROR) { closesocket(SendingSocket); WSACleanup(); return iRet; } 

It looks like you're setting up the server socket and the client socket the same way. 看起来您正在以相同的方式设置服务器套接字和客户端套接字。 The initialization looks good for a server, but for the client, you'll want to bind to port 0. 初始化对于服务器来说看起来不错,但是对于客户端,您将需要绑定到端口0。

In fact, for both of them you can do INADDR_ANY (IP 0.0.0.0), which doesn't bind to a specific interface, but instead allows any connection on the correct port. 实际上,对于它们两者,您都可以执行INADDR_ANY(IP 0.0.0.0),它不绑定到特定的接口,而是允许在正确的端口上进行任何连接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM