catalogue

1. NAT概念
2. P2P概念
3. UDP打洞
4. P2P DEMO
5. ZeroNet P2P

1. NAT概念

在STUN协议中,根据内部终端的地址(LocalIP:LocalPort)到NAT出口的公网地址(PublicIP:PublicPort)的影射方式,把NAT分为四种类型(rfc3489: http://www.ietf.org/rfc/rfc3489.txt)

1. Full Cone: 这种NAT内部的机器A连接过外网机器C后,NAT会打开一个端口,然后外网的任何发到这个打开的端口的UDP数据报都可以到达A。不管是不是C发过来的(NAT源端口映射)
2. Restricted Cone: 这种NAT内部的机器A连接过外网的机器C后,NAT打开一个端口,然后C可以用任何端口和A通信,其他的外网机器不行(目的IP映射)
3. Port Restricted Cone: 这种NAT内部的机器A连接过外网的机器C后,NAT打开一个端口,然后C可以用原来的端口和A通信,其他的外网机器不行(NAT目的端口映射)
4. Symmetic: 对于这种NAT.连接不同的外部目标。原来NAT打开的端口会变化,而Cone NAT不会,虽然可以用端口猜测,但是成功的概率很小 

或者分为2类

1. 基本的NAT: 一个私有网络(域)中的节点中只有很少的节点需要与外网连接。那么这个子网中其实只有少数的节点需要全球唯一的IP地址,其他的节点的IP地址应该是可以重用的。因此,基本的NAT实现的功能很简单,在子网内使用一个保留的IP子网段,这些IP对外是不可见的。子网内只有少数一些IP地址可以对应到真正全球唯一的IP地址。如果这些节点需要访问外部网络,那么基本NAT就负责将这个节点的子网内IP转化为一个全球唯一的IP然后发送出去(基本的NAT会改变IP包中的原IP地址,但是不会改变IP包中的端口)2. NAPT(Network Address/Port Translator): NAPT不但会改变经过这个NAT设备的IP数据报的IP地址,还会改变IP数据报的TCP/UDP端口1) 如果Client A想向Client B发送信息,那么Client A发送命令给Server S,请求Server S命令Client B向Client A方向打洞2) 如果Client B想向Client A发送信息,那么Client B发送命令给Server S,请求Server S命令Client A向Client B方向打洞
总体来说,P2P(NAT环境下)的通信都是被动反向的,即谁想向谁发送数据,需要通知对方向自己"打洞"

2.  P2P概念

P2P是peer-to-peer的缩写,peer在英语里有"(地位、能力等)同等者"、"同事"和"伙伴"等意义。这样一来,P2P也就可以理解为"伙伴对伙伴"的意思,或称为对等联网,简单的说,P2P直接将人们联系起来,让人们通过互联网直接交互。P2P使得网络上的沟通变得容易、更直接共享和交互,真正地消除中间商。P2P就是人可以直接连接到其他用户的计算机、交换文件,而不是像过去那样连接到服务器去浏览与下载。P2P另一个重要特点是改变互联网现在的以大网站为中心的状态、重返“非中心化”,并把权力交还给用户
事实上,网络上现有的许多服务可以归入P2P的行列。即时讯息系统譬如ICQ、AOL Instant Messenger、Yahoo Pager、微软的MSN Messenger以及国内的OICQ是最流行的P2P应用

0x1: 普通的直连式P2P实现

0x2: STUN方式的P2P实现

STUN是RFC3489规定的一种NAT穿透方式,STUN的探测过程需要有一个公网IP的STUN server,在NAT后面的UAC必须和此server配合,互相之间发送若干个UDP数据包。UDP包中包含有UAC需要了解的信息,比如NAT外网IP,PORT等等。UAC通过是否得到这个UDP包和包中的数据判断自己的NAT类型,假设如下场景

1. UAC(B): UAC的IP为IPB
2. NAT(A): NAT的IP为IPA
3. SERVER(C): SERVER的IP为IPC1 、IPC2
//服务器C有两个IP 

NAT的探测过程

0x3: P2P文件传输协议之BitTorrent协议

