Esta puede ser una pregunta muy básica pero me confunde.
¿Pueden dos enchufes conectados diferentes compartir un puerto? Estoy escribiendo un servidor de aplicaciones que debería poder manejar más de 100k conexiones simultáneas, y sabemos que la cantidad de puertos disponibles en un sistema es de alrededor de 60k (16 bits). Un socket conectado se asigna a un puerto nuevo (dedicado), por lo que significa que el número de conexiones simultáneas está limitado por el número de puertos, a menos que varios sockets puedan compartir el mismo puerto. Entonces la pregunta.
¡Gracias por la ayuda por adelantado!
Escucha TCP / HTTP en puertos: ¿cómo pueden muchos usuarios compartir el mismo puerto?
Entonces, ¿qué sucede cuando un servidor escucha las conexiones entrantes en un puerto TCP? Por ejemplo, supongamos que tiene un servidor web en el puerto 80. Supongamos que su computadora tiene la dirección IP pública 24.14.181.229 y la persona que intenta conectarse con usted tiene la dirección IP 10.1.2.3. Esta persona puede conectarse con usted abriendo un socket TCP al 24.14.181.229:80. Suficientemente simple.
De manera intuitiva (y errónea), la mayoría de la gente asume que se parece a esto:
Esto es intuitivo, porque desde el punto de vista del cliente, tiene una dirección IP y se conecta a un servidor en IP: PORT. Dado que el cliente se conecta al puerto 80, ¿su puerto también debe ser 80? Esto es algo sensato de pensar, pero en realidad no es lo que sucede. Si eso fuera correcto, solo podríamos atender a un usuario por dirección IP extranjera. Una vez que una computadora remota se conecta, entonces él toma la conexión del puerto 80 al puerto 80, y nadie más podría conectarse.
Hay que entender tres cosas:
1.) En un servidor, un proceso está escuchando en un puerto. Una vez que obtiene una conexión, la pasa a otro hilo. La comunicación nunca acapara el puerto de escucha.
2.) Las conexiones son identificadas de forma única por el sistema operativo mediante las siguientes 5 tuplas: (IP local, puerto local, IP remota, puerto remoto, protocolo). Si algún elemento de la tupla es diferente, entonces esta es una conexión completamente independiente.
3.) Cuando un cliente se conecta a un servidor, elige un puerto de origen de orden superior aleatorio y no utilizado . De esta manera, un solo cliente puede tener hasta ~ 64k conexiones al servidor para el mismo puerto de destino.
Entonces, esto es realmente lo que se crea cuando un cliente se conecta a un servidor:
Observando lo que realmente sucede
Primero, usemos netstat para ver qué está sucediendo en esta computadora. Usaremos el puerto 500 en lugar del 80 (porque un montón de cosas están sucediendo en el puerto 80 ya que es un puerto común, pero funcionalmente no hace ninguna diferencia).
Como se esperaba, la salida está en blanco. Ahora comencemos un servidor web:
Ahora, aquí está el resultado de ejecutar netstat nuevamente:
Así que ahora hay un proceso que está escuchando activamente (Estado: LISTEN) en el puerto 500. La dirección local es 0.0.0.0, que es un código para "escuchar todas las direcciones IP". Un error fácil de cometer es escuchar solo en el puerto 127.0.0.1, que solo aceptará conexiones desde la computadora actual. Entonces, esto no es una conexión, esto solo significa que un proceso solicitó bind () al puerto IP, y ese proceso es responsable de manejar todas las conexiones a ese puerto. Esto sugiere la limitación de que solo puede haber un proceso por computadora escuchando en un puerto (hay formas de evitar eso usando multiplexación, pero este es un tema mucho más complicado). Si un servidor web está escuchando en el puerto 80, no puede compartir ese puerto con otros servidores web.
Así que ahora, conectemos a un usuario a nuestra máquina:
Este es un script simple ( https://github.com/grokit/quickweb ) que abre un socket TCP, envía el payload ("Test payload." En este caso), espera unos segundos y se desconecta. Si vuelve a hacer netstat mientras esto sucede, se muestra lo siguiente:
Si se conecta con otro cliente y vuelve a hacer netstat, verá lo siguiente:
... es decir, el cliente usó otro puerto aleatorio para la conexión. Así que nunca hay confusión entre las direcciones IP.
fuente
Esa es una intuición común, pero incorrecta. Un enchufe conectado no está asignado a un puerto nuevo / dedicado. La única restricción real que debe satisfacer la pila TCP es que la tupla de (dirección_local, puerto_local, dirección_remota, puerto_remoto) debe ser única para cada conexión de socket. Por lo tanto, el servidor puede tener muchos sockets TCP usando el mismo puerto local, siempre que cada uno de los sockets del puerto esté conectado a una ubicación remota diferente.
Consulte el párrafo "Par de sockets" en: http://books.google.com/books?id=ptSC4LpwGA0C&lpg=PA52&dq=socket%20pair%20tuple&pg=PA52#v=onepage&q=socket%20pair%20tuple&f=false
fuente
bind()
operación precede a laconnect()
operación, incluso implícitamente.bind()
que solo se usaba en el lado del servidor antes.accept()?
¿El lado del cliente también vinculará el puerto en particular?bind()
se puede usar en el lado del cliente antesconnect()
.Teóricamente, sí. Practica, no. La mayoría de los núcleos (incluido Linux) no le permiten un segundo
bind()
a un puerto ya asignado. No fue un gran parche permitir esto.Conceptualmente, deberíamos diferenciar entre socket y puerto . Los sockets son puntos finales de comunicación bidireccional, es decir, "cosas" donde podemos enviar y recibir bytes. Es algo conceptual, no existe tal campo en un encabezado de paquete llamado "socket".
El puerto es un identificador que puede identificar un enchufe. En el caso del TCP, un puerto es un entero de 16 bits, pero también hay otros protocolos (por ejemplo, en sockets Unix, un "puerto" es esencialmente una cadena).
El principal problema es el siguiente: si llega un paquete entrante, el kernel puede identificar su socket por su número de puerto de destino. Es la forma más común, pero no es la única posibilidad:
Como está trabajando en un servidor de aplicaciones, podrá hacerlo.
fuente
bind()
.bind()
? Me lo puedo imaginar, sí es bastante posible, pero el hecho es que tanto WinSock como la API Posix usan labind()
llamada para eso, incluso su parametrización es prácticamente la misma. Incluso si una API no tiene esta llamada, de alguna manera debe decirlo, desde dónde desea leer los bytes entrantes .listen()
/accept()
API pueden crear los sockets de manera que el kernel los diferencie por sus puertos entrantes. La cuestión del OP se puede interpretar de la forma en que él la pide esencialmente. Creo que es bastante realista, pero no es esto lo que significa literalmente su pregunta.No. No es posible compartir el mismo puerto en un instante en particular. Pero puede hacer su aplicación de tal manera que haga que el puerto acceda en un instante diferente.
fuente