在两个客户端都连接了会议点服务器之后,如何使两个客户端彼此直接连接?

时间:2018-11-26 10:59:00

标签: python sockets networking nat hole-punching

我正在编写一个玩具集合点/中继服务器,它在端口5555上侦听两个客户端“ A”和“ B”。

它的工作原理是:即使A和B不知道各自的IP,服务器从第一个连接的客户端A接收到的每个字节也会发送到第二个连接的客户端B, >:

~/.bashrc

此代码当前有效:

~/.bash_profile

,您可以通过在服务器上启动它进行测试,并对其进行两个netcat连接:A -----------> server <----------- B # they both connect the server first A --"hello"--> server # A sends a message to server server --"hello"--> B # the server sends the message to B

然后我如何将信息传递给客户端A和B,使他们可以直接相互通信,而无需通过服务器传输字节?

有2种情况:

  • 一般情况,即即使A和B不在同一个本地网络中

  • 在这两个客户端位于同一本地网络(例如:使用同一家庭路由器)的特殊情况下,当这两个客户端将通过端口5555连接到服务器时,这将显示在服务器上:

    # server.py
    import socket, time
    from threading import Thread
    socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socket.bind(('', 5555))
    socket.listen(5)
    buf = ''
    i = 0
    
    def handler(client, i):
        global buf
        print 'Hello!', client, i 
        if i == 0:  # client A, who sends data to server
            while True:
                req = client.recv(1000)
                buf = str(req).strip()  # removes end of line 
                print 'Received from Client A: %s' % buf
        elif i == 1:  # client B, who receives data sent to server by client A
            while True:
                if buf != '':
                    client.send(buf)
                    buf = ''
                time.sleep(0.1)
    
    while True:  # very simple concurrency: accept new clients and create a Thread for each one
        client, address = socket.accept()
        print "{} connected".format(address)
        Thread(target=handler, args=(client, i)).start()
        i += 1
    

备注:此处先前未成功的尝试:UDP or TCP hole punching to connect two peers (each one behind a router) UDP hole punching with a third party

1 个答案:

答案 0 :(得分:1)

接受的答案给出了解决方案。在“客户端A和客户端B在同一个本地网络中” 的情况下,这是一些其他信息。 如果服务器注意到两个客户端具有相同的公共IP,则确实可以检测到这种情况。

然后服务器可以选择客户端A作为“本地服务器”,选择客户端B作为“本地客户端”。

然后,服务器将向客户端A询问其“本地网络IP”。 Client A can find it with

import socket
localip = socket.gethostbyname(socket.gethostname())  # example: 192.168.1.21

,然后将其发送回服务器。服务器将将此“本地网络IP”传达给客户端B。

然后,客户端A将运行“本地服务器”:

import socket
soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
soc.bind(('0.0.0.0', 4000))
data, client = soc.recvfrom(1024)
print("Connected client:", client)
print("Received message:", data)
soc.sendto(b"I am the server", client)

并且客户端B将作为“本地客户端”运行:

import socket
soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server = ('192.168.1.21', 4000)   # this "local network IP" has been sent Client A => server => Client B
soc.sendto("I am the client", server)
data, client = soc.recvfrom(1024)
print("Received message:", data)