13 votos

Compartir el puerto de origen TCP

Mi entendimiento de la conexión TCP es que un PUERTO fuente permanece exclusivo para una conexión, sin importar cuál sea el destino, por lo que el número de conexiones desde el puerto local 12345, por ejemplo, nunca puede exceder 1.

Recientemente leí que una conexión TCP se identifica por

TCP permite el uso compartido de puertos fuente entre múltiples procesos, pero cada proceso requiere un puerto libre al que enlazarse para su conexión

así que fui a validar ese "uso compartido de puertos entre procesos": esto debe significar que el mismo puerto fuente se puede usar para conectarse a destinos diferentes.

Sin embargo, al experimentar esto, probé estos dos comandos:

nc -v -p 12345 google.com 80

lo cual funciona bien (-v para verboso, y -p para especificar el puerto fuente como 12345, para mi propósito de aprendizaje)

Ahora, al ejecutar simultáneamente este comando en otra terminal

nc -v -p 12345 github.com 80

falla con este mensaje de error:

nc: connectx to github.com port 80 (tcp) failed: Address already in use

la razón por la que especifiqué el mismo puerto fuente con -p es para validar que un puerto fuente se puede compartir. No hay necesidad práctica para esto, en un escenario del mundo real ni siquiera me preocuparía por el puerto fuente. De acuerdo con esto, ¿es verdad que un puerto fuente se usará sólo una vez?

15voto

nneonneo Puntos 278

No hay razón por la cual dos procesos no puedan usar el mismo puerto de origen, siempre y cuando no se conecten ambos al mismo destino (anfitrión, puerto). En muchos sistemas UNIX, se establece la opción SO_REUSEPORT para permitir a los procesos compartir un número de puerto; en Windows, se establece SO_REUSEADDR. Por ejemplo, con socat:

  • proceso 1: socat stdio tcp:google.com:80,bind=:12345,reuseport
  • proceso 2: socat stdio tcp:bing.com:80,bind=:12345,reuseport

Estos dos procesos pueden ejecutarse simultáneamente y ambos tendrán el puerto de origen 12345 (como puedes confirmar con netstat).

Nota, sin embargo, que casi con toda seguridad tendrás problemas si los sockets no se cierran de manera limpia en ambos extremos, ya que los sockets TCP no cerrados entrarán en un estado de TIME_WAIT que causará que el cuádruple (srcaddr, srcport, dstaddr, dstport) se mantenga ocupado hasta que expire el período de espera. Por lo tanto, al usar un solo puerto de origen para múltiples conexiones, no podrás reconectarte al mismo servidor y puerto a menos que la conexión previa se haya cerrado completamente o el período de TIME_WAIT haya expirado.

8voto

Zac67 Puntos 181

Cualquier puerto solo se asigna a un único proceso en cualquier momento. Ese proceso puede crear cualquier cantidad de conexiones con él, con la restricción de que la dirección IP de destino o el número de puerto deben variar entre las conexiones.

Como ejemplo, TCP 10.0.0.10:49152 solo puede conectar una vez a TCP 10.0.0.2:80 pero al mismo tiempo puede conectarse a TCP 10.0.0.3:80 o TCP 10.0.0.2:8080.

2voto

Barmar Puntos 195

Mientras que el protocolo TCP en sí permite combinaciones arbitrarias de puertos y direcciones locales y remotos, la mayoría de las implementaciones de Unix simplifican la gestión de puertos. La razón es que el proceso de configuración de sockets se divide en pasos separados.

  • Primero se establece el puerto local con bind(). Este paso es necesario al crear un socket TCP de escucha (debes especificar en qué puerto está escuchando), es opcional antes de realizar una conexión saliente con connect() (se asignará un puerto local arbitrario). Como aún no conocemos la dirección o puerto remoto, no es posible determinar si esto es totalmente único. Simplemente verifica si el puerto solicitado está disponible. Si el socket tiene la opción SO_REUSEADDR activada, ignora sockets conectados al comprobar si la dirección local está en uso, pero aún así fallará si hay un socket de escucha en ese puerto.

  • Luego, para una conexión saliente, llamas a connect(), especificando la dirección remota. Solo puedes llamar a connect() una vez en un socket, y debido a que verificamos el puerto local durante bind(), esto nunca producirá una dirección/puerto local/remoto duplicado.

  • Para una conexión entrante, llamas a accept() en el socket de escucha. Nuevamente, porque verificamos que el puerto local del socket de escucha está libre cuando lo bindeamos, nunca puede haber una combinación duplicada.

Retrasar las comprobaciones de puertos hasta que tengamos la información remota complicaría el manejo de errores. El diseño actual simplemente verifica la duplicación en un solo lugar: bind().

1voto

rahmanisback Puntos 616

Después de algunas investigaciones, descubrí que compartir el puerto de origen solo está permitido para múltiples conexiones salientes del mismo proceso. El sistema operativo necesita saber a qué proceso dirigir el flujo de conexión.

Seleccionaré esta respuesta en dos días según la política del sitio.

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X