如何解决:使用 Sendto() 发送 UDP 数据包得到“消息太长";如何解决、太长、数据包、消息

2023-09-08 09:09:21 作者:荳蔻年華

我想使用 sendto() API 通过 UDP 数据包发送视频和音频数据.我使用getsockopt()得到的发送缓冲区大小是114688,但是当数据包小于65536而不是114688时,sendto()返回-1.错误信息是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.

当我使用setsockopt()将发送缓冲区大小调整为200000时,我使用getsockopt()发现发送缓冲区大小不是200000而是262142.所以当我发送一个大小的数据包时仍然出现同样的错误大于 65536.

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.

当我使用 FFMPEG 库发送视频和音频数据包时,没有错误.所以我确信这个问题有解决方案,但我错过了一些东西.

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.

我使用的操作系统是 ubuntu 11.04,我在 ubuntu 11.10 中得到了相同的结果.

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

那是我用来创建socket并配置参数的代码:

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.
");
    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.
");
    av_free(output_buffer);
    return NULL;
}

context_data->socket = socket(AF_INET, SOCK_DGRAM, 0);
if(context_data->socket < 0) {
    printf("socket creating fail!
");
    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!
");
    return NULL;
}

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

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

即发送UDP包的代码:

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!
");
    return NULL;
}

推荐答案

您不能使用 UDP 发送大于 2^16 65536 个八位字节的消息(数据报).UDP 数据包的长度字段为 16 位.您请求的缓冲区大小与数据包的大小无关,而是操作系统总共缓冲传入和传出的八位字节数(分布在多个数据包上).但是单个数据包不能变大.

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.