C++ udp recvfrom reduce drops

I have quite standard setup of my udp receiver socket. My sender sends data at 36Hz and receiver reads at 72Hz. 12072bytes per send.

When I do cat /proc/net/udp. I get usually

 sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode ref pointer drops 
 7017: 0101007F:0035 00000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 10636 2 0000000000000000 0         
 7032: 00000000:0044 00000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 14671 2 0000000000000000 0         
 7595: 00000000:0277 00000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 11113 2 0000000000000000 0         
 7660: 00000000:22B8 00000000:0000 07 00000000:00004100 00:00000000 00000000  1000        0 251331 3 0000000000000000 352743   

You can see the rx_queue has some values in there, reads not fast enough ?

My code

    int recv_len = recvfrom(s, buf, BUFLEN, MSG_TRUNC, (struct sockaddr *) &si_other, &slen); 
   // dont worry buflen is like 64000 no error here

    std::cout <<" recv_len "<<recv_len<<std::endl;

I always get output as recv_len 12072 even though the queue is quite big ? why is this ? Is there a way to speed up my read or read all the messages in the queue ? I dont understand what's wrong even my read frequency is higher.

Upvotes: 0

Views: 439

Answers (1)

Gil Hamilton
Gil Hamilton

Reputation: 12337

UDP datagrams always travel as a complete atomic unit. If you send a 12072 byte UDP datagram, your receiver will get exactly one 12072 byte datagram or nothing at all -- you won't ever receive a partial message (*) or multiple messages concatenated.

Note that with datagrams of this size, they're almost certainly being fragmented at the IP layer because they're probably larger than your network's MTU (maximum transmission unit). In that case, if any one of the fragments is dropped along the way or at the receiving host or found to be corrupted, the entire UDP datagram will be dropped.

(* A message may be truncated if the buffer provided to recvfrom is too small, but it will never even be considered for receiving if the entire message could not be reassembled in the kernel.)

If you are unable to receive all the messages being sent, I would check whether you need to increase the kernel buffer space allocated to UDP. This is done with the sysctl utility. Specifically you should check and possibly adjust the values of net.core.rmem_max and net.ipv4.udp_mem. See the corresponding documentation:
https://www.kernel.org/doc/Documentation/sysctl/net.txt
https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt

Finally, it seems a bit curious to talk about "read frequency" -- I assume that means you are polling the socket 72 times per second? Why not just dedicate a thread to reading from the socket. Then the thread can block on the recvfrom and the receive will complete with the least possible latency. (In any case, this is worth a try, even if only for a test -- to see if the polling is contributing to your inability to keep up with the sender.)

Upvotes: 3

Related Questions