La API de socket es el estándar de facto para las comunicaciones TCP / IP y UDP / IP (es decir, el código de red tal como lo conocemos). Sin embargo, una de sus funciones principales accept()
es un poco mágica.
Para tomar prestada una definición semiformal:
accept () se usa en el lado del servidor. Acepta un intento entrante recibido de crear una nueva conexión TCP desde el cliente remoto y crea un nuevo socket asociado con el par de direcciones de socket de esta conexión.
En otras palabras, accept
devuelve un nuevo socket a través del cual el servidor puede comunicarse con el cliente recién conectado. El socket antiguo (en el que accept
se llamó) permanece abierto, en el mismo puerto, escuchando nuevas conexiones.
Como accept
funciona ¿Cómo se implementa? Hay mucha confusión sobre este tema. Muchas personas afirman que aceptar abre un nuevo puerto y usted se comunica con el cliente a través de él. Pero esto obviamente no es cierto, ya que no se abre un nuevo puerto. En realidad, puede comunicarse a través del mismo puerto con diferentes clientes, pero ¿cómo? Cuando varios hilos llaman recv
al mismo puerto, ¿cómo saben los datos a dónde ir?
Supongo que es algo similar a la dirección del cliente asociada con un descriptor de socket, y cada vez que los datos pasan recv
se enruta al socket correcto, pero no estoy seguro.
Sería genial obtener una explicación exhaustiva del funcionamiento interno de este mecanismo.
fuente
Respuestas:
Su confusión radica en pensar que el servidor identifica un socket: Puerto del servidor. Cuando en realidad, los enchufes se identifican de manera única por un cuarteto de información:
Client IP : Client Port
yServer IP : Server Port
Entonces, si bien la IP del servidor y el puerto del servidor son constantes en todas las conexiones aceptadas, la información del lado del cliente es lo que le permite realizar un seguimiento de dónde va todo.
Ejemplo para aclarar cosas:
Digamos que tenemos un servidor en
192.168.1.1:80
y dos clientes,10.0.0.1
y10.0.0.2
.10.0.0.1
abre una conexión en el puerto local1234
y se conecta al servidor. Ahora el servidor tiene un socket identificado de la siguiente manera:Ahora
10.0.0.2
abre una conexión en el puerto local5678
y se conecta al servidor. Ahora el servidor tiene dos sockets identificados de la siguiente manera:fuente
Solo para agregar a la respuesta dada por el usuario "17 de 26"
El zócalo en realidad consiste en 5 tuplas - (ip de origen, puerto de origen, ip de destino, puerto de destino, protocolo). Aquí el protocolo podría ser TCP o UDP o cualquier protocolo de capa de transporte. Este protocolo se identifica en el paquete desde el campo 'protocolo' en el datagrama IP.
Por lo tanto, es posible tener diferentes aplicaciones en el servidor que se comunican con el mismo cliente en exactamente las mismas 4 tuplas pero diferentes en el campo del protocolo. Por ejemplo
Apache en el lado del servidor hablando en (server1.com:880-client1:1234 en TCP) y World of Warcraft hablando en (server1.com:880-client1:1234 en UDP)
Tanto el cliente como el servidor manejarán esto como campo de protocolo en el paquete IP en ambos casos es diferente incluso si los otros 4 campos son iguales.
fuente
Lo que me confunde cuando estaba aprendiendo esto, fue que los términos
socket
yport
sugieren que son algo físico, cuando en realidad sólo están las estructuras de datos del kernel usos para abstraer los detalles de la creación de redes.Como tal, las estructuras de datos se implementan para poder mantener separadas las conexiones de diferentes clientes. En cuanto a cómo se implementan, la respuesta es a.) No importa, el propósito de la API de sockets es precisamente que la implementación no debería importar ob.) Solo eche un vistazo. Además de los libros altamente recomendados de Stevens que proporcionan una descripción detallada de una implementación, consulte la fuente en Linux o Solaris o uno de los BSD.
fuente
Como dijo el otro tipo, un socket se identifica de manera única por una tupla de 4 (IP del cliente, puerto del cliente, IP del servidor, puerto del servidor).
El proceso del servidor que se ejecuta en la IP del servidor mantiene una base de datos (lo que significa que no me importa qué tipo de tabla / lista / árbol / matriz / estructura de datos mágicos usa) de sockets activos y escucha en el puerto del servidor. Cuando recibe un mensaje (a través de la pila TCP / IP del servidor), comprueba la IP y el puerto del cliente en la base de datos. Si la IP del cliente y el puerto del cliente se encuentran en una entrada de la base de datos, el mensaje se transfiere a un controlador existente, de lo contrario, se crea una nueva entrada en la base de datos y se genera un nuevo controlador para manejar ese socket.
En los primeros días de ARPAnet, ciertos protocolos (FTP para uno) escucharían un puerto específico para solicitudes de conexión y responderían con un puerto de transferencia. Las comunicaciones adicionales para esa conexión irían por el puerto de transferencia. Esto se hizo para mejorar el rendimiento por paquete: las computadoras eran varios órdenes de magnitud más lentas en esos días.
fuente