C ++ UDP. Почему recvfrom () не блокирует? - PullRequest
3 голосов
/ 29 июля 2011

Я пишу простой клиент-серверный код, используя 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 ]

6 голосов
/ 29 июля 2011

Есть множество способов, которыми sendto может потерпеть неудачу.Некоторые из них, такие как сбой arp, вызовут ошибку во время sendto.При следующем использовании сокета может появиться сообщение о другом, например ICMP port unreachable.

Ваш recvfrom вызов может фактически получать пакет ICMP, отправленный в ответ на ваш исходящий пакет.

Второй recvfrom блокируется, как ожидалось?

2 голосов
/ 27 октября 2014

Необходимо установить гнездо BLOCKING / NON-BLOCKING.

  1. Набор БЛОКИРОВКА

     int nMode = 0; // 0: BLOCKING
	 if (ioctlsocket (objSocket, FIONBIO, &nMode) == SOCKET_ERROR)
	 {
 		closesocket(SendingSocket);
 		WSACleanup();
        return iRet;
	 }
  1. Установить НЕБЛОКИРОВКУ

         int nMode = 1; // 1: NON-BLOCKING
    	 if (ioctlsocket (objSocket, FIONBIO, &nMode) == SOCKET_ERROR)
    	 {
     		closesocket(SendingSocket);
     		WSACleanup();
            return iRet;
    	 }
0 голосов
/ 29 июля 2011

Похоже, вы настраиваете сокет сервера и сокет клиента одинаково. Инициализация выглядит хорошо для сервера, но для клиента вам нужно привязать к порту 0.

Фактически, для обоих из них вы можете сделать INADDR_ANY (IP 0.0.0.0), который не привязывается к определенному интерфейсу, но вместо этого разрешает любое соединение через правильный порт.

...