L. Terrat
L. Terrat

Reputation: 47

C++, UDP, sendto needs delay to work

I am programming a UDP Relaying Server in C++. But I have a problem.

I have a basic loop that just calls recvfrom(), checks for errors in the packet, then reads the "target" out of the packet and uses sendto() on the same socket to send a packet to the target client that is also relaying on the same server.

The problem is that nearly all packets get lost if I don't add a delay before the sendto() (this delay depends on the connection speed, so I can´t set it statically).

m_iSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bind(m_iSocket, (SOCKADDR*)&m_oSockAddress, sizeof(SOCKADDR_IN));
...
while(true) {
    recvfrom(m_iSocket, (char*)m_pRecvBuffer, m_nBufferSize, 0, (SOCKADDR*)&remoteAddr, &remoteAddrLen);
    ...
    sendto(m_iSocket, reinterpret_cast<char*>(rw.getData()), rw.getBufferSize(), 0, targets address , address size);
}

Any ideas?

Upvotes: 0

Views: 3168

Answers (2)

user207421
user207421

Reputation: 311031

The target process isn't reading fast enough, so datagrams are being dropped because its socket receive buffer is full. The question then arises as to what the correct mitigation is:

  1. (If you can) speed up the receiver.
  2. Add a delay into your loop. This only moves the problem downstream to whoever is sending you these datagrams. Datagrams inbound to you will be dropped when your socket receiver buffer is full.
  3. Do nothing. It's not your problem; your code is correct.

I recommend (1) if possible, and (3). Don't add delays into networking code. They don't solve problems: they only change them.

If you have access to all the relevant source code, you should increase the size of all socket send and receive buffers concerned.

Upvotes: 0

Jeremy Friesner
Jeremy Friesner

Reputation: 73294

Any ideas?

Most likely your outgoing UDP packets are getting dropped because a buffer is overflowing somewhere. The most likely place for it to overflow would be in your socket's own outgoing-data buffer; if so, you might be able to reduce the number of dropped packets by calling setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, ...) to make your socket's outgoing-buffer-size larger (i.e. large enough to send hold all of the packets you pass over via sendto() calls at one time).

If that's not enough to deal with the problem, then the next thing you can do is implement your own in-application buffering; i.e. instead of just immediately calling sendto(), push the packet data to the tail of a FIFO data structure, and then only call sendto() when the socket select()'s as ready-for-write (and when that happens, pop the next packet from the head of the FIFO and call sendto() with that). That way you're always sending data only at the speed the socket's buffer can accept it, rather than assuming the socket's buffer will always be large enough to immediately accept everything you throw at it.

(The other place where a buffer might be overflowing is on the receiving app's socket's receive-buffer, in which case a call to setsockopt(s, SOL_SOCKET, SO_RCVBUF, ...) on the receiving app's socket might also help)

Upvotes: 1

Related Questions