【P2P学习(2)】P2P 通信,主要存在四种不同的网络模型

本文介绍P2P网络的四种模型,包括集中式、纯分布式、混合式和结构化模型,分析其优缺点。还阐述了中央索引、本地索引和分布式索引三种搜索策略。同时探讨了内网穿透问题,对比TCP和UDP协议的差异,介绍了它们的报文头格式、连接和断开过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

技术点

P2P 主要存在四种不同的网络模型,也代表着 P2P 技术的四个发展阶段

第一阶段:集中式

最简单的路由方式就是集中式,即存在一个中心节点保存了其他所有节点的索引信息,索引信息一般包括节点 IP 地址、端口、节点资源等。集中式路由的优点就是结构简单、实现容易。但缺点也很明显,由于中心节点需要存储所有节点的路由信息,当节点规模扩展时,就很容易出现性能瓶颈;而且也存在单点故障问题。

一般是有一个服务器,和一群客户端。各个客户端可以两两相互发送消息。各个客户端用IP地址和TCP/IP监听端口号进行标识。客户端,可执行注册和聊天过程;注册服务器,主要用于注册客户端和分发注册客户端信息。技术点:设计GUI、多线程和套接字编程

我们在【P2P学习(3)】中进行尝试。
https://github.com/xixihahag/p2pchating/tree/master
https://github.com/adomy/P2PChatRoom
https://github.com/ypingcn/P2PChat-Qt/tree/master
https://github.com/sreid8/Qt-Cpp-IM-Client/tree/master

第二阶段:纯分布式

在 P2P 节点之间建立随机网络,就是在一个新加入节点和 P2P 网络中的某个节点间随机建立连接通道,从而形成一个随机拓扑结构。新节点加入该网络的实现方法也有很多种,最简单的就是随机选择一个已经存在的节点并建立邻居关系。像比特币的话,则是使用 DNS 的方式来查询其他节点,DNS 一般是硬编码到代码里的,这些 DNS 服务器就会提供比特币节点的 IP 地址列表,从而新节点就可以找到其他节点建立连接通道。新节点与邻居节点建立连接后,还需要进行全网广播,让整个网络知道该节点的存在。全网广播的方式就是,该节点首先向邻居节点广播,邻居节点收到广播消息后,再继续向自己的邻居节点广播,以此类推,从而广播到整个网络。这种广播方法也称为泛洪机制。

纯分布式结构不存在集中式结构的单点性能瓶颈问题和单点故障问题,具有较好的可扩展性,但泛洪机制引入了新的问题,主要是可控性差的问题,包括两个较大的问题,一是容易形成泛洪循环,比如节点 A 发出的消息经过节点 B 到 节点 C,节点 C 再广播到节点 A,这就形成了一个循环;二是响应消息风暴问题,如果节点 A 想请求的资源被很多节点所拥有,那么在很短时间内,会出现大量节点同时向节点 A 发送响应消息,这就可能会让节点 A 瞬间瘫痪。

这可能就是全节点的CPU 占用高的原因,一直在响应。

我们在”https://www.kancloud.cn/digest/in-memory-computing/202165“ 定义这种是Unstructured Network。

非结构化的P2P网络并不给覆盖网络强加某种特定架构,而是结点间随机形成链接。最流行的P2P网络,像Bittorrent、eMule、Gnutella、Kazaa等都是非结构化的P2P协议。因为缺少结构,所以网络面对频繁的动态添加和删除结点时,依然能够健壮地运行。但也正因为缺少结构,所以当某个结点想要搜索某些数据或文件时,查询必须flood整个网络(详见搜索策略)

img

第三阶段:混合式

就是混合了集中式和分布式结构,网络中存在多个超级节点组成分布式网络,而每个超级节点则有多个普通节点与它组成局部的集中式网络。一个新的普通节点加入,则先选择一个超级节点进行通信,该超级节点再推送其他超级节点列表给新加入节点,加入节点再根据列表中的超级节点状态决定选择哪个具体的超级节点作为父节点。这种结构的泛洪广播就只是发生在超级节点之间,就可以避免大规模泛洪存在的问题。在实际应用中,混合式结构是相对灵活并且比较有效的组网架构,实现难度也相对较小,因此目前较多系统基于混合式结构进行开发实现。其实,比特币网络如今也是这种结构。

链接:https://blog.csdn.net/qq_40213907/article/details/127168928

第四阶段:结构化模型

它也是一种分布式网络结构,但与纯分布式结构不同。纯分布式网络就是一个随机网络,而结构化网络则将所有节点按照某种结构进行有序组织,比如形成一个环状网络或树状网络。而结构化网络的具体实现上,普遍都是基于 DHT(Distributed Hash Table,分布式哈希表) 算法思想。

