去中心化的网络设计 — P2P的实现

本文深入浅出地介绍了去中心化网络设计的基础——网络穿透,特别是P2P技术。通过实例详细解释了不同类型的NAT(完全锥形、限制锥形、端口限制锥形和对称NAT)及其在网络穿透中的影响,并提供了实现穿透的步骤。最后,文章还探讨了如何检测和应对不同类型的NAT,以实现P2P连接。
摘要由CSDN通过智能技术生成

随着区块链的越来越火,去中心化的网络设计再次被拿到技术人员面前。在这里我使用非常通俗的语言,帮大家来理解去中心化的网络设计的基础—网络穿透。再使用代码来实现穿透。如果阐述不到位的地方,欢迎大家抛砖。

 

    在有中心化服务器的网络中,客户端,服务器,网关构成网络拓扑图。如下图1所示:由于后续出现的名词概念很多,先约法三章,在这里统一一下称呼:所有的终端机器成为客户端,不同客户端使用大写字母区分(A,B,C,…);客户端上面运行的应用程序统一称为客户程序,不同的应用程序使用不数字区分(1,2,3,…)。作为服务器的物理机称为服务器,而服务器上运行的程序称为服务程序,后文中每一个拓扑组件都只有一个IP地址。为客户端提供公网IP服务的组件称为网关。

wKioL1nGkdbRpj8jAAB4putmiMQ017.png-wh_50

图1 中心化服务器的网络拓扑图


从网关映射到客户端中的网络结构,这里需要引入一个NAT的概念。什么NAT呢?中文名叫网络地址转换,习惯称为网络地址映射。为什么需要网络地址映射呢?:需要说到IPV4网络地址已经用完,全部使用IPV6又会造成很多只支持IPV4的终端设备无法正常使用,所以网络地址映射应运而生,忍辱负重。才会有我们现在所谓的网络穿透的出现。到底怎么映射的?如图2网络地址映射所示。客户程序使用192.168.0.234:7890发送数据,通过网关的网络地址映射在公网被转换为112.93.116.102:6834,被互联网上的大家所认知。此时在公网上使用客户程序的ip与端口被112.93.116.102:6834代替。在这里大家应该明白了NAT是何许物种了。

wKiom1nGkg_Q03LBAABXmGw3UOQ516.png-wh_50

图2 网络地址映射

为了保持新手福音,业界良心的态度。什么是穿透?因为NAT是客户程序发起的,网络为了保持通讯新建的一个临时牌照,随时可能被收回,而且重新发起后的牌照不一样。从而外界及时知道了这个临时牌照也没有用。所以需要通过穿透在网关上面打个洞,来为外界进行服务。那NAT与穿透有什么关系呢?正因为有了NAT才需要穿透,如果是IPV6每个客户端一个IP地址,那就不需要直接可以找到客户端了。

   

网络地址映射

 

    由于网关的安全性要求不一致,就出现四种不同的NAT方式。分别进行阐述:

第一种完全锥形NAT,英文名叫Full Cone NAT。如图3完全锥形NAT所示,客户程序(192.168.0.234:7890)与服务器A(13.44.178.98:9800)通信,通过网关的地址转换产生的临时牌照的公网地址(112.93.116.102:6834),服务器B(157.78.13.156:23456)发送数据到公网地址(112.93.116.102:6834),如果客户程序(192.168.0.234:7890)能够收到服务器B(157.78.13.156:23456)发送的数据,这种NAT映射关系为完全锥形NAT;

wKiom1nGkhGRaHQkAABqja7Jt88832.png-wh_50



图3 完全锥形NAT


第二种限制锥形NAT,英文名叫RestrictedCone NAT。在图3 完全锥形NAT中,如果客户程序(192.168.0.234:7890)不能收到服务器B(157.78.13.156:23456)发送的数据,这种NAT映射关系为限制型锥形NAT。

 

第三种端口限制锥形NAT,英文名叫Port RestrictedCone NAT。客户程序(192.168.0.234:7890)发送数据给服务程序(13.44.178.98:9800),网关通过网络地址转换产生的地址(112.93.116.102:6834),同样的服务器内的另一个服务程序(13.44.178.178:9801)发送数据给网关(112.93.116.102:6834)地址,如果客户程序(192.168.0.234:7890)能够收到,则为限制锥形NAT,如果客户程序(192.168.0.234:7890)不能收到,则为端口限制锥形NAT。

 

    对于所有的锥型NAT,客户程序(192.168.0.234:7890)对外发送的数据时,网关地址转换的地址都是一样的为(112.93.116.102:6834),那为什么在图4 限制型锥形NAT中,客户程序不能收到服务程序B(13.44.178.98:9801)的数据呢?因为在网关中没有发生过客户程序(192.168.0.234:7890)给服务程序B(13.44.178.98:9801),故服务程序(13.44.178.98:9801)直接发送给网关(112.93.116.102:6834),则被网关所丢弃。

