java实现P2P通信(含安卓实现的基于IPV6的p2p通信代码)
什么是P2P网络
p2p网络又叫对等网络,顾名思义就是在该网络中所有节点都是平等的,都可以共享自己的硬件资源和数据资源。每个节点都能被其它对等节点直接访问而无需经过中间实体。换句话来说,目前绝大多数应用都是基于C/S或者B/S架构的,就拿微信来说,当A要通过微信给B发一条消息时,消息首先会从A发送到服务器,然后服务器在转发给B。这样服务器就会知道AB之间的聊天记录。而P2P网络来说,A可以直接发送消息给B不需要中转服务器。这样的好处就不言而喻了。
用udp打洞的三种方式
本来按照互联网之前的设计p2p通信不是什么大问题。A想给B发消息只需要知道B的IP地址和端口号就可以直接发送消息给B了。但是由于IPV4地址数量只有42亿多个,已经远远不能满足人们的上网需求,因此出现了NAT技术,通过绑定端口让多台计算机可以共用一个公网IP从而缓解公网IP地址空间的枯竭。但这样就带来了新的问题。A不知道B的公网IP和映射端口号就找不到B了。那么我就有了个大胆的想法,通过中间服务器存储A和B的公网IP以及映射的端口号,然后分别发送给A和B,这样A和B就知道对方的公网IP和端口号,不就可以访问了吗。这个也叫做udp打洞。如图所示:
基于上图我用java的udp协议包实现了程序代码如下:
服务器:
// An highlighted block
public class p2pService {
//map存储每个注册用户的名字和公网地址
Map<String,String>map =new HashMap<String,String>();
byte[] inBuff=new byte[2048];
DatagramPacket inpacket=new DatagramPacket(inBuff,2048);
public void init() {
try {
System.out.println("服务器启动");
DatagramSocket socket=new DatagramSocket(30000);
while(true) {
socket.receive(inpacket);
System.out.println("地址:"+inpacket.getSocketAddress()+" 端口:"+inpacket.getPort()+" 消息:"+new String(inBuff,0,inpacket.getLength()));
JSONObject json=JSONObject.fromObject(new String(inBuff,0,inpacket.getLength()));
//message封装通信消息格式
message mess=(message)JSONObject.toBean(json, message.class);
//link类消息为注册消息
if("link".equals(mess.type))
{
map.put(mess.name, inpacket.getSocketAddress()+"");
List<Map<String,String>>list=new ArrayList<>();
for(String key:map.keySet())
{
Map<String,String> map1=new HashMap<>();
map1.put("name", key);
map1.put("IP", map.get(key));
list.add(map1);
}
String messs=JSONArray.fromObject(list)+"";
message mes=new message();
mes.type="list";
mes.value=messs;
messs=JSONObject.fromObject(mes)+"";
System.out.println(messs);
byte[] outmess=messs.getBytes("utf-8");
DatagramPacket out=new DatagramPacket(outmess,outmess.length,inpacket.getSocketAddress());