0
点赞
收藏
分享

微信扫一扫

p2p技术,python,udp实现打洞原理笔记

有点d伤 2022-04-26 阅读 76
pythonp2pudp

peer-to-peer简称P2P,即点对点技术。又称对等互联网络技术,是一种网络新技术,简单的说,P2P直接将计算机直接联系起来,在两台都是公网ip下的计算机可以轻松实现两台电脑的连接,但是运营商现在基本给的都是非公网ip,而且进入家庭中也会由路由器再次进行NAT,这样两台电脑将无法直接连接,如果传输信息,通常都是两台电脑向具有公网ip的服务器发送信息,再由服务器转发给对方,这样传输速度势必会大打折扣,采用p2p技术可将两台在NAT后的电脑直接连接,达到点对点传输。

p2p打洞的原理(采用udp):

两台在NAT之后的电脑无法直接建立连接,因此可以让两台电脑向向一个有公网ip的服务器发送请求,服务器会记录两个发送方的源地址,并将对方的源地址分别发送给发送方,这样两个发送方都拥有了对方的的地址,然后发送方可直接向对方的源地址发送信息,这样达到了点对点连接的效果。笔记记录了最基础的实现原理,目前只在NAT1,NAT2上可以测试成功,NAT3,NAT4理论上好像不行就没在测试。。。连个互相连接的源ip地址都是发送方最外层网关的ip,对于怎么从最外部网关连接到内部电脑的传输原理,在这里就不赘述了,就是记录下实现过程,有不对的地方望批评指正。

采用网络调试助手实现(3个不同的网络中):

1、建立一个公共服务器,主要作用为服务器在接收到2个请求之后分别将对方源地址发送给发送方。

2、第一台电脑网络调试助手,向服务器发送任意信息。

 如上图  两台电脑分别向ip后三位位为246的服务器发送请求,服务器将对方的源地址返回,之后将调试助手远程主机ip修改为刚才接收到的地址,这样udp打洞就实现了,两台电脑可以愉快的与对方直接连接,发送信息,达到点对点传输的目的。采用网络调试助手进行打洞的连接有时候不成功,需要多试几次,且受到对方地址后要快速发送,不然就通不了了,这个应该和运营商设定的资源释放时间有关。

用python实现的代码如下:

server

import logging
import socket

logger = logging.getLogger()
addresses = []

def addr_to_msg(addr):
    return '{}:{}'.format(addr[0], str(addr[1])).encode('utf-8')

def main(host='0.0.0.0', port=9999):
    sock = socket.socket(socket.AF_INET, # Internet
                         socket.SOCK_DGRAM) # UDP
    sock.bind((host, port))
    while True:
        data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
        logger.info("connection from: %s", addr)
        addresses.append(addr)
        if len(addresses) >= 2:
            logger.info("server - send client info to: %s", addresses[0])
            sock.sendto(addr_to_msg(addresses[1]), addresses[0])
            logger.info("server - send client info to: %s", addresses[1])
            sock.sendto(addr_to_msg(addresses[0]), addresses[1])
            addresses.pop(1)
            addresses.pop(0)


if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
    main()

client

import logging
import socket
import threading

logger = logging.getLogger()


def msg_to_addr(data):
    ip, port = data.decode('utf-8').strip().split(':')
    return (ip, int(port))


def send_to(sock,addr):
    while 1:
        a=input(f"\r向{addr}发送:").encode()
        sock.sendto(a, addr)

def to_recv(sock):
    while 1:
        data, addr1 = sock.recvfrom(1024)
        print('\r 接收信息: 地址:{} 内容:{}'.format(addr1, data))


def main(host='39.104.133.246', port=9999):
    sock = socket.socket(socket.AF_INET,  # Internet
                         socket.SOCK_DGRAM)  # UDP
    sock.sendto(b'0', (host, port))
    print(f"向服务器{host}发送")

    while True:
        print("开始等待接收1")
        data, addr = sock.recvfrom(1024)
        print('1、接收: 地址:{} 内容:{}'.format(addr, data))
        addr = msg_to_addr(data)
        print(f"2、获取新地址{addr}地址并开始发送")
        sock.sendto(b'0', addr)
        break

    t2 = threading.Thread(target=to_recv, args=(sock,))
    t2.start()
    t1 = threading.Thread(target=send_to, args=(sock, addr,))
    t1.start()


if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
    main()
举报

相关推荐

0 条评论