socket programming program how geeksforgeeks c sockets ubuntu udp

programming - Cómo resolver: el envío de paquetes UDP con Sendto() tiene "mensaje demasiado largo"



socket tcp udp c++ (3)

¿Por qué no simplemente llamar a sendto varias veces, con una compensación en el búfer?

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; }

Algo así como la función anterior enviará el búfer 1024 bytes a la vez.

Quiero usar la API sendto () para enviar datos de video y audio a través de paquetes UDP. El tamaño del búfer de envío que obtuve usando getsockopt () es 114688, sin embargo, sendto () devolvió -1 cuando el paquete de datos es menos de 65536 que 114688. Y el mensaje de error es Mensaje demasiado largo.

Cuando usé setsockopt () para ajustar el tamaño del búfer de envío como 200000, utilicé getsockopt () y encontré que el tamaño del búfer de envío no era 200000 sino 262142. Así que recibí el mismo error cuando envié paquetes de datos con un tamaño superior a 65536 .

Estoy confundido acerca de esta situación. Quiero saber cuál es el motivo y cómo resolver este problema.

Cuando utilicé la biblioteca FFMPEG para enviar el paquete de video y audio, no hay ningún error. Así que estoy seguro de que hay una solución para este problema y me perdí algo.

¿Hay alguien que pueda ayudarme con este problema? Realmente no puedo entender cuál es la razón.

El SO que utilicé es ubuntu 11.04, obtuve los mismos resultados en ubuntu 11.10.

Ese es el código que utilicé para crear el socket y configurar el parámetro:

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; }

Ese es el código para enviar paquetes 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.

Ese es el código que utilicé para obtener el tamaño del buffer de envío:

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

Ese es el código que utilicé para configurar el tamaño del buffer de envío:

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; }


No puede enviar mensajes (datagramas) mayores a 2 ^ 16 65536 octetos con UDP. El campo de longitud de un paquete UDP es de 16 bits. Los tamaños de búfer que está solicitando no son del tamaño de un paquete, pero cuántos octetos el SO almacena en búfer entrantes y salientes en total (repartidos en varios paquetes). Pero un solo paquete no puede agrandarse.


Por la respuesta de Per @ datenwolf, simplemente no puede enviar más de 64k en un solo datagrama UDP, ya que ese límite está implícito en el campo de dos bytes de longitud en el protocolo.

Además, en realidad no es una buena idea enviar tanto de una vez. Debe limitar sus paquetes a la MTU en la ruta entre los dos extremos (generalmente en la región de 1500 bytes o menos) para que no se fragmente en la capa IP.

La fragmentación es mala, ¿de acuerdo?