DHT是在BitTorrent、IPFS网络中采用的P2P协议,DHT通过去中心化的方式存下了一个key-value表,key是文件的hash,value是文件所在节点的ip:port

每个节点任选一个hash值作为节点id
每个节点仅存hash值和自己id接近的key及其value
每个节点会维护自己所有peer的ip:port及其id
当检索一个key的时候,通过multi-hop search找到节点

DHT 主要想解决如何在分布式环境下快速而又准确地路由、定位数据的问题。具体的实现方案有 Chord、Pastry、CAN、Kademlia 等算法,其中 Kademlia 也是以太坊网络的实现算法,很多常用的 P2P 应用如 BitTorrent、电驴等也是使用 Kademlia。

DHT全称为分布式哈希表(Distributed Hash Table),是一种分布式存储方法。在不需要服务器的情况下,每个客户端负责一个小范围的路由,并负责存储一小部分数据,从而实现整个DHT网络的寻址和存储。使用支持该技术的BT下载软件,用户无需连上Tracker就可以下载,因为软件会在DHT网络中寻找下载同一文件的其他用户并与之通讯,开始下载任务。 有些软件(比特精灵)还会自动通过DHT搜索种子资源,构成种子市场。 另外,这里使用的DHT算法叫Kademlia(在eMule中也有使用,常把它叫做KAD,具体实现协议有所不同)。 这种技术好处十分明显,就是大大减轻了Tracker的负担(甚至不需要)。用户之间可以更快速建立通讯(特别是与Tracker连接不上的时候)。

在 P2P 网络中,可以抽象出两种空间:资源空间和节点空间。

资源空间就是所有节点保存的资源集合,节点空间就是所有节点的集合。对所有资源和节点分别进行编号,如把资源名称或内容用 Hash 函数变成一个数值(这也是 DHT 常用的一种方法),这样,每个资源就有对应的一个 ID,每个节点也有一个 ID,资源 ID 和节点 ID 之间建立起一种映射关系,比如,将资源 n 的所有索引信息存放到节点 n 上,那要搜索资源 n 时,只要找到节点 n 即可,从而就可以避免泛洪广播,能更快速而又准确地路由和定位数据。当然,在实际应用中,资源 ID 和节点 ID 之间是无法做到一一对应的,虽然如此,但是因为 ID 都是数字,就存在大小关系或偏序关系等,基于这些关系就能建立两者的映射关系。这就是 DHT 的核心思想。DHT 算法在资源编号和节点编号上就是使用了分布式哈希表,使得资源空间和节点空间的编号有唯一性、均匀分布式等较好的性质,能够适合结构化分布式网络的要求。

我们在”https://www.kancloud.cn/digest/in-memory-computing/202165“ 定义这种是structured Network。

结构化P2P网络将覆盖网络组织成某种特定的拓扑结构,并且它的协议能够保证:任何结点都能高效地搜索网络中的资源,即使资源是非常冷门的。常见的结构化P2P网络通常实现一致性哈希或者其变种分布式哈希表DHT分配文件的所有权到特定的结点。

img

插一个话题:BitTorrent协议。BitTorrent协议是架构于TCP/IP协议之上的一个P2P文件传输协议,处于TCP/IP结构的应用层。 BitTorrent协议本身也包含了很多具体的内容协议和扩展协议,并在不断扩充中。主要包含:

  • Torrent文件格式

  • Tracker-Peer协议

  • Peer-Peer 协议

BT客户端首先解析.torrent文件得到Tracker地址,然后连接Tracker服务器。

Torrent文件的作用是:

  • 声明了一个P2P网络的tracker服务器地址和端口

  • 声明了在该P2P网路上共享的一个文件的文件名、长度、区块数、各区块哈希值,唯一确定了一个文件

一个Peer在获取一个Torrent文件后,便可加入该P2P网络并获取该文件。

Tracker — Peer协议:基于C/S通信,这部分协议提供了加入和退出P2P的机制。特别是使得加入P2P的Peer能够获取目前的Peer列表。

Peer发送的Request格式

包含:

Peer的IP

port,Peer的本地监听端口

peer_id,由peer的ip和port组成

event,可能值包括started(用于请求加入网络),stoped(未使用),completed(用于请求退出网络)

Traker发送的Response格式

包含:

error_code,收到的请求有效时为0,非法请求则为1

message,包括started ACK和disconnect ACK两种

num-of-peer,请求前的peer数

请求前P2P网络中的peer的id、端口、地址

该Response仅会向刚刚发送请求的peer发送。这样已经加入的peer不会收到新peer加入的消息,然而由于我们的设计是peer1向peer2主动建立一个peer connection连接时,peer2会同样会(被动地)和peer1建立一个peer connection,因此之前已经加入网络的Peer依旧能够与新Peer建立连接。

