优秀的毕业设计论文网
计算机 JAVA 电子信息 单片机 机械机电 模具 土木工程 建筑结构 论文
热门搜索词:网络 ASP.NET 汽车 电气 数控 PLC

063_虚拟实验平台—VLP2P通信库

以下是资料介绍,如需要完整的请充值下载.
1.无需注册登录,支付后按照提示操作即可获取该资料.
2.资料以网页介绍的为准,下载后不会有水印.资料仅供学习参考之用.
  
资料介绍:

1.3. 项目要求
1.3.1 功能要求
实现虚拟实验平台具有网络基本功能,客户机和主机,客户机和客户机之间的即时通讯、文件的传输。
1.3.2 B/S与 C/S
目前的软件系统体系结构一般分为两种形式,一种为大家所熟识的C/S 结构,另一种为B/S 结构。C/S 结构,即Client/Server(客户端/服务器)结构,通过将任务合理分配到Client 端和Server 端,降低了系统的通讯开销,可以充分利用两端硬件环境的优势。B/S 结构,即Browse /Server(浏览器/服务器)结构,就是只安装维护一个服务器,而客户端采用浏览器运行软件,进行浏览、访问、操作数据。最初的管理信息系统基本上是采用C/S 模式开发的,但随着WWW 的广泛应用,目前的管理信息系统已经逐渐开始从C/S 模式向浏览器/服务器B/S 模式转变。B/S 结构的软件所有的维护、升级工作都只在服务器上进行,而客户端能立刻获得最新版本的软件。
1.3.3 通信协议的选择
主机与客户机之间采用TCP协议,保证其可靠性。
客户机之间采用UDP非连接,不可靠的通讯协议,相对于tcp来说,虽然可靠性不及,但传输效率较高。对于即时通信的系统,选择UDP,就是要保证较高的传输效率。
1.4. 项目难点及解决方法
1.4.1 IP处理问题

【www.think58.com计算机毕业论文网】

