我想使用sendto()API通过UDP数据包发送视频和音频数据。我使用getsockopt()获得的发送缓冲区大小为114688,但是,当数据包小于65536而不是114688时,sendto()返回-1。错误消息是Message太长。
当我使用setsockopt()将发送缓冲区大小调整为200000时,我使用了getsockopt()并发现发送缓冲区大小不是200000而是262142.所以当我发送一个大小的数据包时,我仍然遇到同样的错误大于65536.
我对这种情况很困惑。我想知道原因是什么以及如何解决这个问题。
当我使用FFMPEG库发送视频和音频数据包时,没有错误。所以我确信这个问题有一个解决方案,我错过了一些东西。
有没有人可以帮我解决这个问题?我真的不明白是什么原因。
我使用的操作系统是ubuntu 11.04,我在ubuntu 11.10中得到了相同的结果。
这是我用来创建套接字并配置参数的代码:
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;
}
这是发送UDP数据包的代码:
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.
这是我用来获取发送缓冲区大小的代码:
int bufsize;
int size = sizeof(bufsize);
getsockopt(context_data->socket,SOL_SOCKET, SO_SNDBUF, &bufsize, &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;
}
答案 0 :(得分:5)
使用UDP无法发送大于2 ^ 16 65536个八位字节的消息(数据报)。 UDP分组的长度字段是16位。您请求的缓冲区大小与数据包的大小无关,但操作系统总共缓冲传入和传出的八位字节数(分布在多个数据包上)。但是单个数据包不能变大。
答案 1 :(得分:3)
Per @ datenwolf的回答是,你不能在单个UDP数据报中发送超过64k的内容,因为该限制隐含在协议中的双字节长度字段中。
此外,即使发送那么多也不是一个好主意。您应该将数据包限制在两端之间的路径上的MTU(通常在1500字节或更小的范围内),这样您就不会在IP层中获得碎片。
碎片很糟糕 - 好吗?
答案 2 :(得分:1)
为什么不多次调用sendto
,在缓冲区中有一个偏移量?
int sendto_bigbuffer(int sock, const void *buffer, const size_t buflen, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
size_t sendlen = MIN(buflen, 1024);
size_t remlen = buflen;
const void *curpos = buffer;
while (remlen > 0)
{
ssize_t len = sendto(sock, curpos, sendlen, flags, dest_addr, addrlen);
if (len == -1)
return -1;
curpos += len;
remlen -= len;
sendlen = MIN(remlen, 1024);
}
return buflen;
}
像上面这样的函数会一次发送1024字节的缓冲区。