互联网点对点通信(P2P)

 摘自: http://www.cnblogs.com/zhili/archive/2012/09/14/p2p_pnpr.htmlhtml

 很遗憾,目前看了下代码,我测试只是作到了本地p2p.git

 

 

[C# 网络编程系列]专题八:P2P编程

 

引言:程序员

前面的介绍专题中有朋友向我留言说介绍下关于P2P相关的内容的,首先本人对于C#网络编程也不是什么大牛,由于能力的关系,也只能把本身的一些学习过程和本身的一些学习过程当中的理解和你们分享下的,下面就进入正题——P2P(Peer to Peer)编程编程

 

1、P2P的介绍缓存

 首先,如今你们熟知的BT、电驴、迅雷、QQ、MSN和PPlive等都是基于P2P方式实现的软件,而且对等联网(Peer to Peer,P2P)将是互联网的发展方向,所以对于P2P技术的了解显得很是的重要,下面就来介绍下P2P架构:安全

在P2P技术以前,咱们全部的网络应用都采用C/S或者B/S架构来实现的,然而在以前C/S架构的应用程序中,客户端软件向服务器发出请求,服务器而后对客户端请求作出响应,在这种状况下,若是客户端越多,此时服务器的压力就越大。然而采用P2P技术实现的每台计算机既是客户端,也是服务器,他们的功能都是对等的。对于安装了P2P软件(如迅雷,QQ等)的计算机加入一个共同的P2P网络,网络中的节点之间能够直接进行数据传输和通讯。服务器

1.1 P2P架构和C/S架构的比较网络

C/S架构有下面的缺点(其实上面的简单介绍中也讲到过):多线程

1. 服务器负担太重。当大量用户访问C/S系统的服务器时,服务器经常会出现网络堵塞等现象,这时候,咱们可能会经过增长投资提升服务器的硬件性能架构

2. 系统稳健性和服务器关联密切。指的是——若是服务器出现了问题时,整个系统的运行将会瘫痪(感受是面向对象中常常强调的原则——低耦合原则)

然而P2P具备下面的特色:

1.对等模式

P2P系统中的客户端可以同时扮演客户端和服务器的角色,使两台计算机之间可以不经过服务器直接进行信息分享(QQ中当好友在线的时候发信息时,相信此时是不须要通过服务器转发的,只有当给离线好友发送消息时,此时应该会先把消息发送到服务器端存储起来,当好友再次登陆的时候,会和服务器进行链接,服务器会进行判断是否是给这个用户的信息来决定是否转发,QQ软件的实现属于混合型P2P结构的, 这个会在后面的P2P系统分类中介绍。)

注:括号中都是我我的的一些理解,若是有什么说错的地方请你们及时更正我,这样我会及时的更新以避免误导你们,谢谢你们监督。

2. 网络资源的分布式存储

在C/S架构中,全部客户端都直接从服务器下载全部数据资源,这样势必会加剧服务器的负担,而P2P则改变了以服务器为中心的状态,使每一个节点能够先从服务器上个下载一部分,而后再相互从对方或者其余节点下载其他部分。采用这种方式,当大量客户端同时下载时,就不会造成网络堵塞现象了。

 

1.2 P2P系统的分类

使用P2P技术的系统分为两类:(1)单纯型P2P——没有专用的服务器。安装了P2P软件的各个计算机能够直接通讯

              (2)混合型P2P——有专用的服务器,此时的服务器通常叫索引服务器,此服务器与C/S架构下的服务器不一样,在C/S架构下全部资源都存储在服务器中,全部传递的信息都要通过服务器,而在混合型P2P系统中的索引服务器仅仅起到协调和扩展的功能,资源不是所有存储在服务器上,而是分布在各个电脑上,安装了P2P软件的电脑开始所有和索引服务器链接,以便告知本身监听的IP地址和端口号,而后再经过索引服务器告诉其余与本身链接的电脑,每台计算机的链接和断开都经过服务器通知网络上有联系的计算机,这样就减轻了每台计算机搜索其余计算机的负担,可是信息的传递仍是经过点对点的方式来完成(这里能够以QQ为例,当咱们电脑上安装了QQ这类P2P软件时,安装了QQ这类软件的计算机就会加入一个P2P网络,而且登录的时候都会与索引服务器创建链接,经过链接来告诉服务器本身的IP地址和端口号,当咱们找一个好友聊天时,此时本身的计算机和好友的计算机都会与服务器端口链接,可是要互相发送消息,本身的计算机必须知道好友计算机的IP地址和端口号才能够通讯,这样的工做正是经过索引服务器来告知对方的--指的是告诉本身的计算机好友的计算机的IP地址和端口号,告诉好友的计算机本身的IP地址和端口号,这样双方就能够不经过服务器直接通讯了。)

 

1.3 主流P2P应用分类

P2P 网络应用大体能够分为三类—— 1. 文件共享类,例如迅雷,BT等软件都是文件共享类的应用

                 2. 即时通讯类,例如QQ,MSN等软件都是属于即时通讯类

                 3. 多媒体传输类,例如在线视频直播软件,PPlive等软件

从上面的分类能够看出,如今网络上流行的软件都采用了P2P技术来实现的, 可是它们的实现确定不是单纯的只采用P2P技术来实现的, 而是采用多种技术来实现的, 在下一专题中将介绍利用TCP,UDP和P2P等技术来实现相似QQ的一个即时通讯程序,但愿经过此程序能够综合前面专题介绍的内容以及帮助你们对QQ等软件的实现原理有了解。

 

2、P2P的基本原理

在前面咱们对P2P的一些知识进行的简单的介绍, 经过前面的介绍相信你们对P2P的技术有了必定的了解,可是要本身开发一个P2P的应用固然必须了解P2P技术的实现原理的,下面就介绍下P2P实施的基本原理。

安装了P2P软件后,首先双方要进行通讯,必须可以发现对方(指的就是知道对方的IP地址和端口号),一旦发现了对方后才能够进行通讯,因此P2P应用程序通常分为发现、链接和通讯3个阶段。 发现阶段负责动态定位通讯方的网络位置;链接阶段负责在双方创建网络链接,通讯阶段负责在双方之间传输数据。

 2.1 发现阶段

一台计算机要和另一台计算机通讯,必须知道对方的IP地址和监听端口,不然就没法向对方发送消息。在以前的C/S架构中,服务器的IP地址通常固定不变的,而且提供服务的计算机域名也通常不会改变,因此为了方便客户端访问,一些Web服务器在DNS(DNS其实就是域名和IP地址的一个映射)中进行了注册,客户机能够利用域名解析机制将服务器域名解析为IP地址,而后在P2P应用中,各个对等节点(计算机或资源)能够随时加入和随时离开,而且对等节点的IP地址也不是固定的,因此不能采用DNS的机制来获取P2P架构中的对等节点的信息。

目前,在单纯型P2P中,针对如何发现对等节点,各类P2P技术采用的协议和标准都不同,微软在.net 支持对等名称解析协议(Peer name Resolution Protocol, PNRP),该协议能够发现对等节点的信息,经过无服务器的解析功能将任何资源解析为一组IP地址和端口号,在后面的实现的简单程序用的就是这个协议来完成发现阶段的。

2.2 链接和通讯阶段

 完成对等节点的发现后,接下来就能够根据须要,选择TCP、UDP或者其余协议完成数据传输。若是选择TCP,则须要先创建链接,再利用该链接传输数据,关于TCP的内容能够查看我以前的专题;若是选择UDP,则无须创建链接,直接在对等节点之间通讯就能够了。

3、.net平台对P2P编程的支持

 以前在发现阶段也介绍了.Net平台对P2P编程的支持的,而后微软帮咱们已经封装好了对PNRP协议的实现,这些类在System.Net.PeerToPeer命名空间里(微软如今不少东西都帮咱们封装了,这样能够方便咱们开发应用程序,感受微软的作的东西都是这样,把程序的实现都帮咱们作好了,咱们开发程序的时候只要关注业务逻辑就行了的, 这样作固然有好处也有坏处的, 我以为好处就是缩短软件的开发周期,让花更多的时间去实现软件真真的业务逻辑方面的东西,很差的地方就是如今的程序员就不能叫程序员,因此园子里面有不少人都称码农,这些我本身的观点了)

3.1 对等名称解析协议(PNRP)

PNRP能够完成对等名称的注册和解析(能够和DNS对比来理解)。

3.1.1 基本概念

第一个介绍的是对等名称的概念,咱们将每个网络资源(包括计算机,P2P应用程序、视频、Mp3或其余文档等资源)抽象为对等节点,对等节点名称固然就是对等节点的名称。对等节点名称简称为对等名,分为安全的和不安全的两种形式,不安全的名称仅由文本字符串组成,任何人均可以注册一个相同的不安全对等名称;安全的由一个公钥/私钥(表明惟一)对支持,因此使用PNRP注册时,不会受到欺骗,对等名称的格式以下:

Authority.Classifier

Authority的值取决于该名称的安全类型。对于不安全的类型,Authority为单字符“0”,而对于安全的对等名称,Authority由40个十六机制字符组成

Classifier是用户定义的用于标志对等节点的字符串,最大长度为150个Unicode字符。例如,对等名称0.PeerNametest1就是一个不安全的对等名称。

第二个概念就是云(Cloud)的概念,安装了相同P2P软件的计算机会加入一个共同的P2P网络中,才能相互识别各自拥有的资源并顺利进行P2P通讯。微软PNPR协议将这个P2P网络称为“云”。云是指一组能够经过P2P网络相互识别的对等节点及其上资源的集合。云中的全部对等节点均可以解析注册到该云中的其余任何资源所在的位置(IP+Port),一个对等节点上的某个资源能够同时注册到多个云中。

PNPR目前使用了两种云——本地云和全局云。一个对等名称若注册到连接一本地云,就意味着只有同一本地网络上的其余对等节点能够解析该名称。而注册到全局云上的对等名称则容许IPv6互联网的任何对等节点解析。

注:全局云是基于IPv6协议的,并不支持IPv4,若是不存在IPv6地址,则不会出现全局云,也没法加入全局云。因为如今网上绝大多数应用使用的仍然是IPv4的地址,因此咱们一般的P2P编程还用不到全局云,而只能使用默认的本地云。

3.1.2 名称注册

任何资源要被网络上的其余计算机识别到,首先必须注册进P2P网络,名称注册就是将包含对等节点信息的对等名称发布到云中,以便其余对等节点解析。一个资源若是注册到云中后,就能够被云中的其余对等节点解析和访问。

关于名称注册的具体内容,在后面的P2P的程序中也会使用的, 相信你们能够经过代码来进一步理解名称的注册,这里就先介绍到这里的

3.1.3 名称解析

名称解析是指利用对等名称获取到云中资源所在对等节点的IP地址和端口号的过程(和DNS解析原理同样)。PNPR名称解析仅可以注册到云中的其余对等节点资源,而不能发现自身注册的资源

PNPR协议没有使用索引服务器,因此为了完成解析,云中的每一个对等节点都存储一些PNRP ID的缓存记录。PNPR缓存中的都含有PNPR ID和应用程序的IP地址和端口号。名称解析的步骤为——首先在本地计算机对等节点的缓存中查找目标资源,若是没有,则在缓存中的临近节点查看,这样循环下去,直到找到目标资源所在的对等节点位置。

3.2 PeerToPeer命名空间

上面主要介绍了PNPR协议的工做过程(至关因而理论部分了),下面就介绍下.net 为咱们封装好PNPR的类的使用。这里就简单指明几个经常使用类的使用,并附上MSDN的连接,你们能够直接点连接进行查看详细内容,由于后面的P2P程序中也有具体的使用,因此这里就不一一列出来了。

类名

MSDN连接

Peer

http://msdn.microsoft.com/zh-cn/library/system.net.peertopeer.collaboration.peer.aspx

 

Cloud

http://msdn.microsoft.com/zh-cn/library/system.net.peertopeer.cloud.aspx

PeerName

http://msdn.microsoft.com/zh-cn/library/system.net.peertopeer.peername.aspx

 

PeerNameRecord

http://msdn.microsoft.com/zh-cn/library/system.net.peertopeer.peernamerecord.aspx

 

PeerNameRegistration

http://msdn.microsoft.com/zh-cn/library/system.net.peertopeer.peernameregistration_members(v=VS.90).aspx

 

PeerNameResolver

http://msdn.microsoft.com/zh-cn/library/system.net.peertopeer.peernameresolver.aspx

 

 这些类基本上从类名均可以大体知道他们的用途的,因此在这里就没有一一介绍的,只是附上了MSDN的连接。

4、实现P2P应用程序

以上介绍了那么多P2P的相关的知识,主要是为了实现一个自定义的P2P应用程序作准备的,这里就简单实现了资源发现的一个程序。

核心代码:

 对等名称的注册代码:

复制代码
 // 注册资源
        private void btnRegister_Click(object sender, EventArgs e)
        {
            if (tbxResourceName.Text == "")
            {
                MessageBox.Show("请输入发布的资源名!", "提示");
                return;
            }

            // 将资源名注册到云中
            // 具体资源名的结构在博客有介绍
            PeerName resourceName = new PeerName(tbxResourceName.Text, PeerNameType.Unsecured);
            // 用指定的名称和端口号初始化PeerNameRegistration类的实例
            resourceNameReg[seedCount] = new PeerNameRegistration(resourceName, int.Parse(tbxlocalport.Text));
            // 设置在云中注册的对等名对象的其余信息的注释
            resourceNameReg[seedCount].Comment =resourceName.ToString();
            // 设置PeerNameRegistration对象的应用程序定义的二进制数据
            resourceNameReg[seedCount].Data = Encoding.UTF8.GetBytes(string.Format("{0}", DateTime.Now.ToString()));
            // 在云中注册PeerName(对等名)
            resourceNameReg[seedCount].Start();
            seedCount++;
            comboxSharelist.Items.Add(resourceName.ToString());
            tbxResourceName.Text = "";
        }
复制代码

名称解析代码(搜索资源):

复制代码
  // 搜索资源
        private void btnSearch_Click(object sender, EventArgs e)
        {
            if (tbxSeed.Text == "")
            {
                MessageBox.Show("请先输入要寻找的种子资源名", "提示");
                return;
            }

            lstViewOnlinePeer.Items.Clear();
            // 初始化要搜索的资源名
            PeerName searchSeed = new PeerName("0." + tbxSeed.Text);
            // PeerNameResolver类是将节点名解析为PeerNameRecord的值(即将经过资源名来查找资源名所在的地址,包括IP地址和端口号)
            // PeerNameRecord用来定于云中的各个节点
            PeerNameResolver myresolver = new PeerNameResolver();

            // PeerNameRecordCollection表示PeerNameRecord元素的容器
            // Resolve方法是同步的完成解析
            // 使用同步方法可能会出现界面“假死”现象
            // 解决界面假死现象能够采用多线程或异步的方式
            // 关于多线程的知识能够参考本人博客中多线程系列我前面UDP编程中有所使用
            // 在这里就不列出多线程的使用了,朋友能够本身实现,若是有问题能够留言给我一块儿讨论
            PeerNameRecordCollection recordCollection = myresolver.Resolve(searchSeed);
            foreach (PeerNameRecord record in recordCollection)
            {
                foreach(IPEndPoint endpoint in record.EndPointCollection)
                {
                    if (endpoint.AddressFamily.Equals(AddressFamily.InterNetwork))
                    {
                        ListViewItem item = new ListViewItem();   
                        item.SubItems.Add(endpoint.ToString());
                        item.SubItems.Add(Encoding.UTF8.GetString(record.Data));
                        lstViewOnlinePeer.Items.Add(item);
                    }
                }
            }
        }
复制代码

运行结果截图:
为了演示资源发现的效果,因此同时开启了本程序的3个进程来模拟网络上对等的3个计算机节点,当在资源名中输入资源后会在分享下列表中显示出本地分享的资源,同时在P2P网络上的其余计算机能够经过资源名称搜索该资源,将获得的资源名称和发布时间显示在ListView控件中,下面是程序的运行结果:

5、总结

到这里P2P编程的介绍就结束了, 本专题只是简单演示了一个资源发现的程序,资源发现是P2P的核心技术,正是由于P2P技术实现了互联网范围的资源发现,才使得它被普遍应用,像咱们常常用的下载工具——迅雷,迅雷就是典型采用P2P技术的应用程序,当咱们在迅雷页面中输入“爱情公寓3”(至关于本专题中种子文本框填的资源名)而后点击搜索后迅雷会自动启动“狗狗搜索”并显示资源连接列表,当咱们点击链接就能够进行下载了。不过迅雷确定不是使用微软的PNPR,而是迅雷自主研发的与PNPR做用同样的协议——都是完成解析网络资源的地址的做用,固然,迅雷软件中也采用了其余的一些技术,如搜索引擎等。

但愿本专题能够帮助你们对P2P技术有所了解,若是有任何的问题均可以经过留言的方式来一块儿讨论,在下一个专题中将介绍实现一个相似QQ的程序。

 

源码附上:http://files.cnblogs.com/zhili/P2PResourceDiscovery.zip ,但愿以为有帮助的朋友能够推荐下。谢谢支持

 

 

 
 
77
1
 
(请您对文章作出评价)
 
« 上一篇: VSTO之旅系列(一):VSTO入门
» 下一篇: 我对博客园的建议
posted @ 2012-09-14 15:00 Learning hard 阅读( ...) 评论( 82) 编辑 收藏
相关文章
相关标签/搜索