Как решить: отправка UDP-пакета с помощью Sendto () получила «сообщение слишком длинное» - PullRequest
3 голосов
/ 24 марта 2012

Я хочу использовать API sendto () для отправки видео и аудио данных через пакет UDP.Размер буфера отправки, который я получил с помощью getsockopt (), равен 114688, однако sendto () вернул -1, когда пакет данных меньше 65536, а не 114688. И сообщение об ошибке слишком длинное.

Когда я использовал 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;
}

Ответы [ 3 ]

5 голосов
/ 24 марта 2012

Вы не можете отправлять сообщения (дейтаграммы) размером более 2 ^ 16 65536 октетов с UDP. Поле длины UDP-пакета составляет 16 бит. Размеры запрашиваемого вами буфера не зависят от размера пакета, а от того, сколько октетов операционная система буферизует для всех входящих и исходящих пакетов (распределенных по нескольким пакетам). Но один пакет не может быть больше.

3 голосов
/ 24 марта 2012

В ответе @ datenwolf вы просто не можете отправить более 64 КБ в одной дейтаграмме UDP, поскольку это ограничение неявно указано в двухбайтовом поле длины в протоколе.

Кроме того, на самом деле не стоит отправлять даже столько сразу. Вы должны ограничить свои пакеты MTU на пути между двумя концами (обычно в области 1500 байтов или меньше), чтобы вы не получили фрагментация на уровне IP.

Фрагментация плохая - хорошо?

1 голос
/ 24 марта 2012

Почему бы просто не вызвать 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 байта за раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...