Bittorrent与其他传统P2P软件如Gnutella,Fasttrack不同,Bittorrent只是一个纯粹的文件下载协议,并提供搜索功能,所以往往资源的获取要跟其他一些应用结合起来,比如说发布Bittorrent种子信息的网站

1. Bittorrent工作原理

Bittorrent的工作原理其实很简单,他就是将一份数据分隔成256K大小的数据分组,并在Bittorrent 网络中一群用户相互协作完成这些数据的分发,用户参与数据分发的信息已文件的形式存储,一般可以通过web网站获取这些信息但是实际数据传输依靠的不是Http协议,而是由专门的P2P协议来完成,这些对于用户都是透明的
普通的HTTP/FTP下载使用TCP/IP协议,BitTorrent协议是架构于TCP/IP协议之上的一个P2P文件传输协议,处于TCP/IP结构的应用层。 BitTorrent协议本身也包含了很多具体的内容协议和扩展协议,并在不断扩充中
根据BitTorrent协议,文件发布者会根据要发布的文件生成提供一个.torrent文件,即种子文件,也简称为“种子"。 .torrent文件本质上是文本文件,包含Tracker信息和文件信息两部分

1. Tracker信息主要是BT下载中需要用到的Tracker服务器(中间人服务器)的地址,以及针对Tracker服务器的设置
2. 文件信息是根据对目标文件的计算生成的计算结果根据BitTorrent协议内的B编码规则进行编码,它的主要原理是需要把提供下载的文件虚拟分成大小相等的块,块大小必须为2k的整数次方(由于是虚拟分块,硬盘上并不产生各个块文件),并把每个块的索引信息和Hash验证码写入.torrent文件中
3. 所以,.torrent文件就是被下载文件的"索引"

2. 种子文件结构

一个种子文件,通常是以.torrent后缀结尾。BitTorrent协议规定,torrent文件本身,内容必须是utf8编码格式,并且其中的字段结构采用bencoding编码格式
Torrent种子文件由两部分组成:announce(tracker url)和文件信息,该种子文件的一部分如下,根据bencoding编码格式,把这段字符解码还原后

announce:http://www.chinahdtv.org/announce.php?passkey=6e7a1c7ca4164d87e9b0e00ec63aa749
created by:uTorrent/2040
creation date:1369699038
encoding:UTF-8
info:
{files:[
{length:158784,path:[Iron.Man.3.2013.HDSCR.ULTRA.EDiTiON.720p.x264.chn.srt]}, {length:107117,path:[Iron.Man.3.2013.HDSCR.ULTRA.EDiTiON.720p.x264.chn1.srt]}, {length:93644,path:[Iron.Man.3.2013.HDSCR.ULTRA.EDiTiON.720p.x264.chn2.srt]},
{length:4272200020,path:[Iron.Man.3.2013.HDSCR.ULTRA.EDiTiON.720p.x264.mkv]}],
name:钢铁侠3.Iron.Man.3.2013.HDSCR.ULTRA.EDiTiON.720p.x264,
piece length:4194304,
pieces:P1,P2,P3...P1019
private:1
source:[hd.gg] CNHD ChinaHDTV
}

一个torrent种子文件有点类似于XML格式的文件,包含如下组成部分

1. tracker地址,这里就是announce后面的url
2. 种子创建软件及其版本号,这里是uTorrent软件创建的,版本号为2040
3. 创建日期,这里是1369699038,这个数字显示的是从UTC 1970-1-1 00:00:00到到现在所经历的秒数
4. 编码格式,这里是UTF-8(codepage=936)
5. info区,这里指定的是该种子有几个文件,文件有多长,目录结构,以及目录和文件的名字
6. Name字段,指定顶层目录名字
7. 每个段的大小,Bittorrent协议是把一个文件分成很多个小段,然后分段下载的,这个地方就是指定每个段的大小,单位是字节,这里每个段的大小大约为4MB(4194304)
8. 段哈希值,就是整个种子中,每个段的SHA1哈希值拼在一起,每个段的哈希长度是固定的,20个字符,所以pieces后面跟的那个数字20380其实是段数量*20,如果你用20380除以20,就会发现这个种子段数量为1019,乘上前面的段大小,这个种子大概有4GB大小,也就是说你把这个种子下载完后,占硬盘4GB空间
9. private值,这个属性主要显示这个种子是私有的,还是公有的。一般那些各大PT站就是私有的。私有的种子会禁掉DHT(distributed hash table),因为如果你的client开这个功能,那就会跳过tracker来和其他peer进行数据交换,在很多PT内站(CHDbits,CMCT,CNHD)把这种行为称为作弊,会直接ban掉你在PT站上的帐号
10. 源,显示该种子的来源,这里是CNHD

