UDP打洞、P2P组网方式研究

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‘-‘*100
        print"%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‘:
        pass
    elif cli_str[‘type‘] == ‘logout‘ :
        pass
    elif cli_str[‘type‘] == ‘getalluser‘ :
        print‘-‘*100
        for 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

时间: 2024-10-14 01:25:39

UDP打洞、P2P组网方式研究的相关文章

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

[原创]IP摄像头技术纵览(七)-P2P技术-UDP打洞实现内网NAT穿透 本文属于<IP摄像头技术纵览>系列文章之一: Author: chad Mail: [email protected] 本文可以自由转载,但转载请务必注明出处以及本声明信息. NAT技术的实际需求在10几年前就已经出现,为了解决这个问题,10几年来全世界的牛人早已经研究好了完整的解决方案,网上有大量优秀的解决方案文章,笔者自知无法超越,所以秉承拿来主义,将优秀文章根据个人实验及理解整理汇录于此,用于解释IP摄像头整个技

NAT的全然分析及其UDP穿透的全然解决方式

NAT的全然分析及其UDP穿透的全然解决方式 一:基本术语 防火墙 防火墙限制了私网与公网的通信,它主要是将(防火墙)觉得未经授权的的包丢弃,防火墙仅仅是检验包的数据,并不改动数据包中的IP地址和TCP/UDPport信息. 网络地址转换(NAT) 当有数据包通过时,网络地址转换器不仅检查包的信息,还要将包头中的IP地址和port信息进行改动.以使得处于NAT之后的机器共享几个仅有的公网IP地址(一般是一个).网络地址转换器主要有两种类型. P2P应用程序 P2P应用程序是指,在已有的一个公共s

NAT穿透(UDP打洞)

1.NAT(Network Address Translator)介绍 NAT有两大类,基本NAT和NAPT. 1.1.基本NAT 静态NAT:一个公网IP对应一个内部IP,一对一转换 动态NAT:N个公网IP对应M个内部IP,不固定的一对一转换关系  1.2.NAPT(Network Address/Port Translator) 现在基本使用这种,又分为对称和锥型NAT. 锥型NAT,有完全锥型.受限制锥型.端口受限制锥型三种: a)Full Cone NAT(完全圆锥型):从同一私网地址

UDP 打洞 原理解释

终于找到了一份满意的UDP打洞原理解释,附上正文,自己整理了一下源码 3.3. UDP hole punching UDP打洞技术 The third technique, and the one of primary interest in this document, is widely known as "UDP Hole Punching." UDP hole punching relies on the properties of common firewalls and c

几种VPN组网方式介绍

几种VPN组网方式介绍 VPN是(Virtual Private Network ,虚拟专用网络)的简称,最初是指通过公用网络(例如Internet)将多个不同地区的局域网,组建成广域网的一项技术.为什么要用VPN组网呢?我们简要介绍一下. 在Internet没有普及的时候,跨地区的单位如果要组建网络(广域网)需要从电信租用点对点或点对多点的"专线",例如某个单位总部在北京,在天津.广州.上海有分公司,如果这4个点要组成一个"大局域网",就需要租用3条专线,分别是从

UDP打洞原理

源:UDP打洞原理

Udp打洞原理和源代码。

所谓udp打洞就是指客户端A通过udp协议向服务器发送数据包,服务器收到后,获取数据包,并且 可获取客户端A地址和端口号.同样在客户端B发送给服务器udp数据包后,服务器同样在收到B发送过来 的数据包后获取B的地址和端口号,将A和B的地址与端口号分别发送给对方,这样双方可以继续用UDP协议 通信.这么做有什么用呢?因为对于一些应用或者需求,需要两个客户端临时做一些通信,而这种通信 不需要建立tcp就可以完成,所以才去udp打洞. 下面附上测试代码: 头文件 // udphole.cpp : 定义

简单说一下 TCP打洞和UDP打洞

1, TCP协议通信: 现在有两台电脑A和B.在 假设A的地址为 192.168.0.100 假设B的地址为 192.168.0.102 A想给B发送一个字符串Hello,  如果A,B之间采用TCP协议,那么B收到Hello的过程是怎样的呢? 首先建立连接(3次握手成功之后,A和B的链接才算成功),然后A在给B发送数据. 如果A,B不在一个局域网内,A,B通信就需要打洞了. 假设A通过路由器S1上网.B通过路由器S2上网. S1的外网IP:114.66.5.211          本地IP:

nRF24L01+组网方式及防撞(防冲突)机制的实战分享

利用多个nRF24L01+模块组网通信的实现方式 这里讨论的组网方式,不包含使用6个通道实现的多对1通信方式,因其只限于6个发送端,局限性很大,可以附加其他技术实现更好的组网,暂时这里不讨论.这里分享的是所有nRF24L01+模块都使用通道0,实现的数量远超过6个的组网方式. 经过实战总结,可以实用到落地项目的有轮询方式.时分方式.自主避让方式等几种常用的组网方式,下面会逐一讲解实现原理. 防撞(防冲突)机制的实现原理 其实无论使用那种方式,都会涉及到防止冲突,也就是防止该信道出现多个发射信号冲