Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delay increases sometimes when sending buffer via UDP socket

I've developed an MPEG-ts Streamer. It reads the packets from a file and sends them at the right pace to the receiver.

Now everything works fine excluding that I have some lags quite often. I have searched for every possible error in my code. I have optimized my program quite a bit performance wise.

Now I keep a log with the time it takes the sendto() function to send the packet and I also log the difference between when the packet should have been sent and when it is sent.

I noticed that every time the packets are a lot later than average, the time it took the sendto() to send the previous packet is much higher than normal too.

This indicates me that it is the sendto() that is causing those lags every time it somehow takes longer to send a packet. I am using UDP sockets.

Am I maybe doing something wrong with the sockets? Could it be possible that the socket buffer is full and that it actually takes longer to send the packet? Or am I missing something? Is there maybe a way to accelerate the socket or to make it not fill it's buffer completely before sending?

As this is meant to stream video I am quite depending on the performance, mostly for HD where the lags happen more often as the amount of packets is much higher.

like image 776
Helder AC Avatar asked Feb 23 '12 08:02

Helder AC


People also ask

What happens when UDP socket buffer is full?

It'll stay in the socket buffer until you read it or the process exits. Once the socket buffer is full, new packets arriving is dropped.

Does UDP use a buffer?

TCP reassembles the original segments and places the input in the socket receive buffer. UDP simply passes the input on to the socket receive buffer.

How many UDP packets can be sent per second?

To begin, try a value within the range 50,000 to 150,000 packets per second. Select an initial value based on capacity of the receiving CPUs to handle NIC interrupts. To reduce average latency, try raising the value. If the number of packets overwhelms any receiver, try a lower value.

What is buffer size in UDP?

The default send buffer size for UDP sockets is 65535 bytes. The default receive buffer size for UDP sockets is 2147483647 bytes.


2 Answers

There are only two reasons for sendto() to block:

  • Your outgoing UDP buffer is full, and it needs to wait until space frees up
  • The CPU scheduler simply decides to do something else for a while, as it can with any syscall.

Check the size of your outgoing buffer:

int buff_size;
int len = sizeof(buff_size);

err = getsockopt(s,SOL_SOCKET,SO_SNDBUF,(char*)&size,&len);

Some linux systems default to absurdly small send buffers (only a few kilobytes), so you may need to set it to something larger.

If buffer is larger and sendto() is briefly blocking anyway (how long exactly?) then that's probably just the cost of doing business. Even on a LAN, and certainly on a WAN, latency is going to vary a lot.

Update

To increase the system limit on UDP buffer sizes:

sysctl -w net.core.wmem_max=1048576
sysctl -w net.core.rmem_max=1048576

You can make this permanent by adding the following lines to /etc/sysctl.conf:

net.core.wmem_max=1048576
net.core.rmem_max=1048576

To take advantage of this within your application, you need to use setsockopt():

int len, trysize, gotsize;
len = sizeof(int);
trysize = 1048576+32768;
do {
   trysize -= 32768;
   setsockopt(s,SOL_SOCKET,SO_SNDBUF,(char*)&trysize,len);
   err = getsockopt(s,SOL_SOCKET,SO_SNDBUF,(char*)&gotsize,&len);
   if (err < 0) { perror("getsockopt"); break; }
} while (gotsize < trysize);
printf("Size set to %d\n",gotsize);

Repeat the same thing for SO_RCVBUF. The loop is important because many systems silently enforce a maximum which is less than the max you set with sysctl and when setsockopt() fails, it leaves the previous value untouched. So you have to try many different values until you get one that sticks. Its also important to not test for (gotsize == trysize) because on some systems the result which is set is not actually the same as the one you requested.

like image 63
Seth Noble Avatar answered Sep 18 '22 23:09

Seth Noble


Unlike TCP, UDP does not buffer data. Source code would definitively help to understand things better. How big are the packets you are sending? In UDP it would be best to keep the payload at the size of the MTU (1500 bytes)

like image 25
mac Avatar answered Sep 19 '22 23:09

mac