macos - sierra - puertos http alternativos
Libere el puerto UDP utilizado por el proceso inactivo en OS X (5)
Estoy en OS X 10.11.6 y trato de ejecutar un programa que normalmente escucha en el puerto UDP 8008
al inicio.
Este programa normalmente también genera un par de procesos hijos auxiliares durante su operación, pero el puerto está vinculado por el proceso padre.
Lamentablemente, al salir del programa, a veces el puerto permanece abierto, aunque el programa (padre + hijos) ya no exista.
Cuando esto sucede, si trato de ejecutar el programa nuevamente, naturalmente falla con un error EADDRINUSE
, y en estos casos, sin importar lo que intento, la única solución que encontré fue reiniciar el equipo.
Me está costando creer que no puedo liberar el puerto sin reiniciar.
Aquí hay algunos diagnósticos que ejecuté hasta ahora (ejecuté todos estos con y sin sudo
):
Encuentre el proceso usando el puerto 8008
con lsof
:
$ lsof -i -n -P | grep UDP | grep 8008
Pero sorprendentemente no devuelve ningún resultado.
Sin embargo, tuve más suerte con netstat
:
$ netstat -tulnvp udp | grep 8008
udp4 0 0 *.8008 *.* 196724 9216 47205 0
Entonces, el puerto está realmente atado, y el culpable es pid 47205
, sin embargo:
$ ps aux | grep 47205
No devuelve nada Lo mismo para los PID 47206
y 47207
(sin duda los PID asignados a los niños). También probé otras variaciones del grep
(nombre del programa, ruta, etc.).
También busqué cualquier proceso que informe 47205
como su padre:
$ ps -axo pid,ppid,command | grep 47205
Entonces los procesos de los niños también están claramente muertos.
Al no poder kill
nada, intenté lanzar SIGHUP con la esperanza de que pudiera eliminar cualquier proceso hijo zombie:
$ sudo kill HUP 1
$ sudo kill -s HUP 1
Pero, por desgracia, netstat
todavía muestra el límite del puerto.
Por último, traté de reiniciar la interfaz de loopback:
$ sudo ifconfig lo down
$ sudo ifconfig lo up
Pero de nuevo, sin ningún efecto.
He esperado varias horas desde la última vez que se ejecutó el programa, así que estoy bastante seguro de que ya habría pasado el tiempo de espera, pero el puerto no será liberado.
¿Alguna idea sobre cómo forzar la liberación del puerto sin un reinicio?
Editar:
- El programa en cuestión es Patchwork envuelto en electrones.
- Esta pregunta proviene de este problema de Github .
- Aunque encontrar una solución / corrección de errores que evite que el problema ocurra en primer lugar sería ideal, también estoy interesado en formas de cerrar manualmente ese puerto desde la terminal
De hecho, es posible cerrar el puerto manualmente sin reiniciar la máquina. En varios sabores de Linux esto generalmente se hace con w / GDB emitiendo syscalls enmascarados como un proceso (por ejemplo, close(fd)
syscall en el descriptor de archivo sockets).
El proceso para eso:
- Abra un puerto UDP:
netcat -u 127.0.0.1 33333
. - Compruebe el puerto UDP:
netstat -npu (u for UDP)
, que le proporcionará el PID que ocupa ese puerto. - Ejecute:
lsof -np $pid
para que ese PID obtenga el descriptor de archivo para el socket. - Luego ejecute GDB para ese PID:
sudo gdb -p 73599
- Cuando dentro de GDB ejecuta
call close(file_descriptor)
Ejemplo:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
netcat 73599 ubunt cwd DIR 259,2 4096 13895497 /home/ubunt/Downloads
netcat 73599 ubunt rtd DIR 259,2 4096 2 /
netcat 73599 ubunt txt REG 259,2 31248 28835938 /bin/nc.openbsd
netcat 73599 ubunt mem REG 259,2 47600 23990813 /lib/x86_64-linux-gnu/libnss_files-2.23.so
netcat 73599 ubunt mem REG 259,2 1868984 23990714 /lib/x86_64-linux-gnu/libc-2.23.so
netcat 73599 ubunt mem REG 259,2 101200 23990866 /lib/x86_64-linux-gnu/libresolv-2.23.so
netcat 73599 ubunt mem REG 259,2 81040 23990710 /lib/x86_64-linux-gnu/libbsd.so.0.8.2
netcat 73599 ubunt mem REG 259,2 162632 23990686 /lib/x86_64-linux-gnu/ld-2.23.so
netcat 73599 ubunt 0u CHR 136,19 0t0 22 /dev/pts/19
netcat 73599 ubunt 1u CHR 136,19 0t0 22 /dev/pts/19
netcat 73599 ubunt 2u CHR 136,19 0t0 22 /dev/pts/19
netcat 73599 ubunt 3u IPv4 22142418 0t0 UDP 127.0.0.1:45255->127.0.0.1:33333
Entonces GDB:
$sudo gdb -p 73599
...
(gdb) call close(3u)
$1 = 0
Verás que el puerto ya no está allí:
ubunt@ubunt-MS-7A94:~$ lsof -np 73599
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
netcat 73599 ubunt cwd DIR 259,2 4096 13895497 /home/ubunt/Downloads
netcat 73599 ubunt rtd DIR 259,2 4096 2 /
netcat 73599 ubunt txt REG 259,2 31248 28835938 /bin/nc.openbsd
netcat 73599 ubunt mem REG 259,2 47600 23990813 /lib/x86_64-linux-gnu/libnss_files-2.23.so
netcat 73599 ubunt mem REG 259,2 1868984 23990714 /lib/x86_64-linux-gnu/libc-2.23.so
netcat 73599 ubunt mem REG 259,2 101200 23990866 /lib/x86_64-linux-gnu/libresolv-2.23.so
netcat 73599 ubunt mem REG 259,2 81040 23990710 /lib/x86_64-linux-gnu/libbsd.so.0.8.2
netcat 73599 ubunt mem REG 259,2 162632 23990686 /lib/x86_64-linux-gnu/ld-2.23.so
netcat 73599 ubunt 0u CHR 136,19 0t0 22 /dev/pts/19
netcat 73599 ubunt 1u CHR 136,19 0t0 22 /dev/pts/19
netcat 73599 ubunt 2u CHR 136,19 0t0 22 /dev/pts/19
GDB está disponible para MacOS, por lo que también debería funcionar para su caso.
El sistema puede mantener el socket abierto hasta que el proceso de E / S esté en progreso. Incluso cuando el proceso murió pero no cerró explícitamente el socket. Si su zócalo no se cerró en horas, probablemente le falte algo. Intente utilizar la investigación de kernel de bajo nivel en lugar de utilidades de nivel superior como netstat o lsof.
Renuncia
No soy experto en OS X, y la mayoría de los comandos para Linux. Todavía lo dejo allí si alguien más tiene el mismo problema.
1. Trate de ver si el zócalo sigue vivo (opcional)
Puedo sugerir que revise la comunicación de socket.
tcpdump -A -s0 port 8080 and tcpdump -A -s0 -ilo port 8080
Si ve datos transferidos a través de un socket, puede estar seguro de que el proceso está activo. O puede ser uno de sus hijos. Más tarde puedes atrapar el pid con strace
2. Verifica el proceso y su estado
Linux tiene maravillosos procfs . Puedes obtener tantas cosas desde allí. Y seguro de que puedes ver todos los descriptores de archivos abiertos
ls -al /proc/47205/fd
Si ve la salida y / proc / 47205 existe el pid no liberado, sin embargo, ps aparece. Verá todos los archivos abiertos y su fds. Parece
133 -> socket: [32242509]
Donde 133 es un número fd
Lamentablemente, OS X no tiene el sistema de archivos / proc. El comando alternativo que encontré.
procexp 47205 fds
Pero no estoy seguro de que funcione al 100%.
3. Cerrar el descriptor de archivo (socket) en otro proceso
En linux hay un buen comando
fuser -k -n udp 8080
Esto cerrará explícitamente todos los procesos que bloquean el puerto. Parece que OS X también puede tener fusor
Otra forma real de hackers es conectarse para procesar con gdb y ejecutar comandos dentro del proceso, porque los números de los descriptores de archivos son válidos solo en el entorno del proceso, exactamente como @Mindaugas Bernatavičius escribió:
gdb -p 47205
>call shutdown([fd_number],2)
>call close([fd_number])
Hay una tercera forma , cuando sea posible, puede reiniciar toda la red. Nota Plese, abajo y arriba solo la interfaz loopback no es suficiente. En la ejecución de Linux
systemctl restart network
4. Qué hacer para evitar que el socket se atasque en el sistema
Siempre debe asegurarse de que el calcetín esté cerrado antes de que salga su programa. He visto muchos problemas con nodejs que los sockets permanecen abiertos. Llamar a Socket.destroy () resolverá el problema
Puede poner su código de socket aquí, antes de salir de la aplicación:
app.on (''close'', función (código) {
// El usuario cerró la aplicación. Mata el proceso de host.
process.exit ();
});
En su código, después de crear el socket, pero antes de la llamada de bind
, invoque lo siguiente:
int val = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
Luego llama bind
. Lo anterior permitirá que el enlace de socket tenga éxito incluso si el puerto está en uso.
Dos procesos, que intentan una recvfrom
en el mismo puerto, darán como resultado uno de los procesos que reciben el paquete, pero no el otro. Y no es determinista cuál será. Así que asegúrese de no tener realmente dos procesos ejecutándose legítimamente y compartiendo el puerto.
Su pregunta es similar a:
- release-renew-ip-address-via-terminal-in-os-x
- Cómo restablecer la pila de red
- Restablecer TCP / IP es OSX
Como dijiste:
Por último, traté de reiniciar la interfaz de loopback:
$ sudo ifconfig lo down
$ sudo ifconfig lo up
¿Intentó retener todas las interfaces de red disponibles (lan o wlan) y no solo el loopback?
En lugar de ifconfig
también puede utilizar la utilidad de comando nativa de MacOS (desde here ) para apagar y luego encender el dispositivo (adapte en0
al your device name
):
networksetup -setairportpower en0 off
networksetup -setairportpower en0 on
También puede intentar liberar y renovar DHCP con:
sudo dhclient -v -r
Saludos
una pregunta relacionada: mac cambió el Comportamiento de SO_REUSEADDR y SO_REUSEPORT:
Comportamiento de SO_REUSEADDR y SO_REUSEPORT cambiado?
y soy el mantenedor de iptux [1], si uso SO_REUSEPORT, el programa puede comenzar, pero no puedo recibir msg desde este puerto, todo el mensaje va al puerto no cerrado como un agujero negro.