2011-02-24 29 views
38

Intenté vincular mi socket (servidor) al número de puerto 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 comprobar si el puerto es libre, lo comprobé usando netstat pero muestra que el número de puerto 8000 es gratuito. 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?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`

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

[email protected]:~/Desktop/testing$ sudo ./a.out 
Socket Creation: Success 
File open: Success 
Socket Bind: Address already in use 
Socket Listen: Address already in use 
^C 
[email protected]:~/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  
[email protected]:~/Desktop/testing$ sudo ./a.out 
Socket Creation: Success 
File open: Success 
Socket Bind: Address already in use 
Socket Listen: Address already in use 
^C 
[email protected]:~/Desktop/testing$ 

Respuesta

44

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) and take up to 4 minutes to release.

o, para una explicación detallada REALMENTE/técnica, check this link

puede ser molesto para estar seguro, pero no hay manera real a su alrededor y que no es un error.

+0

gracias por la respuesta con enlaces para satisfacer mi consulta. – Durin

+9

existe una posible solución en la página que vinculó. Puede usar la opción SO_REUSEADDR para el socket. vea setsockopt aquí: http://linux.die.net/man/3/setsockopt – Vereb

+1

"no hay manera de evitarlo y no es un error", le gustó: P –

16

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

+3

Mejor aún, use 'ss -npt'. – user611775

5

simplemente escriba

unlink [SOCKET NAME] 

en el terminal, a continuación, ya no debe existir el error.

1

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 sigo creyendo que el diseñador de socket kernel podría mejorar este problema.

14

Sé que ha sido un tiempo desde que se hizo la pregunta, pero yo era capaz de 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)); 

este conjunto el zócalo apto para ser reutilizado inmediatamente.

Pido disculpas si esto es "incorrecto".No estoy muy experimentado con tomas

+0

Me gusta cómo se pone 'incorrecto' entre comillas, lo que implica que cualquiera que no esté de acuerdo con usted está equivocado. – byxor

+6

las comillas eran más bien un tipo de cosas "si funciona no está mal". Me doy cuenta de que probablemente no sea la forma preferida y si alguien conoce la forma "correcta" que me gustaría escuchar. – Supamee

0

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 desactivar SELinux
  2. en/usr/lib/systemd/system/cockpit service 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 
    

así como se puede ver que nos llevó a cabo la discusión sobre selinux Entonces me encontré:

systemctl daemon-reload 
systemctl start cockpit.service 

continuación, he echado un vistazo a:

I aceptó el certificado autofirmado y fue capaz de iniciar sesión exitosamente en el puesto de pilotaje y usarlo normalmente.

todo esto en una máquina fedora25. el puerto 9090 ya había sido añadido usando firewall-cmd

2

Como ya se dijo, el zócalo probablemente entrar en TIME_WAIT estado. Este problema está bien descrito en Thomas A. Finehere.

Para resumen, toma de cierre diagrama de proceso de la carta a continuación:

Socket closing process

Thomas dice:

Looking at the diagram above, it is clear that TIME_WAIT can be avoided if the remote end initiates the closure. So the server can avoid problems by letting the client close first. The application protocol must be designed so that the client knows when to close. The server can safely close in response to an EOF from the client, however it will also need to set a timeout when it is expecting an EOF in case the client has left the network ungracefully. In many cases simply waiting a few seconds before the server closes will be adequate.

Usando SO_REUSEADDR que comúnmente se sugiere en Internet, pero Thomas complemento:

Oddly, using SO_REUSEADDR can actually lead to more difficult "address already in use" errors. SO_REUSADDR permits you to use a port that is stuck in TIME_WAIT , but you still can not use that port to establish a connection to the last place it connected to. What? Suppose I pick local port 1010, and connect to foobar.com port 300, and then close locally, leaving that port in TIME_WAIT . I can reuse local port 1010 right away to connect to anywhere except for foobar.com port 300.

0

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

Cuestiones relacionadas