p2p技术,又称为点对点(peer-to-peer),可以直接跨越NAT实现内网主机直接通讯。实现方式包括:中继(Relaying),逆向链接(Connection reversal), udp打洞(UDP hole punching)。中继方式是比较传统且效率较低的一种,不推荐使用,本人采用的是udp打洞,可以极大的降低服务器的压力,提高作业效率。
因为项目需要,开始研究起了p2p,之前对网络这块基本还是小白状态,首先,实现内网穿透,我们需要三台机器来搭建环境,一台处在内网的主机A,一台处在内网的主机B,一台处在公网的机器C。代码可参考:
代码转载自p2p代码实现,为了方便,我也把人家代码写在下面了。
注意点:
环境部分的影响因素:
1:部署位置。我们需要将服务端部署在公网环境中。
2:客户端与服务端的防火墙必须都处于关闭状态。
3:客户端与服务端的通信协议必须保持一致(ipv4与ipv6)。
4:保证网络稳定。
代码部分的影响因素:
1:内网主机穿透时必须是异步发起连接。
2:在穿透时,新建的连接,需要先设置SO_REUSEADDR,再绑定端口,最后进行连接,顺序不能错。
3:客户端获取本地ip地址时候,不能使用程序提供的封装方法:InetAddress.getLocalHost().getHostAddress(),需要手动设置改成实际的IP地址,因为有的机器可能有多个网卡或虚拟网卡,不该成当前实际的IP会导致使用错误的IP地址。(最重要的一点,深坑,这点会导致打洞失败!!!)
服务器端代码
package org.inchain.p2p;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
/**
* 外网端服务,穿透中继
*
* @author ln
*
*/
public class Server {
public static List<ServerThread> connections = new ArrayList<ServerThread>();
public static void main(String[] args) {
try {
// 1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = null;
// 记录客户端的数量
int count = 0;
System.out.println("***服务器即将启动,等待客户端的连接***");
// 循环监听等待客户端的连接
while (true) {
// 调用accept()方法开始监听,等待客户端的连接
socket = serverSocket.accept();
// 创建一个新的线程
ServerThread serverThread = new ServerThread(socket);
// 启动线程
serverThread.start();
connections.add(serverThread);
count++;// 统计客户端的数量
System.out.println("客户端的数量:" + count);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}