2014-05-26 2 views
2

У меня есть код UDP-клиента C++ на основе сокетов WSA - это хорошо работает. Код был первоначально написан на VS6, и я недавно перекомпилировал его в VS2010 для 64-битной среды с небольшими корректировками.C++ UDP sendto сбой, нужен сон

Теперь sendto() не отправляет что-либо, если нет сна (..) или любой эквивалентной задержки после sendto() и перед closesocket(). «Сбой» означает, что sendto() возвращает нужный объем данных, но я не вижу сообщений в сети (я использовал wirehark для проверки этого).

Это мой код:

void CTest::SendHello() 
{ 
    SOCKET sSocket; 
    sSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 

    struct sockaddr_in addr; 
    addr.sin_family  = AF_INET; 
    addr.sin_addr.s_addr = inet_addr(m_strDstIpAddr); 
    addr.sin_port   = htons(m_nTxPort); 

    int nMsgLen = 8; 
    char pTxBuffer[8]; 
    *((DWORD*) &pTxBuffer[ 0]) = 0x11223344; 
    *((DWORD*) &pTxBuffer[ 4]) = 0; 

    int nSent = sendto(sSocket, pTxBuffer, nMsgLen, 0, (struct sockaddr *) &addr, sizeof(addr)); 
    Sleep(10); // <- this seems to be necessary 

    if (nSent != nMsgLen) 
    { 
    CString s = "error sending HELO\n"; 
    AfxMessageBox(s); 
    } 
    closesocket(sSocket); 

}

Без сна(), код не посылает ничего, пока он не вернется без ошибок. С Sleep() он работает. Кроме того, это происходит в версии выпуска, при компиляции для отладки, код также работает без Sleep().

Кажется, как будто closesocket() закрывает сокет до отправки сообщения, но я думал, что sendto() является синхронной функцией. Я попытался использовать SO_LINGER, но это не относится к сокетам SOCK_DGRAM.

Поскольку код находится внутри DLL, я не могу создать сокет в ctor и удалить его в dtor, потому что SendHello() может быть вызван из разных контекстов потоков, и мне нравится избегать кода сложно.

спасибо за любую помощь

+0

Как вы говорите, что ничего не посылаете? –

+0

Две строки '* ((DWORD *) & pTxBuffer [0]) = 0x11223344; строки являются креативными. Вы можете использовать 'char pTxBuffer [8] = {0x44, 0x33, 0x22, 0x11};' для того же эффекта. – zneak

+0

@UlrichEckhardt, вопрос говорит, что Wireshark ничего не видит. – zneak

ответ

0

С UDP нет упорядочивания данных между отправителем и получателем и данными, передаваемыми с использованием UDP датаграмм сокетов не гарантируются прибыть. Все сон в вашем случае практически обеспечивает достаточное время для поступления данных на другой конец. Если вы хотите подтвердить получение и проверку ошибок, вы можете либо закодировать схему для UDP, либо использовать TCP. Фактически, вы можете полностью отключить сервер, и ваш клиент будет с радостью запускать пакеты UDP без ошибок, даже если никто не слушает.

для обеспечения соединения, посмотрите на connect(). Ничто не мешает использовать соединение с UDP, и вы можете использовать send() recv().

+1

UDP является бесконтактным и ненадежным, поэтому что нужно «connect()» делать иначе, чем устанавливать липкий целевой адрес? Я не пробовал это, но, честно говоря, ваше предложение не имеет для меня смысла. Кроме того, если вы прочтете документацию, вы должны увидеть, что 'sendto()' должен работать синхронно, поэтому ничего, что вы потом сделаете, должно изменить тот факт, что пакет отправляется (приходит ли он другой вопрос). –

+0

Утверждение, что UDP ненадежно, является глупым (хотя и технически правильным). UDP не менее надежный, чем TCP, поскольку оба они используют один и тот же транспорт. Единственное различие заключается в том, что TCP подтверждает пакеты и избегает перегрузок. Помимо того, что на Wi-Fi или очень плохих интернет-маршрутах нет такой вещи, как «магически исчезающие» датаграммы, по крайней мере, не в измеримом масштабе. Источником недопустимого источника UDP №1 являются датаграммы, которые удаляются при заполнении буферов приема. Это не так (одна датаграмма отправлена). – Damon

+0

Ну, TCP надежно передает данные или явно не работает. UDP этого не делает. Я не считаю это различие глупым. –