通信总结——浅谈P2P通信
? ? ? ? ? ? ? ? ? ? ? ? ? ??? ?浅谈P2P通信
什么是p2p?
定义一:p2p是一种通信模式,其中参与者都有相同的能力。在Internet上,p2p是一种网络类型,它允许相同网络程序的计算机相互连接,直接访问对方的硬盘文件。
定义二:p2p(peer-to-peer)是一种对等网络计算机技术,利用客户端的处理能力,实现客户端的点对点通信。
注:说白了,就是点对点通信。
一个概念—NAT
? ? NAT是Net Address Translation(网络地址转换)的简称,就是说,局域网通常靠一个具有公网IP的代理网关服务器Internet共享上网。局域网内的机器并不具备公网IP地址,它只有内网地址,假设它要和Internet上的HTTP服务器通信,代理网关便会新建一个端口来和这个网内机器关联,并通过这个端口来和HTTP服务器交换数据。最终,网内机器-> 代理网关-> HTTP服务器,在一个会话期间,各自的端口保持了映射关系,特别是代理网关和网内机器的端口映射,使得代理网关不会把接收到的数据向网内转发时,发错了机器。?
? ? 局域网内的机器在网关处,就是靠NAT来映射端口并实现Internet连接,因此,NAT也直接被称为“端口映射”。端口映射之后,在一个会话期间保持,对于TCP连接是直到连接断开才销毁,而对于UDP,却存在一个不定的生存期,例如2秒。 ? ? 我们再来分析一下上课老师提出的一个问题,就是服务器受到客户端发送过来的一条消息,然后要回复消息,服务器怎么知道局域网内某台客户机的IP地址呢?这主要是在局域网的网关处存在一个叫NAT的东西,NAT能够映射处客户机的IP然后准确的发送给服务器
实现P2P
如果两个局域网内的服务器要进行p2p通信,有四种方法:
第一:实现局域网内的数据链路层协议,就是写一个类似于TCP/IP的协议,由它来代替Windows系统里的TCP/IP协议,由它直接基于网卡硬件获取数据。这是十分复杂的。?
第二:用Internet上的公网服务器中转数据,但对于大数据量的中转,显然受到服务器和网络的负载极限的限制。?
第三:依靠Internet上的公网服务器做“媒人”,将这两台分别处于不同局域网的机器相互介绍给对方,在它们建立连接之后,服务器即脱离关系。这种方式下,服务器把A的NAT端口映射关系告诉B,又把B的NAT端口映射关系告诉A,这样AB相互知道对方的端口映射关系之后,就能建立连接。因为A和B各自的端口映射关系是靠各自的代理网关动态建立的,动态建立的映射端口不得不告知对方。?
第四:上面的第三种办法,也可以采用静态端口映射方式,这样就不需要中介服务器对A和B做介绍。在各方的代理网关上,可以在代理工具里将某个端口(如1350)和局域网内的某台机器(如内网IP为200.200.200.100,端口1360)做好静态映射,这样,代理网关会自动地将出入于1350端口的数据发往200.200.200.100的1360端口。当然,通信之前,必须对对方的端口映射关系做配置。有多少台网内机器要通信,就得映射多少个不同的端口,同时在另一个局域网内的机器就要做多少个配置。在局域网内搭建HTTP、FTP等服务器就是通过静态映射端口来实现的,这个端口一般不是HTTP、FTP的默认80和23,所以对这类站点的访问往往会在URL里加上端口号。?
? ? 前面两种方法当然是不可行的,我们了解的一般是第三,第四种方法,第三种动态映射端口,需要增加中间服务器,第四种静态映射端口,在需要通信的各方机器很多的情况下,做手工端口映射和配置都是很繁琐的,并且一方添加一台机器,就需要在其余对方增加配置。 向我们平常用的很多软件已经实现了P2P通信,比如著名的有MSN、QQ和BitTorrent下载软件,
? ? P2P要解决的唯一技术难题是如何发现、定位和寻址对方,就是如何穿透NAT、HTTP、Sock等代理和如何穿透方并建立起防火墙找到对通信的问题。由于绝大多数局域网是NAT代理结构,所以前面对NAT论述比较详细,也是网上讨论最多的话题,相比之下,穿透Http、Sock代理就简单一些。此外,穿透NAT发现对等点的办法还有一些,例如多播,但由于现有Internet对多播并不友好,同时多播是无连接和不可靠的,其实现有难度。
下面附一段我P2P代码测试:
?
package P2PTest;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.InetSocketAddress;import java.util.HashSet;import java.util.Set;/** * UDP P2P测试通信转发服务器:接收,转发消息 * @author yujing * */public class DatagramRouteServer {//存放所有客户机地址的队列private Set<InetSocketAddress> clientAddSet = new HashSet<InetSocketAddress>();//启动接收的UDP端口服务器public void startServer() throws Exception{DatagramSocket socket=new DatagramSocket(10000);System.out.println("UDP服务器等待接收数据:"+socket.getLocalSocketAddress());while(true){//指定接收缓冲区大小byte[] buffer=new byte[256];//创建接收数据包对象DatagramPacket packet=new DatagramPacket(buffer, buffer.length);//阻塞等待数据到来,如果数据,存入packet中的缓冲区socket.receive(packet);//得到发送方得IP地址和端口号InetAddress clientAdd=packet.getAddress();int cientPort=packet.getPort();InetSocketAddress address=new InetSocketAddress(clientAdd, cientPort);//将这个地址加入到队列中clientAddSet.add(address);byte[] recvData=packet.getData();//取得数据//去掉空格String s=new String(recvData).trim();//接收到后,打印出收到的数据长度System.out.println("服务器收到数据:"+s+"form:"+address);for(InetSocketAddress dclient:clientAddSet){String temf=address+",到服务器取数据!";//转发服务器的地址和端口列表数据ByteArrayOutputStream bous=new ByteArrayOutputStream();ObjectOutputStream oos=new ObjectOutputStream(bous);oos.writeObject(temf);oos.flush();byte[] data=bous.toByteArray();DatagramPacket mp=new DatagramPacket(data, data.length);mp.setSocketAddress(dclient);//发送给客户端地址socket.send(mp);}//转发服务器断的地址列表数据ByteArrayOutputStream bous=new ByteArrayOutputStream();ObjectOutputStream oos=new ObjectOutputStream(bous);oos.writeObject(clientAddSet);oos.flush();byte[] data=bous.toByteArray();//发送服务器段保存的各个客户机的地址信息DatagramPacket sendp=new DatagramPacket(data, data.length);sendp.setSocketAddress(address);socket.send(sendp);}}/** * 启动主函数 * @param args * @throws Exception */public static void main(String[] args) throws Exception {DatagramRouteServer reciver=new DatagramRouteServer();reciver.startServer();} }?