Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to solve: sending UDP packet using Sendto() got "message too long"

I want to use the sendto() API to send video and audio data through UDP packet. The sending buffer size I got using getsockopt() is 114688, however, sendto() returned -1 when the data packet less than 65536 not 114688. And the error message is Message too long.

When I used setsockopt() to adjust the sending buffer size as 200000, I used getsockopt() and found the sending buffer size was not 200000 but 262142. So I still got the same error when I sent data packet with a size bigger than 65536.

I am confused about this situation. I want to know what the reason is and how to solve this problem.

When I used FFMPEG library to send the video and audio packet, there is no error. So I am sure there is a solution for this problem and I missed something.

Is there anyone can help me about this problem? I really can not understand what the reason is.

The OS I used is ubuntu 11.04,I got the same results in ubuntu 11.10.

That is the code I used to create socket and configure the parameter:

unsigned char *output_buffer = (unsigned char*)av_malloc(IO_BUFFER_SIZE);
if (NULL == output_buffer) {
    printf("Couldn't allocate input buffer.\n");
    return NULL;
}

output_context_data_t *context_data = (output_context_data_t *)malloc(sizeof(output_context_data_t));
if (NULL == context_data) {
    printf("Could not allocate output context data.\n");
    av_free(output_buffer);
    return NULL;
}

context_data->socket = socket(AF_INET, SOCK_DGRAM, 0);
if(context_data->socket < 0) {
    printf("socket creating fail!\n");
    return NULL;    
}

context_data->socket_addr->sin_family = AF_INET;
context_data->socket_addr->sin_port = htons(output_port);
ret = inet_pton(AF_INET, output_ip, &(context_data->socket_addr->sin_addr));
if(0 == ret) {
    printf("inet_pton fail!\n");
    return NULL;
}

ret = setsockopt(context_data->socket, IPPROTO_IP, IP_MULTICAST_TTL,
                    &option_ttl, sizeof(int));
if(ret < 0) {
    printf("ttl configuration fail!\n");
    return NULL;
}

ret = setsockopt(context_data->socket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
if(ret < 0) {
    printf("resue configuration fail!\n");
    return NULL;
}   

That is the code to send UDP packet:

int send_size = sendto(context_data->socket, buf, buf_size, 0,
                      (struct sockaddr *)context_data->socket_addr, sizeof(*context_data->socket_addr)));
//the video or audio data is in buf and its size is buf_size.

That is the code I used to get the sending buffer size:

int bufsize; 
int size = sizeof(bufsize);
getsockopt(context_data->socket,SOL_SOCKET, SO_SNDBUF, &bufsize, &size);

That is the code I used to configure the sending buffer size:

tmp = 200000;
ret = setsockopt(context_data->socket, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp));
if(ret < 0) {
    printf("sending buffer size configuration fail!\n");
    return NULL;
}
like image 753
user1290120 Avatar asked Mar 24 '12 15:03

user1290120


2 Answers

You can not send messages (datagrams) larger than 2^16 65536 octets with UDP. The length field of a UDP packet is 16 bits. The buffer sizes you're requesting are not about the size for a packet, but how many octets the OS does buffer incoming and outgoing in total (spread over multiple packets). But a single packet can not get larger.

like image 187
datenwolf Avatar answered Sep 22 '22 12:09

datenwolf


Per @datenwolf's answer, you simply can't send more than 64k in a single UDP datagram, as that limit is implicit in the two-byte length field in the protocol.

Furthermore, it's not actually a good idea to send even that much at once. You should limit your packets to the MTU on the path between the two ends (typically in the region of 1500 bytes or less) so that you don't get fragmentation in the IP layer.

Fragmentation is bad - ok?

like image 31
Alnitak Avatar answered Sep 25 '22 12:09

Alnitak