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

发布于 2024-11-26 18:51:47 字数 2926 浏览 2 评论 0原文

我正在使用 UDP 编写一些简单的客户端/服务器代码。程序工作正常,但如果我只启动客户端,recvfrom方法不会阻塞。但是,当我删除 sendto 方法时,recvfrom 开始阻塞。知道发生了什么事吗?

这是客户端代码:

    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);
    }

这是初始化:

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);
    }

I am writing some simple client/server code using UDP. The program works fine, but if I only start the client, the recvfrom method does not block. However, when I remove the sendto method, recvfrom starts to block. 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 *)¤t_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(¤t_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);
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

睫毛上残留的泪 2024-12-03 18:51:47

sendto 失败的原因有很多种。有些(例如 arp 失败)会在 sendto 期间导致错误。其他的,例如 ICMP port unreachable,可能会在您下次使用套接字时报告。

您的 recvfrom 调用实际上可能正在获取响应您的传出数据包而发送的 ICMP 数据包。

第二个 recvfrom 是否按预期阻塞?

There are a variety of ways that sendto can fail. Some, such as arp failure, will cause an error during sendto. Other, such as ICMP port unreachable, may be reported when you next use the socket.

Your recvfrom call could actually be fetching the ICMP packet sent in response to your outgoing packet.

Does a second recvfrom block as expected?

东走西顾 2024-12-03 18:51:47

套接字需要设置为 BLOCKING/NON-BLOCKING。

  1. 设置阻止

     int nMode = 0; // 0: 阻塞
     if (ioctlsocket(objSocket, FIONBIO, &nMode) == SOCKET_ERROR)
     {
        closesocket(SendingSocket);
        WSACleanup();
        返回iRet;
     }
    
  2. 设置非阻塞

     int nMode = 1; // 1:非阻塞
     if (ioctlsocket(objSocket, FIONBIO, &nMode) == SOCKET_ERROR)
     {
        closesocket(SendingSocket);
        WSACleanup();
        返回iRet;
     }
    

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;
     }
    
完美的未来在梦里 2024-12-03 18:51:47

看起来您正在以相同的方式设置服务器套接字和客户端套接字。对于服务器来说,初始化看起来不错,但对于客户端来说,您需要绑定到端口 0。

事实上,对于这两个客户端,您都可以执行 INADDR_ANY (IP 0.0.0.0),它不会绑定到特定接口,而是允许正确端口上的任何连接。

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文