Según tengo entendido, esto es lo que sucede cuando un cliente realiza una solicitud de conexión:
- El servidor estará vinculado a un número de puerto en particular. El número de puerto siempre está vinculado a un proceso de escucha. Como solo el servidor está escuchando las conexiones entrantes, no necesitamos vincularnos del lado del cliente
- El servidor seguirá escuchando ese número de puerto.
- El cliente enviará una
connect()
solicitud. - El servidor aceptará la solicitud usando
accept()
. Tan pronto como el servidor acepta la solicitud del cliente, el kernel asigna un número de puerto aleatorio para el servidorsend()
yreceive()
, dado que el mismo número de puerto en el servidor no se puede usar para enviar y escuchar, y el puerto anterior todavía está escuchando nuevas conexiones
Dado todo eso, ¿cómo descubre el servidor en qué puerto está recibiendo el cliente? Sé que el cliente enviará segmentos TCP con un puerto de origen y un puerto de destino, por lo que el servidor utilizará el puerto de origen de ese segmento como su puerto de destino, pero ¿qué función llama el servidor para averiguar sobre ese puerto? Es accept()
?
Respuestas:
Es parte del encabezado TCP (o UDP, etc.) en el paquete. Entonces el servidor se entera porque el cliente se lo dice. Esto es similar a cómo descubre la dirección IP del cliente (que es parte del encabezado IP).
Por ejemplo, cada paquete TCP incluye un encabezado IP (con IP de origen, IP de destino y protocolo [TCP], como mínimo). Luego hay un encabezado TCP (con puerto de origen y destino, y más).
Cuando el núcleo recibe un paquete SYN (el inicio de una conexión TCP) con una IP remota de 10.11.12.13 (en el encabezado de IP) y un puerto remoto de 12345 (en el encabezado de TCP), entonces conoce la IP y el puerto remotos . Devuelve un SYN | ACK. Si recupera un ACK, la
listen
llamada devuelve un nuevo socket, configurado para esa conexión.Un socket TCP se identifica de forma exclusiva por los cuatro valores (IP remota, IP local, puerto remoto, puerto local). Puede tener múltiples conexiones / sockets, siempre que al menos uno de ellos sea diferente.
Normalmente, el puerto local y la IP local serán los mismos para todas las conexiones a un proceso de servidor (por ejemplo, todas las conexiones a sshd estarán en local-ip: 22). Si una máquina remota realiza múltiples conexiones, cada una utilizará un puerto remoto diferente. Por lo tanto, todo menos el puerto remoto será el mismo, pero está bien, solo uno de los cuatro tiene que diferir.
Puede usar, por ejemplo, wirehsark para ver el paquete, y etiquetará todos los datos por usted. Aquí está el puerto de origen resaltado (observe que está resaltado en el paquete decodificado, así como el volcado hexadecimal en la parte inferior):
fuente
write
(etc.) vaya al lugar correcto.La "solicitud de conexión (la
connect()
llamada al sistema del programa del cliente , por lo general) provoca un protocolo de enlace de tres vías . El primer paquete del protocolo de enlace de tres vías (del cliente al servidor) tiene el indicador SYN establecido e incluye el número de puerto TCP del programa del cliente kernel le asigna.Puede ver esto en un artículo sobre los paquetes Nmap vs Natural SYN . La decodificación del paquete Nmap SYN tiene la frase "source.60058> dest.22". La decodificación del "paquete SYN legítimo" tiene la frase "source.35970> dest.80". Los dos paquetes SYN le dicen al núcleo remoto que los paquetes provienen del puerto TCP 60058 y del puerto 35970, respectivamente.
fuente
getpeername()
debería permitirle hacerlo en cualquier socket abierto. Laaccept()
llamada al sistema que debe usar el código del servidor para obtener un descriptor de archivo de socket para comunicarse con el cliente tiene un parámetro ("sockaddr" en mis páginas de manual) que contiene la dirección IP y el número de puerto TCP del cliente potencial.El socket TCP es un socket orientado a la transmisión. Los dos descriptores de socket (propiedad de usted y su par) están conectados de manera confiable. Para que no tenga que preocuparse por el puerto del cliente, ¡simplemente escriba su descriptor de socket!
Además, siéntase libre de getsockname (2) si realmente quiere saber eso (para el registro tal vez)
fuente
La conexión está definida por una tupla (IP de origen, puerto de origen, IP de destino, puerto de destino). Las respuestas van al revés.
fuente