以上的每个属性并不是必须的,有的属性属于BitTorrent Enhancement Proposals (BEPs),就是BitTorrent协议的扩展,虽然不属于正式标准的一部分,但是很多客户端都支持这种格式

3. BitTorrent通信流程与网络包结构

http://www.cnblogs.com/LittleHann/p/3837839.html

4. BitTorrent下载

下载者要下载文件内容,需要先得到相应的.torrent文件,然后使用BT客户端软件进行下载(读取.torrent文件中的索引)

1. 下载时,BT客户端首先解析.torrent文件得到Tracker地址,然后连接Tracker服务器
2. Tracker服务器回应下载者的请求,提供下载者其他下载者(包括发布者)的IP(相当于打洞过程)
3. 下载者再连接其他下载者
4. 根据.torrent文件,两者分别对方告知自己已经有的块,然后交换对方没有的数据
5. 此时不需要其他服务器参与,分散了单个线路上的数据流量,因此减轻了服务器负担(打洞完成后,不再需要中间人服务器的参与,通信双方直接进行点对点通信)
6. 下载者每得到一个块,需要算出下载块的Hash验证码与.torrent文件中的对比,如果一样则说明块正确,不一样则需要重新下载这个块,这种规定是为了解决下载内容准确性的问题 

一般的HTTP/FTP下载,发布文件仅在某个或某几个服务器,下载的人太多,服务器的带宽很易不胜负荷,变得很慢,而BitTorrent协议下载的特点是,下载的人越多,提供的带宽也越多,种子也会越来越多,下载速度就越快

Relevant Link:

http://www.2cto.com/net/200506/5494.html
http://www.cppblog.com/peakflys/archive/2013/01/25/197562.html
http://blog.chinaunix.net/uid-11572501-id-2868679.html
https://github.com/Martiusweb/p2p
http://network.51cto.com/art/201006/207932.htm
http://blog.csdn.net/wengpingbo/article/details/9174363
https://github.com/axeliux/P2P

3. UDP打洞

UDP打洞用于在两个NAT内网之间进行网络连接

0x1:  打洞基本概念

我们来看看一个P2P软件的流程

1. 首先,Client A登录服务器,NAT A为这次的Session分配了一个端口60000,那么Server S收到的Client A的地址是202.187.45.3:60000,这就是Client A的外网地址了
2. 同样,Client B登录Server S,NAT B给此次Session分配的端口是40000,那么Server S收到的B的地址是187.34.1.56:40000
3. 此时,Client A与Client B都可以与Server S通信了。如果Client A此时想直接发送信息给Client B,那么他可以从Server S那儿获得B的公网地址187.34.1.56:40000,但是Client A不能直接向这个地址发送信息,因为如果这样发送信息,NAT B会将这个信息丢弃(因为这样的信息是不请自来的,为了安全,大多数NAT都会执行丢弃动作)。现在我们需要的是在NAT B上打一个方向为202.187.45.3(即Client A的外网地址)的洞,那么Client A发送到187.34.1.56:40000的信息,Client B就能收到了。这个打洞命令由谁Server S来发出(Server S只是作为一个中转代理)
4. 总结一下这个过程:如果Client A想向Client B发送信息,那么Client A发送命令给Server S,请求Server S命令Client B向Client A方向打洞。然后Client A就可以通过Client B的外网地址与Client B通信了

理解UDP NAT打洞,需要明白的是