wKiom1nGkhCjX6CuAABYmhK5jE4855.png-wh_50

图4 限制型锥形NAT


第四种对称NAT,英文,名叫Symmetric NAT。如图5对称NAT所示,客户程序(192.168.0.234:7890)发送数据给两个不同服务器(13.44.178.98:9800)和(157.78.13.156:23456)时,网关会进行不同的网络地址映射产生(112.93.116.102:6834)和(112.93.116.102:6835)。这是对于整个NAT网络发送数据出去的过程,而接收数据与端口限制锥形NAT一致。

wKiom1nGkhCzHbmVAABstzph6sM258.png-wh_50


图5 对称NAT


本节介绍三种锥形NAT和对称NAT的概念,相信到此你还是不知道NAT类型与怎么穿透网关友什么关系。

 

穿透剖析

 

    怎么穿透网关来实现去中心化,如图6穿透网络NAT拓扑图所示

wKiom1nGkhDyDwdxAAB4Jpb2pAA676.png-wh_50



在理想的情况下,在NAT 1中客户程序(192.168.0.234:7890)知道NAT 2中客户程序(192.168.2.168:2786)的网络映射地址(157.123.80.165:6954),并给网络映射地址(157.123.80.165:6954)发送数据,并且客户程序(192.168.2.168:2786)能够收到数据;而NAT 2中客户程序(192.168.2.168:2786)也知道NAT 1中客户程序的网络映射地址,并给其网络映射地址(112.93.116.102:6834)发送数据,并且也能收到数据。此时对于服务器而言,就已经没有起到数据中转的作用,此时客户程序(192.168.0.234:7890)与客户程序(192.168.2.168:2786)能够互相收发数据,服务程序(13.44.178.98:9800)已经没有作用,对于客户端程序来说,已经实现了去中心化。

 

    这只是在理论情况,现在具体实现步骤以及结合四种NAT类型来分析一下。

第一种:NAT 1为完全锥形NAT,NAT 2为任何一种NAT模式,如图7 完全锥形NAT的穿透,绿色字体的顺序。

  1. 客户程序(192.168.0.234:7890)先发送一个连接请求给服务程序,通知服务程序,需要连接客户程序(192.168.2.168:2786)。

  2. 服务程序收到连接请求后,发送给notify消息给客户程序(192.168.2.168:2786),通知客户程序(192.168.2.168:2786),发送p2p连接请求给网关(112.93.116.102:6834)。

  3. 客户程序(192.168.2.168:2786)发送p2p连接请求给网关(112.93.116.102:6834),由于NAT1为完全锥形NAT,所以客户程序(192.168.0.234:7890)能够收到客户程序(192.168.2.168:2786)的请求。

  4. 客户程序(192.168.0.234:7890)收到p2p连接请求后,从请求数据中解析出请求发送者客户程序(192.168.2.168:2786)的IP地址与端口,并立即返回确认消息。此时双方进入P2P的穿透模式。

然而在这里有一点需要注意:NAT2为对称NAT的时候,在3步骤的时候,网关会新生成另一个端口,IP地址不变,用来与NAT1中的网络进行通信;在4步骤的时候,客户程序(192.168.0.234:7890)返回数据的地址,就是新生成的端口。

wKioL1nGkdejVvCGAACSBtVxl_E171.png-wh_50


图7 完全锥形NAT的穿透


