2

I have a UDP client C++ code - based on WSA sockets - that works well. The code was originally written in VS6 and I recently recompiled it in VS2010 for 64bit environment, with only little adjustments.

Now, the sendto() fails to send something, if there is no Sleep(..) or any equivalent delay after the sendto() and before closesocket(). "Fails" means, that sendto() returns the proper amount of data, but I see no message on the network (I used wireshark to check this).

This is my code:

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

}

Without the Sleep(), the code does not send anything, yet it returns no errors. With the Sleep() it works. Also, this is happens in release version, when compiled for debug, the code also works without the Sleep().

It seems, as if the closesocket() shuts the socket down, before the message is finally sent, but I thought sendto() is a synchronous function. I tried using SO_LINGER, but this is not applicable for SOCK_DGRAM sockets.

Since the code is inside a DLL, I can't create the socket in ctor and delete it in the dtor, because SendHello() might be called from different thread contexts, and I like to avoid to make the code too complicated.

thanks for any help

user3677092
  • 31
  • 1
  • 4
  • How do you tell that it doesn't send anything? – Ulrich Eckhardt May 26 '14 at 17:14
  • The two `*((DWORD*) &pTxBuffer[ 0]) = 0x11223344;` lines are creative. You may want to use `char pTxBuffer[8] = {0x44, 0x33, 0x22, 0x11};` to the same effect. – zneak May 26 '14 at 17:15
  • @UlrichEckhardt, question says Wireshark doesn't see anything. – zneak May 26 '14 at 17:15
  • 1
    Wireshark ... true, but where? On the target machine? If so, that could be misleading, as UDP in unreliable. The only thing that should work almost always is that sending the packet on an idle network interface shows up as outgoing packet. That said, I would try calling `shutdown()` on the socket. This shouldn't be necessary, but out of curiosity whether it changes anything. Further, I'd try creating the customary minimal example, in particular without MFC. – Ulrich Eckhardt May 26 '14 at 20:21

1 Answers1

0

With UDP there is no ordering of data between the sender and receiver and data sent using UDP datagram sockets isn't guaranteed to arrive. All sleep is doing in your case is practically providing enough time for the data to arrive at the other end. If you want confirmation of receipt and error checking, then you can either code a scheme for UDP or use TCP. In fact, you can turn off the server completely and your client will happily fire UDP packets out without error even though there is nobody listening.

to insure a connection, look at connect(). Nothing prevents using connect with UDP and you can then use send() recv().

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • 1
    UDP is connectionless and unreliable, so what should `connect()` do other than setting a sticky target address? I didn't try this, but in all honesty, your suggestion doesn't make sense to me. Also, if you read the documentation, then you should see that `sendto()` should work synchronously, so nothing that you do afterwards should change the fact that the packet gets sent (whether it arrives is a different issue). – Ulrich Eckhardt May 26 '14 at 20:12
  • Stating that UDP is unreliable is silly (although technically correct). UDP is none less reliable than TCP, since they both use the same transport. The only difference is that TCP acknowledges packets and avoids congestion. Other than on Wifi or very bad internet routes, there is no such thing as "magically disappearing" datagrams, at least not on a measurable scale. The #1 source of UDP being unreliable is datagrams being dropped when receive buffers are full. That isn't the case here (one datagram sent). – Damon May 26 '14 at 20:27
  • 1
    Well, TCP reliably transmits the data or visibly fails. UDP does no such thing. I don't find this difference silly. – Ulrich Eckhardt May 28 '14 at 17:39
  • Well, the problem is we only have insight into `Test::SendHello()` and it simply fires UDP packets to server and port, there is no way to tell what if anything server is doing in response. Second, since this is a recompile to 64-bit, the issue may lie somewhere else entirely. Finally, as to the question of how to test if `sendto` is working absent `wait`, tcpdump can monitor traffic leaving client something like `tcpdump -i eth0 -c [count] -w [filename] host client` would capture all traffic to/from client. Then just open filename in wireshark (you can set the options in wireshark as well) – David C. Rankin May 29 '14 at 01:35