Peer向tracker请求peer列表。收到后向这些peer中的指定个数目(例如4个)peer主动发起连接

根据Peer-Peer 协议,两者分别对方告知自己已经有的块,然后交换对方没有的数据。此时不需要其他服务器参与,分散了单个线路上的数据流量,因此减轻了服务器负担。

实现的例子:https://blog.csdn.net/pythonyanyan/article/details/128784572?

搜索策略

两种P2P网络可以使用不同的检索策略:中央索引、本地索引和分布式索引。分布式索引策略是对其他两种策略的权衡。

img

中央索引(中央服务器)

由一个中央服务器统一保存资源与结点的关系。这种方式搜索效率比较高,因为可以通过中央索引直接定位到目标结点,然而这种方式有时并不可行,特别是集群规模特别大时。

img

本地索引(flooding搜索)

每个结点保存自己的资源信息,当寻找不属于自己的资源时,会flooding整个网络进行寻找。这种flooding的方式会在网络中引起大量的traffic,并使每个结点都要处理查询请求而导致高CPU和内存使用率。并且flooding不保证通信质量,所以flooding也无法保证一定能够找到保存指定数据的那个结点。因为热数据在多个结点上存在,所以比较容易搜索成功。反之,冷数据只在很少的结点上存在,所以搜索很可能会以失败告终。并且搜索效率也很低,也容易导致安全问题。

img

分布式索引

为了高效地在网络中搜索,结点需要保存满足特定条件的邻居的列表,这使得整个网络在高频率的添加删除结点时,没有非结构化网络那样健壮。使用DHT路由的结构化P2P网络的著名软件有BitTorrent,Kad Network,以及各种研究项目Chord等。基于DHT的网络在网络计算系统中也有广泛的应用,它帮助实现高效的资源发现和应用程序调度等

典型的P2P网络使用的架构和搜索策略如下:

img

内网穿透

https://cnodejs.org/topic/5a6303479288dc8153287fe1

  • 选择udp协议
  • 节点之间的建立,连接和广播
  • 内网穿透,如何能让两个处在内网的节点,相互发现自己的存在,并且建立通信

首先解决的是内网穿透的问题,常见的底层协议tcp,udp,他们各自有优缺点,简单说明一下。 tcp:需要处理粘包问题,双工流通道,是可靠的链接。 udp: 每次发送的都是数据包,没有粘包问题,但是连接不可靠,只能传输少量数据

更加详细的请Google

这里选择udp协议,简单一些。

再下来是内网穿透,先说结论: 两个处于不同内部网络的节点,永远无法发现他们之间的相互存在,你就算是想顺着网线过去打他都不行。

所有的内网穿透原理无外乎需要一个有公网ip的中介服务器,包括虚拟货币像比特币之类的,所以首先要有一个创世节点

把服务部署要公网,那么其他所有的节点都能访问,通过中转服务器,能够使得两个节点可以建立连接

节点.png

在设计中,每个节点的功能都是一样的。如果需要加入到网络中,不一定跟创世节点链接

假设已存在的节点: 创世节点,A、B、C节点,此时有个D节点想要加入到网络。

那么D节点不一定非得链接到创世节点,可以链接到A、B、C中的任意一个节点,然后该节点再广播给其他节点说"Hey, 有个新人叫做D的加入了网络"。

这样所有人都知道,有个叫做D的节点存在,你可以和它通信,同时D节点和会同步已存在的节点。这样D节点也知道了其他节点的存在了。

这只是一些基本原理,离实际应用还差很多,有很多坑,比如D节点退出网络之后,要广播 “D节点退出网络了,把这个节点注销了吧,这波没他",还有消息加密,通信的双向验证(A节点想要B节点通信,但是不需要B节点的同意)

那如果A,B,C都是内网节点,说白了都需要通过创世节点进行打洞,通过创世节点中转才能通讯,假设还是D节点进来,是不是还通过创世节点打洞?按你的说法D不一定非链接到创世节点。那这个时候创世节点挂了,也不就是因为没人维护打洞导致整个p2p网络都挂了? 那如果节点多了,又如何选择性连接到就近节点,DHT表又是如何构建的呢?

创世节点可以有几个,就好像比特币的种子服务器,在代码写死了有固定几个DNS地址,帮助发现节点列表。 成功加入网络之后,就需要同步节点。同步节点完成之后,你才会知道哪个节点是离你最近的。这时候两个节点之间的通信就需要依赖两个节点各自的网络情况了。

https://github.com/axetroy/p2p-chat

内网穿透的因为NAT

https://blog.csdn.net/hzhsan/article/details/45038265