第二种:NAT 1为限制锥形NAT或者端口限制锥形NAT(两个锥形NAT模式是一样的,就不分开解释了),NAT 2为锥形NAT。如图8 限制锥形NAT的穿透所示

  1. 客户程序(192.168.0.234:7890)发送连接请求给服务程序,通知服务程序,需要连接客户程序(192.168.2.168:2786)。

  2. 服务程序收到连接请求后,发送给notify消息给客户程序(192.168.2.168:2786),通知客户程序(192.168.2.168:2786),发送p2p连接请求给网关(112.93.116.102:6834)。

  3. 客户程序(192.168.2.168:2786)发送p2p连接请求给网关(112.93.116.102:6834),由于NAT1为限制锥形NAT,所以客户程序(192.168.0.234:7890)收不到发送的p2p连接请求,此步骤最终的是在NAT2的网关(157.123.80.165:6954)新生成一条NAT目的地址的记录。与后续6步骤作为配合。

  4. 客户程序(192.168.2.168:2786)提醒服务程序通知客户程序(192.168.0.234:7890),

  5. 服务程序马上通知客户程序(192.168.0.234:7890)发送请求给NAT2的网关(157.123.80.165:6954)。

  6. 客户程序(192.168.0.234:7890)发送p2p连接请求给网关(157.123.80.165:6954),由于刚刚3步骤发出了请求,此时网关会认为是3步骤返回的响应,所以能够p2p连接请求发送给客户程序(192.168.2.168:2786)

  7. 客户程序(192.168.2.168:2786)收到p2p连接请求后,立即返回确认消息给p2p连接请求包解析出来的IP地址与端口,此确认消息能够顺利到底客户程序(192.168.0.234:7890),到此网关已经穿透,P2P已经建立。


wKioL1nGkdiAKZ-cAAChO9RNALs726.png-wh_50

图8 限制锥形NAT的穿透


第三种:NAT1为限制锥形NAT,NAT2为对称NAT。如图8限制锥形NAT的穿透所示。

在步骤3和步骤6与NAT2为限制锥形NAT有些差异,其余步骤流程一致。

步骤3:客户程序(192.168.2.168:2786)发送p2p连接请求给网关(112.93.116.102:6834),由于NAT2为对称网络,此时会重新生成一个端口用于对网关(112.93.116.102:6834)通信。新生成的端口没有办法能够准确的知道。只能进行猜测。

步骤6:发送数据给网关(157.123.80.165:猜测端口)。

在这里提供一种思路来提高测猜的准确度,把服务程序使用两个端口(之前9800,新加一个9801),由于网关NAT分配端口是顺序的,在步骤4发送请求给服务程序(9801端口),因为步骤3与步骤4相隔时间短,步骤3在网关(157.123.80.165)所生成的新端口比步骤4的端口小。从而来提高猜测的准确度。

    相信已经对穿透的具体步骤有明确的概念,怎么准确的判断当前NAT的类型?

 

NAT分类

其实在网络地址映射概念已经有介绍分类,在这里使用更加计算机化语言描述。

第一种,检测当前客户程序的网关是否为完全锥形NAT,如图9检测完全锥形NAT所示

wKioL1nGkdeyikmBAABxHWZavbg981.png-wh_50


图9 检测完全锥形NAT


首先检测Udp的可用性,客户程序(192.168.0.234:7890)使用一个300ms定时器发送Udp请求数据包给服务器A。等待服务器A返回确认数据。如果多次发送请求并未得到服务器的确认数据,则认为Udp不能信息,则推出整个检测过程。如果收到确认数据,同样使用定时器再发送另一种请求数据要求服务器B发送数据给网关(112.93.116.102:6834),如果收到服务器B的数据,则认为是完全锥形网络。如果没有收到则进行限制锥形NAT。

 

第二种,检测限制锥形网络,如图10所示。

wKioL1nGkdeQXaSUAABtIOVt-Ik423.png-wh_50

图10 检测限制锥形NAT

 

客户程序(192.168.0.234:7890)定时发送数据包给服务程序A,并要求服务程序从另一个端口发送数据包给网关(112.93.116.102:6834)。若客户程序(192.168.0.234:7890)收到回应,则该NAT为限制锥形NAT。若多次操作没有回应,则进行对称NAT检测。

 

第三种,检测当前客户程序的网关是否为对称NAT,如图9所示

客户程序(192.168.0.234:7890)给服务器A(13.44.178.98:9800)与服务器B(157.78.13.156:23456)发送数据包,对比两个服务器收到客户程序的()IP地址与端口是否一致。如果不一致则是对称网络。如果一致则该网络为端口限制锥形NAT。




以下为实现了完全锥形网络的穿透代码


udp.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
/*
  * Author: WangBoJing
  * email: 1989wangbojing@gmail.com 
  * github: https://github.com/wangbojing
  */
 
#ifndef __UDP_H__
#define __UDP_H__
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <time.h>
 
 
typedef  unsigned  int  U32;
typedef  unsigned  short  U16;
typedef  unsigned  char  U8;
typedef  volatile  long  UATOMIC;
typedef  void
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值