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

时间:2011-07-28 23:57:43

标签: c++ client udp winsock blocking

我正在使用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);
    }

3 个答案:

答案 0 :(得分:6)

sendto可能有多种失败方式。某些(例如arp失败)将在sendto期间导致错误。当您下次使用套接字时,可能会报告其他内容,例如ICMP port unreachable

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

是否会按预期阻止第二个recvfrom阻止?

答案 1 :(得分:2)

插座需要设置BLOCKING / NON-BLOCKING。

  1. 设置阻止
  2. &#13;
    &#13;
         int nMode = 0; // 0: BLOCKING
    	 if (ioctlsocket (objSocket, FIONBIO, &nMode) == SOCKET_ERROR)
    	 {
     		closesocket(SendingSocket);
     		WSACleanup();
            return iRet;
    	 }
    &#13;
    &#13;
    &#13;

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

答案 2 :(得分:0)

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

事实上,对于它们两者,您可以执行INADDR_ANY(IP 0.0.0.0),它不绑定到特定接口,而是允许在正确的端口上进行任何连接。