网络地址转换Network Address Translation后的一些理解整理,主要通过实例和图表的方式展示了NAT的工作原理和每个阶段的状态。本文的NAT是基本于Linux下的iptables命令实现。

1 概述

1.1 简介

NAT英文全称是“Network Address Translation”,中文意思是“网络地址转换”,它是一个IETF(Internet Engineering Task Force, Internet工程任务组)标准,允许一个整体机构以一个公用IP(Internet Protocol)地址出现在Internet上。顾名思义,它是一种把内部私有网络地址(IP地址)翻译成合法网络IP地址的技术。因此我们可以认为,NAT在一定程度上,能够有效的解决公网地址不足的问题。

1.2 分类

NAT有三种类型:静态NAT(Static NAT)、动态地址NAT(Pooled NAT)、网络地址端口转换NAPT(Port-Level NAT)。

其中,网络地址端口转换NAPT(Network Address Port Translation)则是把内部地址映射到外部网络的一个IP地址的不同端口上。它可以将中小型的网络隐藏在一个合法的IP地址后面。NAPT与 动态地址NAT不同,它将内部连接映射到外部网络中的一个单独的IP地址上,同时在该地址上加上一个由NAT设备选定的端口号。

NAPT是使用最普遍的一种转换方式,在HomeGW中也主要使用该方式。它又包含两种转换方式:SNAT和DNAT。

(1)源NAT(Source NAT,SNAT):修改数据包的源地址。源NAT改变第一个数据包的来源地址,它永远会在数据包发送到网络之前完成,数据包伪装就是一具SNAT的例子。

(2)目的NAT(Destination NAT,DNAT):修改数据包的目的地址。Destination NAT刚好与SNAT相反,它是改变第一个数据懈的目的地地址,如平衡负载、端口转发和透明代理就是属于DNAT。

img

1.3 应用

NAT主要可以实现以下几个功能:数据包伪装、平衡负载、端口转发和透明代理。

数据伪装: 可以将内网数据包中的地址信息更改成统一的对外地址信息,不让内网主机直接暴露在因特网上,保证内网主机的安全。同时,该功能也常用来实现共享上网。

端口转发: 当内网主机对外提供服务时,由于使用的是内部私有IP地址,外网无法直接访问。因此,需要在网关上进行端口转发,将特定服务的数据包转发给内网主机。

负载平衡: 目的地址转换NAT可以重定向一些服务器的连接到其他随机选定的服务器。(不是很明白)

失效终结: 目的地址转换NAT可以用来提供高可靠性的服务。如果一个系统有一台通过路由器访问的关键服务器,一旦路由器检测到该服务器当机,它可以使用目的地址转换NAT透明的把连接转移到一个备份服务器上。(如何转移的?)

透明代理: NAT可以把连接到因特网的HTTP连接重定向到一个指定的HTTP代理服务器以缓存数据和过滤请求。一些因特网服务提供商就使用这种技术来减少带宽的使用而不用让他们的客户配置他们的浏览器支持代理连接。(如何重定向的?)

2 原理

2.1 地址转换

NAT的基本工作原理是,当私有网主机和公共网主机通信的IP包经过NAT网关时,将IP包中的源IP或目的IP在私有IP和NAT的公共IP之间进行转换。

如下图所示,NAT网关有2个网络端口,其中公共网络端口的IP地址是统一分配的公共 IP,为202.20.65.5;私有网络端口的IP地址是保留地址,为192.168.1.1。私有网中的主机192.168.1.2向公共网中的主机202.20.65.4发送了1个IP包(Dst=202.20.65.4,Src=192.168.1.2)。

img

当IP包经过NAT网关时,NAT Gateway会将IP包的源IP转换为NAT Gateway的公共IP并转发到公共网,此时IP包(Dst=202.20.65.4,Src=202.20.65.5)中已经不含任何私有网IP的信息。由于IP包的源IP已经被转换成NAT Gateway的公共IP,Web Server发出的响应IP包(Dst= 202.20.65.5,Src=202.20.65.4)将被发送到NAT Gateway。

这时,NAT Gateway会将IP包的目的IP转换成私有网中主机的IP,然后将IP包(Des=192.168.1.2,Src=202.20.65.4)转发到私有网。对于通信双方而言,这种地址的转换过程是完全透明的。转换示意图如下。

img

如果内网主机发出的请求包未经过NAT,那么当Web Server收到请求包,回复的响应包中的目的地址就是私网IP地址,在Internet上无法正确送达,导致连接失败。

2.2 连接跟踪

在上述过程中,NAT Gateway在收到响应包后,就需要判断将数据包转发给谁。此时如果子网内仅有少量客户机,可以用静态NAT手工指定;但如果内网有多台客户机,并且各自访问不同网站,这时候就需要连接跟踪(connection track)。如下图所示:

