socket programming programing program how geeksforgeeks cpp c linux sockets

programming - sockets cpp



Error: La dirección ya está en uso mientras se vincula el socket con la dirección pero el número de puerto se muestra gratis con `netstat` (8)

Como ya se dijo, su socket probablemente ingrese en el estado TIME_WAIT . Este problema está bien descrito por Thomas A. Fine here .

Para resumir, el proceso de cierre de socket sigue el siguiente diagrama:

here

Thomas dice:

Mirando el diagrama de arriba, está claro que TIME_WAIT puede evitarse si el extremo remoto inicia el cierre. Por lo tanto, el servidor puede evitar problemas al permitir que el cliente cierre primero. El protocolo de la aplicación debe estar diseñado para que el cliente sepa cuándo cerrar. El servidor puede cerrarse de forma segura en respuesta a un EOF del cliente, sin embargo, también deberá establecer un tiempo de espera cuando se espera un EOF en caso de que el cliente haya abandonado la red de forma descortés. En muchos casos, simplemente esperar unos segundos antes de que el servidor se cierre será suficiente.

El uso de SO_REUSEADDR se sugiere comúnmente en Internet, pero Thomas agrega:

Curiosamente, el uso de SO_REUSEADDR puede llevar a errores más difíciles de "dirección ya en uso". SO_REUSADDR permite utilizar un puerto que está bloqueado en TIME_WAIT , pero todavía no puede usar ese puerto para establecer una conexión con el último lugar al que se conectó. ¿Qué? Supongamos que escojo el puerto local 1010 y me conecto al puerto 300 de foobar.com y luego me cierro localmente, dejando ese puerto en TIME_WAIT . Puedo reutilizar el puerto local 1010 de inmediato para conectarme a cualquier lugar, excepto al puerto 300 de foobar.com .

Traté de enlazar mi socket (socket del servidor) en el puerto número 8000 . Funcionó e hizo el trabajo por mí. Al final del código también cierro el socket. El siguiente instante corro mi código nuevamente y me muestra que la dirección ya está en uso. He impreso el significado de los valores de error strerror(errno); para ver si mi código funciona correctamente en cada punto. Para verificar si el puerto es libre lo comprobé usando netstat pero muestra que el número de puerto 8000 es gratis. Me ha sucedido muchas veces. Cada vez que espero unos segundos más y luego vuelve a funcionar. Estoy usando el lenguaje c Entonces, ¿cuál es la razón de este comportamiento por mi sistema operativo?

Después de algunos segundos más, ejecuto el código y luego funciona.

anirudh@anirudh-Aspire-5920:~/Desktop/testing$ sudo ./a.out Socket Creation: Success File open: Success Socket Bind: Address already in use Socket Listen: Address already in use ^C anirudh@anirudh-Aspire-5920:~/Desktop/testing$ sudo netstat -lntp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1348/lighttpd tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 984/sshd tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 1131/cupsd tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 1211/mysqld tcp6 0 0 :::22 :::* LISTEN 984/sshd tcp6 0 0 ::1:631 :::* LISTEN 1131/cupsd anirudh@anirudh-Aspire-5920:~/Desktop/testing$ sudo ./a.out Socket Creation: Success File open: Success Socket Bind: Address already in use Socket Listen: Address already in use ^C anirudh@anirudh-Aspire-5920:~/Desktop/testing$


Incluso la respuesta de icfantv a esta pregunta ya es perfecta, todavía tengo más hallazgos en mi prueba.

Como un socket de servidor en estado de escucha, si solo está en estado de escucha, e incluso acepta solicitudes y obtención de datos del lado del cliente, pero sin ninguna acción de envío de datos. Todavía podemos reiniciar el servidor de una vez después de que se detenga. Pero si ocurre alguna acción de envío de datos en el lado del servidor para el cliente, el mismo reinicio del servicio (mismo puerto) tendrá este error: (Dirección ya en uso).

Creo que esto es causado por los principios de diseño de TCP / IP. Cuando el servidor envía los datos al cliente, debe garantizar el éxito del envío de los datos. Para ello, el sistema operativo (Linux) necesita supervisar la conexión incluso si la aplicación del servidor cerró este socket. Pero todavía creo que el diseñador de socket kernel podría mejorar este problema.


Me he encontrado con el mismo problema también. Es porque está cerrando su conexión al zócalo, pero no al zócalo en sí. El socket puede ingresar al estado TIME_WAIT (para garantizar que todos los datos se hayan transmitido, TCP garantiza la entrega si es posible) y demorar hasta 4 minutos para su lanzamiento .

o, para una explicación REALMENTE detallada / técnica, verifique este enlace

Puede ser molesto, pero no hay forma de evitarlo y no es un error.


Para AF_UNIX puede usar desvincular llamada (ruta); después de cerrar () socket en la aplicación "servidor"


Pruebe netstat de la siguiente manera: netstat -ntp , sin el -l . Mostrará la conexión tcp en el estado TIME_WAIT .


Sé que ha pasado un tiempo desde que se hizo la pregunta, pero pude encontrar una solución:

int sockfd; int option = 1; sockfd = socket(AF_INET, SOCK_STREAM, 0); setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));

Esto establece el socket capaz de ser reutilizado de inmediato.

Me disculpo si esto es "incorrecto". No tengo mucha experiencia con enchufes


Sólo tipo

unlink [SOCKET NAME]

en la terminal, entonces el error ya no debería existir.


el error que recibí fue:

cockpit.socket: Failed to listen on sockets: Address already in use

la solución que descubrí es:

  1. Tuve que deshabilitar selinux
  2. en el servicio / usr / lib / systemd / system / cockpit cambié la línea:

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws --selinux-type=etc_t

    a:

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws

para que pueda ver, saqué la discusión sobre Selinux y luego ejecuté:

systemctl daemon-reload systemctl start cockpit.service

luego busqué:

Acepté el certificado autofirmado y pude iniciar sesión con éxito en el puesto de pilotaje y usarlo normalmente.

esto es todo en una máquina fedora25. el puerto 9090 ya se había agregado usando firewall-cmd