免费开源网站,各地持续优化防控措施,郴州互联网公司招聘,专业微信网站对于网络用户来说#xff0c;一定都经历过出门在外无法直接在异地访问公司的ERP系统、或是难以部署异地远程桌面#xff0c;因此心急如焚的情况#xff1b;对于企业来说#xff0c;无论是财务管理软件难以将分店信息同步到总部进行统计汇总、还是员工出差在外或在家里就不能…对于网络用户来说一定都经历过出门在外无法直接在异地访问公司的ERP系统、或是难以部署异地远程桌面因此心急如焚的情况对于企业来说无论是财务管理软件难以将分店信息同步到总部进行统计汇总、还是员工出差在外或在家里就不能访问企业内部办公系统都极大地影响了公司整体效率对于个人开发者来说微信小程序或者在线支付系统等开发环境往往需要一个可以环境进行调试不然的话难以进行开发调试。
诸如此类的难题众多但解决方法其实很简单那就是使用软件或者自己手写一个可以支持访问我的电脑上的微信支付接口从而实现这一系列的简易操作。目前国内这方面企业级的服务商有**壳和神卓互联我接触过很多公司在用**壳的技术是PHTunnel 神卓互联用的是Wangooe Tunnel技术这里就介绍神卓互联的接下来就介绍和分析这款软件的用法和技术要点。如果没有接触过这方面技术的同学可以看一下这个图 首先用法很简单就是在界面上创建一条映射规则填写应用名称和要连接的内网应用主机地址和端口号。 填写自己要穿透的应用名称和端口号如果需要获取原访问者IP最好是选择Web应用。提交提交就可以了。
例如我需要发布一个Tomcat应用访问端口号是7070那么应用名称填写tomcat,内网主机填写127.0.0.1内网端口填7070点提交就可以。
首先新建一个web项目 新建login.jsp登陆文件内容如下
% page languagejava contentTypetext/html; charsetUTF-8pageEncodingUTF-8%
!DOCTYPE html PUBLIC -//W3C//DTD HTML 4.01 Transitional//EN http://www.w3.org/TR/html4/loose.dtd
html
head
meta http-equivContent-Type contenttext/html; charsetUTF-8
title登录系统/title
style typetext/css
table td{font: 14px/1.5 Microsoft YaHei,arial,tahoma,\5b8b\4f53,sans-serif;}
/style
/head
body
table
trtd用户名/tdtdinput typetext/td/tr
trtd密码/tdtdinput typetext/td/tr
trtdnbsp;/tdtdinput typesubmit value登录/td/tr
/table
/body
/html
先在本地运行看项目是否可以正常运行 本地运行没有问题可以正常打开接下来就试一下外网访问 打开神卓互联软件主界面右键选择外网访问 如果需要绑定域名访问的话也很简单这里不多说。
接下来就分析是如何做到将请求转发到内网因为又返回给访问客户端的。 InetAddress
//获取本机的InetAddress实例
InetAddress address InetAddress.getLocalHost();
address.getHostName();//获取计算机名
address.getHostAddress();//获取IP地址
byte[] bytes address.getAddress();//获取字节数组形式的IP地址,以点分隔的四部分//获取其他主机的InetAddress实例
InetAddress address2 InetAddress.getByName(其他主机名);
InetAddress address3 InetAddress.getByName(IP地址);
URL类
//创建一个URL的实例
URL baidu new URL(http://www.baidu.com);
URL url new URL(baidu,/index.html?usernametom#test);//表示参数#表示锚点
url.getProtocol();//获取协议
url.getHost();//获取主机
url.getPort();//如果没有指定端口号根据协议不同使用默认端口。此时getPort()方法的返回值为 -1
url.getPath();//获取文件路径
url.getFile();//文件名包括文件路径参数
url.getRef();//相对路径就是锚点即#号后面的内容
url.getQuery();//查询字符串即参数
以下就是P2P打洞核心代码TCP
假设现在有以下3台机器
外网机器IP121.56.21.85 以下简称“主机A”
处在内网1下的机器外网IP106.116.5.45 内网IP192.168.1.10 以下简称“主机1”
处在内网2下的机器外网IP104.128.52.6 内网IP192.168.0.11以下简称“主机2”
很显然内网的两台机器不能直接连接我们现在要实现的是借助外网机器让两台内网机器进行tcp直连通讯。
实现过程如下
1、主机A启动服务端程序监听端口8888接受TCP请求。
2、启动主机1的客户端程序连接主机A的8888端口建立TCP连接。
3、启动主机2的客户端程序连接主机A的8888端口建立TCP连接。
4、主机2发送一个命令告诉主机A我要求与其他设备进行连接请求协助进行穿透。
5、主机A接收到主机2的命令之后会返回主机1的外网地址和端口给主机2同时把主机2的外网地址和端口发送给主机1。
6、主机1和主机2在收到主机A的信息之后同时异步发起对对方的连接。
7、在与对方发起连接之后监听本地与主机A连接的端口也可以在发起连接之前由于不同的操作系统对tcp的实现不尽相同有的操作系统会在连接发送之后把对方的连接当作是回应即发出SYN之后把对方发来的SYN当作是本次SYN的ACK这种情况就不需要监听也可建立连接本文的代码所在测试环境就不需要监听测试环境为服务器centos 7.3 内网1 win10内网2 win10和centos7.2都测试过。
8、主机1和主机2成功连上可以关闭主机A的服务主机1和主机2的连接依然会持续生效不关闭就形成了一个3方直连的拓扑网状结构网络。
服务器端代码
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 ListServerThread connections new ArrayListServerThread();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();}}
}
package org.inchain.p2p;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;/*** 外网端服务多线程处理内网端连接* * author ln**/
public class ServerThread extends Thread {// 和本线程相关的Socketprivate Socket socket null;private BufferedReader br null;private PrintWriter pw null;public ServerThread(Socket socket) throws IOException {this.socket socket;this.br new BufferedReader(new InputStreamReader(socket.getInputStream()));this.pw new PrintWriter(socket.getOutputStream());}// 线程执行的操作响应客户端的请求public void run() {InetAddress address socket.getInetAddress();System.out.println(新连接客户端的IP address.getHostAddress() ,端口 socket.getPort());try {pw.write(已有客户端列表 Server.connections \n);// 获取输入流并读取客户端信息String info null;while ((info br.readLine()) ! null) {// 循环读取客户端的信息System.out.println(我是服务器客户端说 info);if (info.startsWith(newConn_)) {//接收到穿透消息通知目标节点String[] infos info.split(_);//目标节点的外网ip地址String ip infos[1];//目标节点的外网端口String port infos[2];System.out.println(打洞到 ip : port);for (ServerThread server : Server.connections) {if (server.socket.getInetAddress().getHostAddress().equals(ip) server.socket.getPort() Integer.parseInt(port)) {//发送命令通知目标节点进行穿透连接server.pw.write(autoConn_ socket.getInetAddress().getHostAddress() _ socket.getPort() \n);server.pw.flush();break;}}} else {// 获取输出流响应客户端的请求pw.write(欢迎您 info \n);// 调用flush()方法将缓冲输出pw.flush();}}} catch (Exception e) {e.printStackTrace();} finally {System.out.println(客户端关闭 address.getHostAddress() ,端口 socket.getPort());Server.connections.remove(this);// 关闭资源try {if (pw ! null) {pw.close();}if (br ! null) {br.close();}if (socket ! null) {socket.close();}} catch (IOException e) {e.printStackTrace();}}}Overridepublic String toString() {return ServerThread [socket socket ];}
}
最后附上测试方法和运行效果
使用方法 1、在服务器启动Server。 2、在客户端1启动Client输入notwait命令等待服务器通知打洞。 3、在客户端2启动Client输入conn命令然后输入服务器返回的客户端1的外网ip和端口接下来就会自动完成连接。 运行效果 客户端1运行结果 穿透成功之后客户端会把穿透对方返回的内容发送给服务器服务器再返回 客户端1使用netstat查看的网络连接 客户端2的运行结果
客户端2使用netstat查看的网络连接 可以看到客户端2对应的端口不同那是因为电信NAT的问题本地获取的Ip是电信10开头的内网地址相当于在客户端2的上层还进行了一次中继。
s由于没有对称型的NAT设备无法做深入研究对称型设备的端口太难猜测穿透成功概率很小。