img

在NAT Gateway收到客户机发来的请求包后,做源地址转换,并且将该连接记录保存下来,当NAT Gateway收到服务器来的响应包后,查找Track Table,确定转发目标,做目的地址转换,转发给客户机。

2.3 端口转换

以上述客户机访问服务器为例,当仅有一台客户机访问服务器时,NAT Gateway只须更改数据包的源IP或目的IP即可正常通讯。但是如果Client A和Client B同时访问Web Server,那么当NAT Gateway收到响应包的时候,就无法判断将数据包转发给哪台客户机,如下图所示。

img

此时,NAT Gateway会在Connection Track中加入端口信息加以区分。如果两客户机访问同一服务器的源端口不同,那么在Track Table里加入端口信息即可区分,如果源端口正好相同,那么在时行SNAT和DNAT的同时对源端口也要做相应的转换,如下图所示。(这里的理解灰常重要)

img

TCP穿越NAT的问题必须解决

实现方式:

静态转换、动态转换、端口多路复用。

  1. 静态转换:是指将内部网络的私有IP地址转换为公有IP地址,IP地址对是一对一的,是一成不变的。通过静态配置,把一个固定的私网IP地址和端口关联到一个公网地址和端口,这种方式适用于在NAT网关上把一个知名服务(如HTTP)映射到一个内部主机上。
  2. 动态转换:是指将内部网络的私有IP地址转换为公用IP地址时,IP地址对是不确定的,而是随机的,所有被授权访问Internet的私有IP地址可随机转换为任何指定的合法IP地址。也就是说,只要指定哪些内部地址可以进行转换,以及用哪些合法地址作为外部地址时,就可以进行动态转换。
  3. 端口多路复用:是指改变外出数据包的源端口并进行端口转换,即端口地址转换(Port Address
    Translation,PAT)。采用端口多路复用方式,内部网络的所有主机均可共享一个合法外部IP地址实现对Internet的访问,从而最大限度地节约IP地址资源。同时,又可隐藏网络内部的所有主机,避免来自Internet的攻击。因此,目前网络中应用最多的就是端口多路复用方式。

分类:

NAT设备的类型对于TCP穿越NAT,有着十分重要的影响,根据端口映射方式,NAT可分为如下4类,前3种NAT类型可统称为cone类型。下面是NAT的几种类型:

  1. 全克隆( Full Clone) :NAT把所有来自相同内部IP地址和端口的请求映射到相同的外部IP地址和端口。任何一个外部主机均可通过该映射发送IP包到该内部主机。
  2. 限制性克隆(Restricted Clone) :NAT把所有来自相同内部IP地址和端口的请求映射到相同的外部IP地址和端口。但是,只有当内部主机先给IP地址为X的外部主机发送IP包,该外部主机才能向该内部主机发送IP包。
  3. 端口限制性克隆( Port Restricted Clone):端口限制性克隆与限制性克隆类似,只是多了端口号的限制,即只有内部主机先向IP地址为X,端口号为P的外部主机发送1个IP包,该外部主机才能够把源端口号为P的IP包发送给该内部主机。
  4. 对称式NAT ( Symmetric NAT):这种类型的NAT与上述3种类型的不同,在于当同一内部主机使用相同的端口与不同地址的外部主机进行通信时,NAT对该内部主机的映射会有所不同。对称式NAT不保证所有会话中的私有地址和公开IP之间绑定的一致性。相反,它为每个新的会话分配一个新的端口号。

NAT打洞技术:

NAT技术虽然在一定程度上解决了IPv4地址短缺的问题,在构建防火墙、保证网络安全方面都发挥了一定的作用,却破坏了端到端的网络通信。NAT阻碍主机进行P2P通信的主要原因是NAT不允许外网主机主动访问内网主机,因为NAT设备上没有相关转发表项,要在NAT网络环境中进行有效的P2P通信,就必须寻找相应的解决方案——NAT穿越打洞。下面分各种NAT场景(如图2)来说明UDP打洞的过程:

在这里插入图片描述