1. 在NAT模式下,内网的IP是不能被外网直接正向访问到的,只能又内网IP向外网IP主动发起连接,一旦连接成功建立起来,后续的交互通信是完全正常的
2. 而P2P要面对的问题就是两个IP都在NAT内网中,谁也无法率先发起连接(NAT会拒绝"不请自来"的外网连接),所以需要事先在"中间人(Server S)"上进行登记,登记的内容为对应的NAT公网IP:PORT
3. 如果某个NAT内网IP需要向另一个NAT内网IP进行通信,需要"通知"中间人Server S,由它转发来告知目标NAT IP主动向自己主动发起连接,这谓之"打洞","打洞"完成后,当前NAT就记录了当前NAT IP和目标NAT外网IP的的会话记录了,而此时对于对方的NAT来说,同样也记录一个会话,解决了"鸡生蛋,蛋生鸡"的问题后,此后,两个NAT内网IP就可以互相开始正常通信了

0x2: Server端

#!/usr/bin/python
#coding:utf-8
import socket, sys, SocketServer, threading, thread, time SERVER_PORT = 1234
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', SERVER_PORT))
user_list = [] def server_handle(): while True: cli_date, cli_pub_add = sock.recvfrom(8192) now_user = [] headder = [] cli_str = {} headder = cli_date.split('\t') for one_line in headder: str = {} str = one_line args = str.split(':') cli_str[args[0]] = args[1] if cli_str['type'] == 'login' : del cli_str['type'] now_user = cli_str now_user['cli_pub_ip'] = cli_pub_add[0] now_user['cli_pub_port'] = cli_pub_add[1] user_list.append(now_user) toclient = 'info#%s login in successful , the info from server'%now_user['user_name'] sock.sendto(toclient,cli_pub_add) print'-'*100print"%s 已经登录,公网IP:%s 端口:%d\n"%(now_user['user_name'],now_user['cli_pub_ip'],now_user['cli_pub_port']) print"以下是已经登录的用户列表"for one_user in user_list: print'用户名:%s 公网ip:%s 公网端口:%s 私网ip:%s 私网端口:%s'%(one_user['user_name'],one_user['cli_pub_ip'],one_user['cli_pub_port'],one_user['private_ip'],one_user['private_port']) elif cli_str['type'] == 'alive': passelif cli_str['type'] == 'logout' : passelif cli_str['type'] == 'getalluser' : print'-'*100for one_user in user_list : toclient = 'getalluser#username:%s pub_ip:%s pub_port:%s pri_ip:%s pri_port:%s'%(one_user['user_name'],one_user['cli_pub_ip'],one_user['cli_pub_port'],one_user['private_ip'],one_user['private_port']) sock.sendto(toclient,cli_pub_add) if __name__ == '__main__': thread.start_new_thread(server_handle, ()) print'服务器进程已启动,等待客户连接'
while True: for one_user in user_list: toclient = 'keepconnect#111'sock.sendto(toclient,(one_user['cli_pub_ip'],one_user['cli_pub_port']))  time.sleep(1) 

0x3: Client

#!/usr/bin/python
#coding:utf-8
import socket, SocketServer, threading, thread, time
CLIENT_PORT = 4321
SERVER_IP = "114.55.36.222"
SERVER_PORT = 1234
user_list = {}
local_ip = socket.gethostbyname(socket.gethostname())
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) def server_handle(): print'客户端线程已经启动 , 等待其它客户端连接'while True: data, addr = sock.recvfrom(8192) data_str = data.split('#') data_type = data_str[0] data_info = data_str[1] if data_type == 'info' : del data_str[0] print data_info      if data_type == 'getalluser' : data_sp = data_info.split(' ') user_name = data_sp[0].split(':')[1] del data_sp[0] user_list[user_name] = {} for one_line in data_sp: arg = one_line.split(':') user_list[user_name][arg[0]] = arg[1] if data_type == 'echo' : print data_info if data_type == 'keepconnect': messeg = 'type:alive'sock.sendto(messeg, addr) if __name__ == '__main__': thread.start_new_thread(server_handle, ()) time.sleep(0.1) cmd = raw_input('输入指令>>') while True: args = cmd.split(' ') if args[0] == 'login': user_name = args[1] local_uname = args[1] address = "private_ip:%s private_port:%d" % (local_ip, CLIENT_PORT) headder = "type:login\tuser_name:%s\tprivate_ip:%s\tprivate_port:%d" % (user_name,local_ip,CLIENT_PORT) sock.sendto(headder, (SERVER_IP, SERVER_PORT)) elif args[0] == 'getalluser': headder = "type:getalluser\tuser_name:al"sock.sendto(headder,(SERVER_IP,SERVER_PORT)) print '获取用户列表中...'time.sleep(1) for one_user in user_list: print'username:%s pub_ip:%s pub_port:%s pri_ip:%s pri_port:%s'%(one_user,user_list[one_user]['pub_ip'],user_list[one_user]['pub_port'],user_list[one_user]['pri_ip'],user_list[one_user]['pri_port']) elif args[0] == 'connect': user_name = args[1] to_user_ip = user_list[user_name]['pub_ip'] to_user_port = int(user_list[user_name]['pub_port']) elif args[0] =='echo': m = ' '.join(args[1:]) messeg = 'echo#from %s:%s'%(local_uname,m) sock.sendto(messeg, (to_user_ip, to_user_port)) time.sleep(0.1)  cmd = raw_input('输入指令>>') 

