windows tcp network-protocols winsock2 hole-punching

windows - Punzonado de agujeros TCP



network-protocols winsock2 (4)

Un comienzo 2 hilos:
Un hilo intenta conectarse al enrutador de B con la información enviada por S
El otro hilo está esperando una conexión entrante en el mismo puerto que se usó para conectarse a su enrutador cuando se conectó a S

No puedes hacer esto con dos hilos, ya que es solo una operación. Cada conexión TCP que está realizando una conexión de salida también está esperando una conexión entrante. Simplemente llame a ''conectar'', y ambos están enviando SYN salientes para establecer una conexión y están esperando que SYN entrantes hagan una conexión.

Sin embargo, es posible que deba cerrar su conexión al servidor. Es probable que su plataforma no le permita realizar una conexión TCP desde un puerto cuando ya tiene una conexión establecida desde ese mismo puerto. Entonces, al iniciar la perforación de agujeros TCP, cierre la conexión con el servidor. Vincule un nuevo socket TCP a ese mismo puerto y llame a connect .

Estoy tratando de implementar la perforación de orificios TCP con el socket de Windows usando la cadena de herramientas mingw. Creo que el proceso es correcto, pero el agujero no parece tomar. Utilicé this como referencia.

  1. A y B se conectan al servidor S
  2. S envía al enrutador IP de A , B + el puerto que usó para conectarse a S
  3. S hace lo mismo para B
  4. Un comienzo 2 hilos:
    • Un hilo intenta conectarse al enrutador de B con la información enviada por S
    • El otro hilo está esperando una conexión entrante en el mismo puerto que se usó para conectarse a su enrutador cuando se conectó a S
  5. B hace lo mismo

No tengo ningún problema en el código que pienso desde:

  • A y B consiguen entre sí ip y puerto para usar
  • Ambos están escuchando en el puerto que utilizaron para conectarse a su enrutador cuando contactaron con el servidor
  • Ambos se conectan a la ip y al puerto correctos pero se agotan (código de error 10060 )

Me estoy perdiendo algo?

EDITAR: Con la ayuda del explorador de procesos, veo que uno de los clientes logró establecer una conexión con el par. Pero el par no parece considerar la conexión a realizar.

Aquí está lo que capturé con Wireshark. Por el bien del ejemplo, el servidor S y el cliente A están en la misma PC. El servidor S escucha en un puerto específico ( 8060 ) redirigido a esa PC. B aún intenta conectarse con la IP correcta porque ve que la dirección pública de A enviada por S es localhost y, por lo tanto, usa la IP pública de S en su lugar. (He reemplazado las IP públicas por marcadores de posición)

EDIT 2 : Creo que la confusión se debe al hecho de que los datos de solicitud de conexión entrantes y salientes se transfieren en el mismo puerto. Lo que parece alterar el estado de la conexión porque no sabemos qué zócalo obtendrá los datos del puerto. Si cito msdn:

La SO_REUSEADDR socket SO_REUSEADDR permite que un socket se enlace a la fuerza a un puerto en uso por otro socket. El segundo socket llama setsockopt con el parámetro optname establecido en SO_REUSEADDR y el parámetro optval establecido en un valor booleano de TRUE antes de llamar a bind en el mismo puerto que el socket original. Una vez que el segundo socket se ha enlazado correctamente, el comportamiento de todos los sockets enlazados a ese puerto es indeterminado.

¡Pero hablar en el mismo puerto es requerido por la técnica de perforación de agujeros TCP para abrir los agujeros !


  1. Use Wireshark para verificar que la solicitud de conexión tcp (proceso Handhsake de 3 vías) funcione correctamente.

  2. Asegúrese de que su hilo de escucha tenga select () para des-multiplexar el descriptor.

  3. sockPeerConect (el zócalo utilizado para conectar otro par) es FD_SET () en el hilo de escucha.

  4. Asegúrate de que estás comprobando

    int Listener Thread() { while(true) { FD_SET(sockPeerConn); FD_SET(sockServerConn); FD_SET(nConnectedSock ); if (FD_ISSET(sockPeerConect) { /// and calling accept() in side the nConnectedSock = accept( ....); } if (FD_ISSET(sockServerConn) { /// receive data from Server recv(sockServerConn ); } if (FD_ISSET(nConnectedSock ) { /// Receive data from Other Peer recv(nConnectedSock ); } } }

5. Asegúrese de que está iniciando simultáneamente la conexión entre pares A a B y B a A.
6. Comience su hilo de escucha antes de conectarse al servidor y igual y tenga un solo hilo de escucha para recibir el servidor y el cliente.


Una solución simple para atravesar los enrutadores NAT es hacer que su tráfico siga un protocolo que su NAT ya tiene un algoritmo para reenviar, como FTP.


no todos los enrutadores son compatibles con la perforación de tcp, consulte el siguiente documento que explica en detalle:

this