假设现在有A和B通信双方,同时为了便于描述打洞过程,假定图2中的NAT类型均为Full Cone NAT:

  1. A和B都处于公网下,无需打洞,A和B可直接P2P直连。
  2. A处于公网,B在内网。若A去连B,由于B没有向A发送过数据,A的数据包会被B的NAT1丢弃,所以即使A知道了B通过NAT1转换后的地址和端口,也是无法连接成功的。但是由于A在公网下,所以反过来B可以连接A,P2P通信成功。
  3. A和B都处于内网,分属不同的内网,它们彼此的内网地址在外网中是没有路由的,所以发往各自内网地址的UDP数据包会发送到错误的主机或者根本不存在的主机上。由于双方都不知道对方的公网IP和端口,就会无从下手,所以要在A和B之间架设一台服务器S来为它们牵线,而且S是处在公网,以保证A和B都能连接到S。A和B登录时都首先连接S,S就会知道A和B经过NAT后的IP和端口,当A想要连接B时,就向S发出请求,S会把B经过NAT后的IP和端口告诉A,同时S向B发送A经过NAT后的IP和端口,并要求B发送数据给A,B发送数据到达A时会被A的NAT抛弃(不同的路由器会有不同的结果,有些路由器在这个操作就能建立连接,大多数路由器对于不请自到的SYN请求包直接丢弃而导致connect失败),但是B的NAT会有B发送数据到A的记录,这时A再向B发送数据时就会被B的NAT放行,因为B曾经向A的外网IP和端口发送过数据。A向B的外网地址发送消息的过程就是“打洞”的过程,一旦A与B都向对方的外网地址发送了数据包,就打开了A与B之间的“洞”,一旦应用程序确认已经可以通过往对方的外网地址发送数据包的方式让数据包到达NAT后面的目的应用程序,程序会自动停止继续发送用于“打洞”的数据包,转而开始真正的P2P数据传输。这个过程可借助于网上的一个形象比喻来理解(见图3)。

在这里插入图片描述

NAT1和NAT2是由ISP(Internet Service
Provider)提供的NAT设备,提供将多个用户节点映射到有限的几个公网IP的服务。NAT3作为NAT1的内网节点将把用户的家庭网络或内部网络接入NAT1的内网,然后用户的内部网络就可以经由NAT1访问公网了(NAT4同理)。从这种拓扑结构上来看,只有服务器S与NAT1、NAT2是真正拥有公网可路由IP地址的设备,而NAT3和NAT4所使用的公网IP地址,实际上是由ISP服务提供商设定的(相对于NAT1和NAT2而言)内网地址(这个由ISP提供的内网地址相对于NAT1和NAT2被称之为“伪”公网地址)。现在假定A和B希望通过UDP“打洞”完成P2P直连。最优化的路由策略是A向B的“伪公网”IP上发送数据包。由于从服务器S的角度只能观察到真正的公网地址,也就是NAT3、NAT4分别通过NAT1、NAT2转换的外网地址,非常不幸的是A与B是无法通过服务器S知道这些“伪”公网的地址,而且即使客户端A和B通过某种手段可以得到NAT3和NAT4的“伪”公网地址,我们仍然不建议采用上述的“最优化”的打洞方式,这是因为这些地址是由ISP服务提供商提供的,或许会存在与客户端本身所在的内网地址重复的可能性,这样就会导致打洞数据包无法发出的问题。因此客户端别无选择,只能使用由服务器S观察到的A,B的公网地址进行“打洞”操作,打洞过程与(3)类似。

A和B位于同一个NAT设备后面,并且处于同一局域网中,发出的数据包不需要路由,可进行速度较快的常规P2P通信。另外,A和B发往对方公网地址的UDP数据包不一定会被对方收到,这取决于当前的NAT设备是否支持不同端口之间的UDP数据包传输(即Hairpin转换),就算支持,应用程序也应该优先选择上述常规的P2P直连,否则势必会造成数据包无谓地经过NAT设备,这是一种对资源的浪费。

由于A和B不在一个内网中,所以相对于(5)而言,就不能不经过NAT让A和B直接相连,这样情况下就需要NAT1支持Hairpin转换,虽然目前也有很多NAT设备不支持类似这样的“Hairpin转换”,但是已经有越来越多的NAT设备商开始加入对该转换的支持中来。

TCP和UDP

TCP/IP协议族为运输层指明了两个协议:TCP和UDP,它们都是作为应同程序和网络操作的中介物。

**TCP协议全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC793定义。**TCP是面向连接的、可靠的流协议。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。

**UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。**在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。

两者的区别:

1、TCP是面向连接的,UDP是面向无连接的;

2、UDP程序结构较简单;

3、TCP是面向字节流的,UDP是基于数据报的;

4、TCP保证数据正确性,UDP可能丢包;

5、TCP保证数据顺序,UDP不保证。

内网穿透UDP和TCP的差异

这里选择udp协议,简单一些。

路由器负责转发分组,但不知道转发的是udp报文还是tcp报文

都可以的。
在运输层这样的数据单元就叫做TCP报文段或UDP用户数据报。但在不需要十分严格和不致弄混的情况下,有时也都可笼统地采用分组这一名词。

1、TCP报文头格式TCP协议是传输层协议,它基于IP协议做可靠的数据传输。所以TCP报文在网络中传输时是存放在IP报文的Data字段中的,报文格式如下:帧头Data(IP报文)F