0x4: 测试过程

1. 登录(NAT内网机器向Server S注册)

2. NAT内网IP获取Server S中注册用户,准备开始打洞

3. 用户A(51_10)需要向用户B(190_203)建立连接

完成打洞的建立和正常通信

Relevant Link:

http://www.cnblogs.com/yrh2847189/archive/2007/06/20/790013.html
http://lustlost.blog.51cto.com/2600869/1177494

4. P2P DEMO

A peer-to-peer file sharing server written in C, and client written in Java. Developed in collaboration with Justin Hill (https://github.com/justindhill).
p2p utilizes TCP server (https://github.com/mdlayher/tcpd) as well as the Apache Commons Codec (http://commons.apache.org/codec/) in order to facilitate the C server component
p2p uses a centralized directory server approach. Clients connect to the central server in order to retrieve a list of files which exist among peers in the network. Once a client requests to download a file, the connection is negotiated between peers, and the client can begin to download the file.

Relevant Link:

https://github.com/huangyingcai/p2p

5. ZeroNet P2P

ZeroNet是一个利用比特币加密和BT技术提供不受审查的网络与通信的BT平台,ZeroNet网络功能已经得到完整的种子的支持和加密连接,保证用户通信和文件共享的安全。使用ZeroNet,可以实现匿名上网,可以在任意一台机器上搭建网站,但即机器关闭,网站依然在全球存在,别人无法关闭这个网站
ZeroNet是一个去中心化的类似于Internet的网络,由Python制作,完全开源。网站由特殊的"ZeroNet URL"可以被使用一般的浏览器通过ZeroNet程序浏览,就像访问本地主机一样。ZeroNet默认并"不"匿名,但是用户可以通过内置的Tor功能进行匿名化。ZeroNet使用Bitcoin加密算法及BitTorrent网络

0x1: 优势

1. 防DMCA Take down
2. 基于p2p原理,只要建好并有人浏览过,即使服务器,网站依然在全球存在
3. 基于p2p原理,支付内网穿透
4. 基于比特币原理,账号很安全
5. 不需要域名,任何人访问都使用http://127.0.0.1:43110/字符串

Relevant Link:

http://www.williamlong.info/archives/4574.html
https://github.com/HelloZeroNet/ZeroNet

Copyright (c) 2016 LittleHann All rights reserved

转载于:https://www.cnblogs.com/LittleHann/p/5556185.html

UDP打洞、P2P组网方式研究相关推荐

  1. 华为WLAN产品介绍与组网(包括capwap隧道,ap上线,STA上线,组网方式,转发方式)

    AC6003: AC6005: AC6605: ACU2:用在交换机上的一个板卡,适用于S7700,S9700,S12700等框式交换机的任何LPU槽位,ACU2可安装在等框式交换机的任何LPU槽位, ...

  2. 【原创】IP摄像头技术纵览(七)---P2P技术—UDP打洞实现内网NAT穿透

    [原创]IP摄像头技术纵览(七)-P2P技术-UDP打洞实现内网NAT穿透 本文属于<IP摄像头技术纵览>系列文章之一: Author: chad Mail: linczone@163.c ...

  3. 基于TCP/UDP的P2P网络通信协议研究与实现

    此章节是理论知识,下个章节会奉献源码 摘    要 对等式网络(peer-to-peer,简称P2P),又称点对点技术,是一种实现网络中不同主机直接通信的技术.在物联网的应用中,大量的设备需要能进行点 ...

  4. UDP打洞NAT大致分为下面四类 P2P

    NAT大致分为下面四类 1) Full Cone 这种NAT内部的机器A连接过外网机器C后,NAT会打开一个端口.然后外网的任何发到这个打开的端口的UDP数据报都可以到达A.不管是不是C发过来的. 例 ...

  5. pwnat——一种无需第三方服务器就能完成NAT点对点P2P穿透的基于UDP打洞技术的新方法

    pwnat--一种无需第三方服务器就能完成NAT点对点P2P穿透的基于UDP打洞技术的新方法 简介 传统的udp打洞 UDP 打洞原理及过程 pwnat技术,无需第三方服务器! pwnat用法 pwn ...

  6. 简单解释 P2P 技术之 UDP 打洞

    P2P 通信最大的障碍就是 NAT(网络地址转换),NAT 使得局域网内的设备也可以与公网进行通讯,但是不同 NAT 下的设备之间通讯将会变得很困难.UDP 打洞就是用来使得设备间绕过 NAT 进行通 ...

  7. P2P技术基础: UDP打洞原理

    转自:http://blog.pfan.cn/fengfei/18828.html 首先先介绍一些基本概念:             NAT(Network Address              ...

  8. 短波自组网路由协议驱动方式研究

    短波自组网路由协议驱动方式研究 宋宝华   杨平   摘 要:自 组网路由协议可依驱动方式分为表驱动和按需驱动,这两种驱动方式的路由协议各有其优缺点.本文对这两类路由协议的路由发现延迟.路由开销.网络 ...

  9. p2p内网穿透技术-udp打洞

    在公司如何访问家里的电脑?实现方法有很多,其它p2p传输文件最快,能否实现? udp打洞原理 假设有两台分别处于各自的私有网络中的主机:A和B:N1和N2是两个网络的NAT设备,分别拥有IP地址P1和 ...

最新文章

  1. 热门专业没那么难,文科生打开统计学的正确方式!
  2. ubuntu16安装anaconda显示没有文件或那个目录
  3. 100%你没见过的魔兽表情包,拿去!再扯情怀已俗!
  4. html ip输入框效果,html5 input文本框输入动画特效
  5. 织梦文章主表关联栏目查询 生成静态url语句
  6. 第八节:实战前必须掌握的10个指令(下)
  7. 大学计算机基础网络配置实验报告答案,大学计算机基础实验报告2.doc
  8. php增加md5加密的方法_php进行md5加密简单实例方法
  9. android代码 发警报音,Android 8中的警报重复
  10. 2008年国际十大财经新闻
  11. 三人表决器逻辑表达式与非_数电实验 | 组合逻辑电路(半加器全加器及逻辑运算)...
  12. 批量打印二维码的软件---使用心得(领跑条码标签打印软件)
  13. 公布C#写的网游外挂源代码
  14. 7-2 列出连通集 (25分)
  15. modelmapper属性匹配问题分析
  16. 如何在Docker容器中安装RabbitMQ
  17. 梦想照进现实:挣扎中的国产操作系统
  18. 苹果x怎么关机_苹果12怎么关机 iPhone12关机方法汇总
  19. 【无标题】PCI-5565PIORC-110000128MB反射内存卡多模光纤
  20. 斗鱼直播Android开发二面被刷,好文推荐

热门文章

  1. 【久远讲算法】队列——先进先出的数据结构
  2. mysql 悲观锁实现
  3. 如何理解statsmodels.ols的输出结果?ols计算的线性回归结果以及手动计算的结果的对比
  4. 常用H5标签-第二部分
  5. JavaScript中Map方法的详解
  6. Gephi简易学习[一]———— Gephi安装,并了解Gephi
  7. 人工智能可预测阿茨海默症病情演变
  8. 怎么提高公文写作水平?原来这就是公文参考模版
  9. 微信支付:商户订单号重复
  10. 使用VMware备份操作系统