¿Cómo funciona el socket API accept () funciona?

126

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, acceptdevuelve un nuevo socket a través del cual el servidor puede comunicarse con el cliente recién conectado. El socket antiguo (en el que acceptse llamó) permanece abierto, en el mismo puerto, escuchando nuevas conexiones.

Como acceptfunciona ¿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 recval 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 recvse enruta al socket correcto, pero no estoy seguro.

Sería genial obtener una explicación exhaustiva del funcionamiento interno de este mecanismo.

Eli Bendersky
fuente
2
entonces, para cada solicitud del cliente, se abre una conexión de socket NUEVA en el extremo del servidor. El servidor debe estar abierto a 80 siempre para escuchar las llamadas entrantes. Si recibe una llamada, crea inmediatamente un NUEVO socket con las cuatro tuplas como se menciona a continuación, lo que hará una conexión TCP entre el cliente y el servidor. ¿Es correcto mi entendimiento?
tormenta de cerebro
1
Esta es una cuestión fundamental y se probó recientemente en este en una entrevista: stackoverflow.com/questions/24871827/... Si tiene algún comentario sobre esto, por favor, puesto
lluvia de ideas
@brainstorm Solo si ignoras por completo la existencia de HTTP keep-alive.
Marqués de Lorne

Respuestas:

140

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 y Server 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:80y dos clientes, 10.0.0.1y 10.0.0.2.

10.0.0.1abre una conexión en el puerto local 1234y se conecta al servidor. Ahora el servidor tiene un socket identificado de la siguiente manera:

10.0.0.1:1234 - 192.168.1.1:80  

Ahora 10.0.0.2abre una conexión en el puerto local 5678y se conecta al servidor. Ahora el servidor tiene dos sockets identificados de la siguiente manera:

10.0.0.1:1234 - 192.168.1.1:80  
10.0.0.2:5678 - 192.168.1.1:80
17 de 26
fuente
3
No conozco los detalles de implementación (que probablemente varían de una plataforma a otra), solo sé que conceptualmente los sockets se identifican por el cuarteto de información que describí.
17 de 26
3
¿Tienes alguna referencia sobre esto?
qeek
3
Pregunta aleatoria: ¿Qué sucede si se está utilizando NAT y dos clientes en la misma red intentan usar el mismo puerto local cuando se conectan al servidor? Por ejemplo, si 10.0.0.1 y 10.0.0.2 están conectados a un enrutador con una IP externa de 192.168.0.1, entonces el servidor en 192.168.1.1 ve dos conexiones desde 192.168.0.1. ¿Qué sucede en ese caso si por alguna casualidad del generador de números aleatorios 10.0.0.1 y 10.0.0.2 eligen el mismo puerto local?
Aroth
44
El soporte NAT en el enrutador se encarga de los detalles allí. El tráfico de red en realidad pasa por dos conexiones: cliente a enrutador y enrutador a servidor. El enrutador realiza las conexiones salientes en dos puertos diferentes 192.168.0.1:1234 y 192.168.0.1:5678. El enrutador redirige el tráfico entrante al cliente correcto.
17 de 26
3
Si el cuarteto identifica un socket, ¿cuál es la información del cuarteto de un socket de escucha?
Eric Zheng
74

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.

Methos
fuente
13

Lo que me confunde cuando estaba aprendiendo esto, fue que los términos sockety portsugieren 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.

a2800276
fuente
Sí, la mayor parte de la terminología de la red es simplemente asignar nombres a ciertas colecciones de bits y a decisiones tomadas en función de sus valores ("identificador de protocolo", "enrutamiento", "enlace", "socket", etc.). Todo el hardware de su tarjeta de red está diseñado para recibir un flujo de bits. El controlador y el sistema operativo deciden qué les sucede en relación con los programas de su computadora. Podríamos deshacernos de toda esa terminología mañana si quisiéramos, pero el principio de entregar un flujo de bits parece fundamental ...
masterxilo
-1

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
¿Puedes dar más detalles sobre la parte del 'puerto de transferencia'?
Eli Bendersky
1
Esta es una descripción de algún protocolo anterior al TCP, o demasiado simplificada. Un cliente que intenta conectarse a un socket de escucha envía un paquete especial para establecer la conexión (conjunto de bits SYN). Hay una clara distinción entre un paquete que crea un nuevo socket y uno que usa un socket existente.
John M
... envía un paquete especial para establecer la conexión (conjunto de bits SYN). Lo que (según tengo entendido) hace que la pila de protocolos lo entregue al 'oyente' (si lo hay), por lo que solo puede haber un puerto de escucha por combinación de dirección / puerto / protocolo. Sin embargo, no estoy seguro de si esto está en la especificación o simplemente en la convención de implementación.
Peter Wone
1
El segundo párrafo no describe correctamente lo que sucede en la capa TCP o dentro de un proceso del servidor. Los procesos del servidor no necesitan mantener estructuras de datos de sockets de ningún tipo, ni verificar la entrada de IP: pares de puertos contra nada en absoluto. Para eso están los enchufes. FTP utiliza un puerto separado para datos, no para todas las 'comunicaciones adicionales', y sombreros hechos para simplificar el protocolo, no por razones de rendimiento. Usar un nuevo puerto sin mejorar el rendimiento de ninguna manera.
Marqués de Lorne
"mantiene una base de datos (lo que significa que no me importa qué tipo de estructura de tabla / lista / árbol / matriz / datos mágicos usa)" :) Normalmente llamo a esto una "Tabla" (o tal vez "Gráfico" o "Árbol de decisión" ) "Base de datos" me sugiere alguna implementación.
masterxilo