¿Cómo cerrar con fuerza el socket UDP de Winsock?

Resuelto Alex asked hace 12 años • 3 respuestas

Necesito cerrar el socket UDP que tiene datos no enviados inmediatamente. Existe el parámetro SO_LINGER para sockets TCP pero no encontré nada para UDP. Está en Windows.

Gracias de antemano.

Actualización 0:

Doy antecedentes de esta pregunta. Tengo una aplicación: el primer hilo abre/vincula/cierra el socket, el segundo hilo le envía datagramas. En algunos casos, después de cerrar el socket (código de error = 0), la función de vinculación devuelve el código de error 10048 "Dirección ya en uso". Descubrí que después de cerrar() el puerto de ejecución todavía se usa (a través del comando netstat). ¿Quizás hago una pregunta incorrecta y el motivo de tal comportamiento es otra cosa?

Alex avatar Jul 24 '12 23:07 Alex
Aceptado

Para todos los fines de la solicitud, una vez que send()regresa, el paquete se "envía". No hay un búfer de envío como en TCP y no tienes control sobre la cola de paquetes de la NIC. Normal close()es todo lo que necesitas.

Editar 0:

@EJP, aquí tienes una cita de la UNP (Sección 2.11 "Salida UDP"):

Esta vez, mostramos el búfer de envío del socket como un cuadro discontinuo porque en realidad no existe. Un socket UDP tiene un tamaño de búfer de envío (que podemos cambiar con la SO_SNDBUFopción socket, Sección 7.5), pero esto es simplemente un límite superior en el datagrama UDP de tamaño máximo que se puede escribir en el socket. Si una aplicación escribe un datagrama mayor que el tamaño del búfer de envío del socket, EMSGSIZEse devuelve. Dado que UDP no es confiable, no necesita conservar una copia de los datos de la aplicación y no necesita un búfer de envío real. (Los datos de la aplicación normalmente se copian en un búfer del núcleo de algún tipo a medida que pasan por la pila de protocolos, pero la capa de enlace de datos descarta esta copia después de que se transmiten los datos).

Esto es lo que quise decir en mi respuesta: no tienes control sobre el búfer de envío, por lo que "para todos los fines de la aplicación" no existe.

Nikolai Fetissov avatar Jul 24 '2012 16:07 Nikolai Fetissov

También estaba teniendo este problema con un socket UDP de Windows. Después de horas de probar todo, finalmente descubrí que mi problema era que estaba llamando socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)al hilo principal para crear el socket, llamando a bind(...)y recvfrom()en un hilo de trabajo, luego, después de cerrar el hilo de trabajo, llamé closesocket(...)al hilo principal. Ninguna de las funciones devolvió un error, pero por alguna razón, al hacer esto se deja la combinación de dirección/puerto UDP en uso (por lo que una futura llamada a bind() desencadena el error 10048 WSAEADDRINUSE y netstat -abot -p UDPtambién muestra el puerto aún en uso hasta que se cierre toda la aplicación). ). La solución fue mover socket(...)y closesocket(...)llamar al hilo del trabajador.

Aparte de problemas extraños como el caso anterior, normalmente no hay forma de dejar abierto un socket de servidor UDP después de llamarlo closesocket(). Microsoft explica que no se mantiene ninguna conexión con un socket UDP y no es necesario realizar ninguna llamada shutdown()ni ninguna otra función. Por lo general, la razón por la que un socket TCP se deja abierto después de la llamada closesocket()es que no se desconectó correctamente y está esperando aproximadamente 4 minutos en estado TCP_WAIT para que entren posibles datos adicionales antes de que realmente se cierre. En el caso anterior, netstat mostró que el socket UDP nunca se cerró hasta que se cerró la aplicación, incluso si esperé más de 30 minutos.

Si está utilizando un contenedor para Winsock como el marco .NET, también leí que algunas funciones, como configurar devoluciones de llamadas asíncronas, pueden dejar un socket UDP abierto si no limpia las devoluciones de llamadas correctamente, pero yo no Creo que existen funciones de este tipo en la API win32 winsock que pueden causar esto.

Winter Dragoness avatar Sep 30 '2014 20:09 Winter Dragoness