1、TCP报文头格式

TCP协议是传输层协议,它基于IP协议做可靠的数据传输。所以TCP报文在网络中传输时是存放在IP报文的Data字段中的,报文格式如下:

帧头Data(IP报文)FCSIP头Data(TCP报文)TCP头Data

TCP头字段较多,这里将连续的字段做换行处理。

Source PortDestination PortSequence NumberAcknowledge NumberHeader length16位16位32位32位4位ResvURGACKPSHRSTSYNFINWindowChecksumUrgent PointerOptions6位1位1位1位1位1位1位16位16位16位0-40字节

Source Port:源端口号

Destination Port:目的端口号

Sequence Number:首字节序号。TCP报文也是分段传输的,TCP的数据流为每一个字节都分配了序号,报文中记录其首字节的序号。如前一个报文段的首字节序号为100,而报文总长度为300字节,则下一报文段的首字节序号为400。

Acknowledge Number:确认序号。记录了下一报文段的首字节序号。

Header length:报文头长度。因Options字段长度可变,所以TCP报头的长度可变。

Resv:保留字段。供往后应用。

URG:紧急标志位。当URG=1时,表明此报文应尽快传送,而不要按本来的队列次序传送。

ACK:确认标志位。只有当ACK=1时,前面的确认序号字段才有意义。

PSH:急迫标志位。当PSH=1时,表明接收到此报文的主机应立即将此报文段传送至应用层,而不要等所有报文段都到齐了再向上交付

RST:复位标志位。当RST=1时,表明出现了严重的错误,接收到此报文的主机应与源主机断开并重建连接。还可以用来拒绝一个非法的报文段或拒绝打开一个连接。

SYN:同步标志位。在建立连接时使用,SYN=1表示这是一个连接请求或连接接受报文。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,应返回一个SYN=1和ACK=1的报文段。

FIN:终止标志位。用来释放一个连接,当FIN=1时,表明需要发送的报文段已发完,并要求释放传输连接。

Window:窗口字段。用来告知对方自己缓存区的大小,目标主机通过这个字段来确定返回给源主机的数据量最大值,也就是一个报文段的最大长度。

Checksum:校验和字段。校验范围包括首部和数据,由发送方填写接收方验证。

Urgent Pointer:紧急指针。它指出报文中紧急数据最后一个字节的序号。因为紧急数据有可能被分段发送,所以需要指明紧急数据的最后一字节,接收方接收完全后才能处理。只有当紧急标志位URG=1时此字段才有效。

Options:可选字段。TCP报文提供此字段用作功能扩展,包括窗口扩大和时间戳选项,后面会详细讲到。

2、TCP连接(三次握手)

三次握手中,使用了SYN标志位表明这是一个连接请求或连接接受报文;使用了seq(Sequence Number)字段和ack(Acknowledge Number)字段,用以校验报文的连续性;被连接主机使用ACK标志位表明同意连接。这里一般层连接的发起方为client端,被连接方成为server端,连接过程分为三次如下图所示。

技术分享

第一次握手(SYN_SENT):Client向Server端发送一个请求报文,报文中SYN=1、Sequence Number=一个随机值J,Client进入SYN_SENT状态,等待Server确认。

第二次握手(SYN_RCVD):Server端收到该请求报文后,向Client返回一个确认报文,报文中SYN=1、ACK=1、Acknowledge Number=J+1、Sequence Number=一个随机值K,Server进入SYN_RCVD状态,等待Client端的再次确认。

第三次握手(ESTABLISHED):Client收到该确认报文后,认可连接已建立,于是向Server端发送一个连接建立的确认报文,报文中ACK=1、Acknowledge Number=K+1。Server端收到该报文后知道Client端已认可了本次连接,于是Client和Server就可以开始传输数据了。

3、TCP断开(四次挥手)

四次挥手中使用FIN标志位表明这是一个申请连接释放的报文;使用seq(Sequence Number)字段和ack(Acknowledge Number)字段,用以校验报文的连续性;被断开主机使用ACK标志位表明同意断开连接。因为TCP连接是全双工的,所以每个方向都必须单独进行关闭,各方向关闭均需两次共四次如下图所示。

技术分享

第一次挥手(FIN_WAIT_1):Client发送一个关闭连接的请求报文,报文中FIN=1、Sequence Number=一个随机值M,Client进入FIN_WAIT_1状态,等待Server确认。

第二次挥手(CLOSE_WAIT):Server端收到该关闭的请求报文后,向Client返回一个确认报文,报文中ACK=1、Acknowledge Number=M+1,Server进入CLOSE_WAIT状态。Client端收到确认报文后就断开与Server的连接。