copyright think58 [版权所有:http://think58.com]

[资料来源:http://www.THINK58.com]


由于涉及到各种局域网,因此需要处理各种私有IP的访问问题。
解决方法:采用NAT技术实现私有地址转换成公共有效的地址。
1.4.2 Client之间的通信问题
解决方法:利用服务器的打洞原理(后详)
2. 网络基础知识介绍
2.1. SOCKET编程
什么是 socket?它是使用 标准Unix 文件描述符 (file descriptor) 和其它程序通讯的方式。Unix 程序在执行任何形式的 I/O 的时候,程序是在读或者写一个文件描述符。一个文件描述符只是一个和打开的文件相关联的整数。但是(注意后面的话),这个文件可能是一个网络连接,FIFO,管道,终端,磁盘上的文件或者什么其它的东西。Unix 中所有的东西就是文件!所以,你想和Internet上别的程序通讯的时候,你将要使用到文件描述符。你必须理解刚才的话。现在你脑海中或许冒出这样的念头:“那么我从哪里得到网络通讯的文件描述符呢?”,这个问题无论如何我都要回答:你利用系统调用 socket(),它返回套接字描述符 (socket descriptor),然后你再通过它来进行send() 和 recv()调用。“但是...”,你可能有很大的疑惑,“如果它是个文件描述符,那么为什 么不用一般调用read()和write()来进行套接字通讯?”。答案是:“你可以,但是使用send()和recv()让你更好的控制数据传输。”存在这样一个情况:在我们的世界上,有很多种套接字。有DARPA Internet 地址 (Internet 套接字),本地节点的路径名 (Unix套接字),CCITT X.25地址 (你可以将X.25 套接字完全忽略)。也许在你的Unix 机器上还有其它的。 [资料来源:www.THINK58.com]
2.2. P2P网络简介(introduction)
P2P技术源于局域网共享,其目标是改变人们通过服务器中转交换文件的传统方式,达到自由交换资源的目的。IBM为P2P下了如下定义:系统由若干互联协作的计算机构成,且至少具有如下特征之一:系统依存于边缘化(非中央式服务器)设备的主动协作,每个成员直接从其他成员而不是从服务器的参与中受益;系统中成员同时扮演服务器与客户端的角色;系统应用的用户能够意识到彼此的存在,构成一个虚拟或实际的群体。P2P网络是互联网整体架构的基础,互联网最基本的 TCP/IP协议并没有客户端和服务器的概念,在通讯过程中,所有的设备都是平等的一端。P2P 技术改变了“内容”所在的位置,使其正在从“中心”走向“边缘”,也就是说不再如C\S模式将内容存于主要的服务器上,而是存在所有用户的 PC 机上。广义的P2P 网络将 P2P网络划分为纯分散式 P2P网络(如gnutella模型)、超级结点式网络和混合式 P2P网络等大类。
本文所讨论的通讯技术属于混合式 P2P网络,各节点之间可以直接建立连接,但网络的构建需要服务器,通过集中认证,建立索引机制。但是这里的服务器仅用于辅助对等节点之间建立连接,对等节点之间直接进行通信,这不同于 C/S 模式中的服务器。如图1 p2p网络传输模型所示:

think58 [版权所有:http://think58.com]



图1 p2p网络传输模型
3. 项目网络通信的实现过程
3.1. NAT的一些基本概念
NAT(Network Address Translators),网络地址转换:网络地址转换是在IP地址日益缺乏的情况下产生的,它的主要目的就是为了能够地址重用。NAT分为两大类,基本的NAT和NAPT(Network Address/Port Translator)。最开始NAT是运行在路由器上的一个功能模块。
最先提出的是基本的NAT,它的产生基于如下事实:一个私有网络(域)中的节点中只有很少的节点需要与外网连接。那么这个子网中其实只有少数的节点需要全球唯一的IP地址,其他的节点的IP地址应该是可以重用的。
因此,基本的NAT实现的功能很简单,在子网内使用一个保留的IP子网段,这些IP对外是不可见的。子网内只有少数一些IP地址可以对应到真正全球唯一的IP地址。如果这些节点需要访问外部网络,那么基本NAT就负责将这个节点的子网内IP转化为一个全球唯一的IP然后发送出去。(关于基本的NAT可以参看RFC 1631)
3.2. 通信过程
另外一种NAT叫做NAPT,从名称上我们也可以看得出,NAPT不但会改变经过这个NAT设备的IP数据报的IP地址,还会改变IP数据报的TCP/UDP端口。基本NAT的设备可能我们见的不多,NAPT才是我们真正讨论的主角。见图2 NAPT端口映射: copyright think58 [资料来源:http://www.THINK58.com]

图2 NAPT端口映射
有一个私有网络10.*.*.*,Client A是其中的一台计算机,这个网络的网关(一个NAT设备)的外网IP是155.99.25.11(应该还有一个内网的IP地址,比如10.0.0.10)。如果Client A中的某个进程(这个进程创建了一个UDP Socket,这个Socket绑定1234端口)想访问外网主机18.181.0.31的1235端口,那么当数据包通过NAT时会发生什么事情呢?
首先NAT会改变这个数据包的原IP地址,改为155.99.25.11。接着NAT会为这个传输创建一个Session(Session是一个抽象的概念,如果是TCP,也许Session是由一个SYN包开始,以一个FIN包结束。而UDP呢,以这个IP的这个端口的第一个UDP开始,结束呢,呵呵,也许是几分钟,也许是几小时,这要看具体的实现了)并且给这个Session分配一个端口,比如62000,然后改变这个数据包的源端口为62000。所以本来是(10.0.0.1:1234->18.181.0.31:1235)的数据包到了互联网上变为了(155.99.25.11:62000->18.181.0.31:1235)。
一旦NAT创建了一个Session后,NAT会记住62000端口对应的是10.0.0.1的1234端口,以后从18.181.0.31发送到62000端口的数据会被NAT自动的转发到10.0.0.1上。(注意:这里是说18.181.0.31发送到62000端口的数据会被转发,其他的IP发送到这个端口的数据将被NAT抛弃)这样Client A就与Server S1建立以了一个连接。 [资料来源:www.THINK58.com]
呵呵,上面的基础知识可能很多人都知道了,那么下面是关键的部分了。看看下面的情况,见图3 NAPT转发过程:

图3 NAPT转发过程
接上面的例子,如果Client A的原来那个Socket(绑定了1234端口的那个UDP Socket)又接着向另外一个Server S2发送了一个UDP包,那么这个UDP包在通过NAT时会怎么样呢?
这时可能会有两种情况发生,一种是NAT再次创建一个Session,并且再次为这个Session分配一个端口号(比如:62001)。另外一种是NAT再次创建一个Session,但是不会新分配一个端口号,而是用原来分配的端口号62000。前一种NAT叫做Symmetric NAT,后一种叫做Cone NAT。我们期望我们的NAT是第二种,呵呵,如果你的NAT刚好是第一种,那么很可能会有很多P2P软件失灵。(可以庆幸的是,现在绝大多数的NAT属于后者,即Cone NAT)
好了,我们看到,通过NAT,子网内的计算机向外连结是很容易的(NAT相当于透明的,子网内的和外网的计算机不用知道NAT的情况)。
但是如果外部的计算机想访问子网内的计算机就比较困难了(而这正是P2P所需要的)。
那么我们如果想从外部发送一个数据报给内网的计算机有什么办法呢?首先,我们必须在内网的NAT上打上一个“洞”(也就是前面我们说的在NAT上建立一个Session),这个洞不能由外部来打,只能由内网内的主机来打。而且这个洞是有方向的,比如从内部某台主机(比如:192.168.0.10)向外部的某个IP(比如:219.237.60.1)发送一个UDP包,那么就在这个内网的NAT设备上打了一个方向为219.237.60.1的“洞”,(这就是称为UDP Hole Punching的技术)以后219.237.60.1就可以通过这个洞与内网的192.168.0.10联系了。(但是其他的IP不能利用这个洞)。 内容来自think58
[资料来源:http://THINK58.com]

呵呵,现在该轮到我们的正题P2P了。有了上面的理论,实现两个内网的主机通讯就差最后一步了:那就是鸡生蛋还是蛋生鸡的问题了,两边都无法主动发出连接请求,谁也不知道谁的公网地址,那我们如何来打这个洞呢?我们需要一个中间人来联系这两个内网主机。
现在我们来看看一个P2P软件的流程,以下图为例:

图4 p2p打洞过程
首先,Client A登录服务器,NAT A为这次的Session分配了一个端口60000,那么Server S收到的Client A的地址是202.187.45.3:60000,这就是Client A的外网地址了。同样,Client B登录Server S,NAT B给此次Session分配的端口是40000,那么Server S收到的B的地址是187.34.1.56:40000。
此时,Client A与Client B都可以与Server S通信了。如果Client A此时想直接发送信息给Client B,那么他可以从Server S那儿获得B的公网地址187.34.1.56:40000,是不是Client A向这个地址发送信息Client B就能收到了呢?答案是不行,因为如果这样发送信息,NAT B会将这个信息丢弃(因为这样的信息是不请自来的,为了安全,大多数NAT都会执行丢弃动作)。现在我们需要的是在NAT B上打一个方向为202.187.45.3(即Client A的外网地址)的洞,那么Client A发送到187.34.1.56:40000的信息,Client B就能收到了。这个打洞命令由谁来发呢,呵呵,当然是Server S。 内容来自think58
[来源:http://think58.com]

3.3. 通信过程总结
总结一下这个过程:如果Client A想向Client B发送信息,那么Client A发送命令给Server S,请求Server S命令Client B向Client A方向打洞。),然后Client A就可以通过Client B的外网地址与Client B通信了。
注意:以上过程只适合于Cone NAT的情况,如果是Symmetric NAT,那么当Client B向Client A打洞的端口已经重新分配了,Client B将无法知道这个端口(如果Symmetric NAT的端口是顺序分配的,那么我们或许可以猜测这个端口号,可是由于可能导致失败的因素太多,我们不推荐这种猜测端口的方法)。
4. 实现代码及其效果简介
下面是这个通信的过程的源代码,,P2PServer运行在一个拥有公网IP的计算机上,P2PClient运行在两个不同的NAT后(注意,如果两个客户端运行在一个NAT后,本程序很可能不能运行正常,这取决于你的,NAT是否支持loopback translation,当然,此问题可以通过双方先尝试连接对方的内网IP来解决,但是这个代码只是为了验证原理,并没有处理这些问题)。
4.1. 程序主要功能介绍
主机与客户机连接,客户机向主机发送消息或下载实验文本,主机自行决定客户机下载文本的渠道(通过主机下载或从别的客户机下载)。
4.2. 主要代码介绍 [资料来源:http://www.THINK58.com]
4.3.1 服务器监听过程主要代码
//准许连接,发送欢迎信息
private void Accept(IAsyncResult iar) {
Socket Remote = (Socket)iar.AsyncState;
clientS[i] = (Socket)Remote.EndAccept(iar);
//服务器接受由客户端传来的UDP包,用于记录客户端的UDP端口
UDPS.ReceiveFrom(Data, ref RemoteEP);
//异步发送欢迎消息
clientS[i].BeginSend(Message, 0, Message.Length, SocketFlags.None, new AsyncCallback(Send), clientS[i]); }
4.3.2 客户端连接过程主要代码
private void BTNConnect_Click(object sender, EventArgs e){
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//S1为服务器IP,S2为服务器端口
P = new IPEndPoint(IPAddress.Parse(NewF.S1.ToString()), Int32.Parse(NewF.S2.ToString()));
//异步连接开始
sock.BeginConnect(P, new AsyncCallback(Connected), sock); }
void Connected(IAsyncResult iar) {
Client = (Socket)iar.AsyncState;
Client.EndConnect(iar);
//向服务器发送一个UDP包,服务器可由此包记录客户端的UDP端口,为P2P打洞作准备 think58
[资料来源:www.THINK58.com]

UDPClient.SendTo(Data, SUDPIp);
//异步接收从服务器传来的欢迎信息,用来检测连接是否成功
Client.BeginReceive(Data, 0, Data.Length, SocketFlags.None, new AsyncCallback(Receive), Client); }
copyright think58
[资料来源:http://THINK58.com]