第三次挥手(LAST_ACK):Server端发送一个关闭连接的请求报文,报文中FIN=1、Sequence Number=一个随机值N,Server进入LAST_ACK状态,等待Client确认。

第四次挥手(TIME_WAIT):Client收到该关闭的请求报文后,向Server返回一个确认报文,报文中ACK=1、Acknowledge Number=N+1,Client进入TIME_WAIT状态。Server端收到确认报文后就断开与Client的连接,至此双向的连接都已关闭。

4、UDP报文头格式

UDP与TCP类似都是传输层协议,也是基于IP协议的,所以在传输时也是存放于IP报文的Data字段中。与TCP不同的是它是一种无连接的传输协议,它不提供数据包分组、组装和不能对数据包进行排序,也就是当报文发送后,是无法得知其是否安全完整的到达。

帧头Data(IP报文)FCSIP头Data(UDP报文)UDP头DataSource PortDestination PortLengthChecksum8位8位8位8位

Source Port:源端口号。

Destination Port:目的端口号。

Length:总长度。报文的长度。

Checksum:校验和。接收方用于校验传输是否正确。

【为什么TCP关闭是四次挥手】由于TCP连接是全双工的。

也就是说Clinet和Server端是可以同时收发的,在进行关闭时,若Client端关闭了Client到Server端的连接,但此时Server端可能还有数据没有发完,所以需要等到Server端也发完数据后,Server主动向Client发起关闭请求。可以这样理解,TCP连接后,Server和Client各自发送自己的数据,发送完毕后各自断开连接。应当将Client和Server连接断开看作是两次不连续的事件,实际上也会出现Server端先断开连接或Client和Server同时断开连接,所以需要四次握手。

【TCP可选字段】可选字段的第一个字节称为kind,说明选项的类型。默认kind为空,即不启用Options字段。

kind=0:禁用此字段。

kind=1:启用窗口扩大选项。此选项使TCP的窗口定义从原来的16位扩大到32位,就是说发送方的缓存区能支持从最大能支持65535字节到最大能支持4294967295字节。

kind=2:启用时间戳选项。此选项使发送方在每个报文段中放置一个时间戳,接收方会在确认收到的报文中带上这个数值,这样发送方就能计算报文段在网络中的往返延迟。

kind=3:启用窗口扩大和时间戳选项。

【TCP与UDP的区别】UDP和TCP协议的主要区别是两者在如何实现信息的可靠传递方面不同。

TCP协议中包含了专门的传递保证机制,当数据接收方收到发送方传来的信息时,会自动向发送方发出确认消息;发送方只有在接收到该确认消息之后才继续传送其它信息,否则将一直等待直到收到确认信息为止。与TCP不同,UDP协议并不提供数据传送的保证机制。如果在从发送方到接收方的传递过程中出现数据报的丢失,协议本身并不能做出任何检测或提示。而且在网络拥堵时可能出现先发出的数据后到达的情况,也就是接收方收到数据的顺序可能与发送方不一致。因此,通常人们把UDP协议称为不可靠的传输协议。

【UDP应用】既然UDP是一种不可靠的网络协议,那么还有什么使用价值或必要呢?

其实不然,在有些情况下UDP协议可能会变得非常有用。因为UDP具有TCP所望尘莫及的速度优势。虽然TCP协议中植入了各种安全保障功能,但是在实际执行的过程中会占用大量的系统开销,无疑使速度受到严重的影响。反观UDP由于排除了信息可靠传递机制,将安全和排序等功能移交给上层应用来完成,极大降低了执行时间,使速度得到了保证。同时UDP也是分发信息的一个理想协议。例如,在屏幕上报告股票市场、在屏幕上显示航空信息等等。UDP也用在路由信息协议RIP(Routing Information Protocol)中修改路由表。在这些应用场合下,如果有一个消息丢失,在几秒之后另一个新的消息就会替换它。

【TCP与UDP的端口号】TCP与UDP协议使用端口号为不同的应用保留其各自的数据传输通道。

UDP和TCP协议正是采用这一机制实现对同一时刻内多项应用同时发送和接收数据的支持。数据发送一方(可以是客户端或服务器端)将UDP数据包通过源端口发送出去,而数据接收一方则通过目标端口接收数据。有的网络应用只能使用预先为其预留或注册的静态端口;而另外一些网络应用则可以使用未被注册的动态端口。因为UDP报头使用两个字节存放端口号,所以端口号的有效范围是从0到65535。一般来说,大于49151的端口号都代表动态端口。

实际上TCP和UDP是基础的传输协议,基于这二者实现的应用层协议可能有固定的端口号,如ftp服务进行TCP通讯时默认使用21号端口,有些应用也可能临时申请一个端口,通信完成后就释放该端口,由计算机统一管理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值