上面为类路径
需要在公网运行PublicServer
在有服务的内网上运行LocalServer
流程图
下面代码段
公网服务获取类PublicServer
package Server;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class PublicServer {
private ServerSocket serverSocket;
public MyServerClient myServerClient;
private void CreatePublic(int Port) throws IOException {
System.out.println("服务器启动成功.........");
//监听服务器
serverSocket=new ServerSocket(Port);
while (true){//接受浏览器请求
Socket socket=serverSocket.accept();
System.out.println("请求!");
new MyServer(socket).run();//提交socket线程进行读写
}
}
private void CreateChannel(int Port) throws IOException {
myServerClient=new MyServerClient(Port);//隧道开启
System.out.println("隧道启动");
myServerClient.KeepAlice();//隧道保持长链
}
class MyServer extends Thread {
private Socket accept;
MyServer(Socket accept){
this.accept=accept;
}
@Override
public void run() {
try {
InputStream inputStream = accept.getInputStream();
String RequestMessage;
accept.setSoTimeout(1000);//设置读取超时,否则堵塞
try {
byte b[]=new byte[1024];
try {
inputStream.read(b);
}catch (Exception e){
}
RequestMessage=new String(b).split("\r\n")[0];//仅获取请求中的第一行
System.out.println(RequestMessage);
accept.getOutputStream().write("HTTP/1.1 200 OK \r\n\r\n".getBytes());//输出头部200
if(!"".equals(RequestMessage)){//非空请求进行Channel传输
myServerClient.GetAndSend(RequestMessage.split(" ")[1],accept.getOutputStream());
}else{
System.out.println("空请求");
}
}catch (Exception e){
e.printStackTrace();
}finally {
accept.close();//关闭
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
if(args.length!=2){
System.out.println("参数不足使用默认端口号和地址");
System.out.println("SPort:"+ 7456+",CPort:"+8080);
PublicServer server=new PublicServer();
server.CreateChannel(7456);
server.CreatePublic(8080);
}else{
PublicServer server=new PublicServer();
server.CreateChannel(Integer.parseInt(args[0]));
server.CreatePublic(Integer.parseInt(args[1]));
}
}
}
本地服务提供类LocalServer
package Client;
import java.io.*;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
public class LocalServer {//进行Channel连接,提供内网服务
Socket socket;
// static int SPort=8888;
static int SPort=7456;
static int CPort=5555;
static boolean check=false;
static String ip="172.81.247.205";
// static String ip="127.0.0.1";
LocalServer(int sport,int cport,String ip) throws Exception {
SPort=sport;
CPort=cport;
this.ip=ip; init();
}
LocalServer() throws Exception {
init();
}
public void init() throws Exception {//进行Channel连接
while (true){
try {
socket=new Socket(ip,SPort);
break;
}catch (ConnectException CE){
continue;
}
}
System.out.println("隧道已连接");
while (true){
// 接受Channel参数请求
String param=new DataInputStream(socket.getInputStream()).readUTF();
if(param.trim().equals("")){//保持连接
continue;
}
System.out.println("param"+param);
new SendData(GetOneStream(param)).run();//开启线程回应Channel并且阻塞
while (check){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
InputStream GetOneStream(String param) throws Exception {//获取Stream流
URL url=new URL("http://127.0.0.1:"+CPort+param);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(6 * 1000);
return conn.getInputStream();
}
class SendData extends Thread{
InputStream is;
SendData(InputStream is){
this.is=is;
}
@Override
public void run() {//与内网服务对接传输
try {
Socket s=new Socket(ip,SPort);
check=true;
int len=is.read();
while (len!=-1){
s.getOutputStream().write(len);
len=is.read();
}
s.close();
check=false;
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
if(args.length!=3){
System.out.println("参数不足使用默认端口号和地址");
System.out.println("SPort:"+ SPort+",CPort:"+CPort+",ip:"+ip);
while (true){
try {
new LocalServer();
}catch (Exception e){
System.out.println("隧道断开,重新连接");
}
}
}else{
while (true){
try {
new LocalServer(Integer.parseInt(args[0]),Integer.parseInt(args[1]),args[2]);
}catch (Exception e){
System.out.println("隧道断开,重新连接");
}
}
}
}
}
Channel类、SC之间的通讯类
MyServerClient
package Server;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyServerClient {//进行Channel连接,获取内网服务
private int Port;
private static boolean check=false;
public static String res="";
public static ServerSocket serverSocket;
public static Socket socket;
MyServerClient(int accept) throws IOException {//初始化Channel
this.Port=accept;
serverSocket=new ServerSocket(Port);
System.out.println(Port+"隧道等待连接");
socket=serverSocket.accept();
System.out.println(Port+"隧道连接成功");
}
private final String NotFoundPage="<!DOCTYPE html>" + "<html lang=\"en\">" + "<head>" + " <meta charset=\"UTF-8\">" + " <meta http-equiv=\"Cache-Control\" content=\"max-age=7200\" />" + " <meta http-equiv=\"Expires\" content=\"Mon, 20 Jul 2013 23:00:00 GMT\" />" + " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">" + " <title>404 not found</title>" + "</head>" + "<body style=\"display: flex;min-width: 300px;\">" + " <div style=\"margin-top: 0%; width: 60%; padding-left: 20%;\" >" + " <img style=\"width: 100%;\" src=\"404-l.jpg\" alt=\"\" srcset=\"\"/>" + " <div style=\"display: flex;\">" + " <span style=\"line-height: 64px;font-size: xxx-large;width: 50%;text-align: right;\">" + " 404</span>" + " <img style=\"width: 50%;max-width: 64px;\" src=\"404-r.png\" alt=\"\" srcset=\"\"/> </div>" + " </div>" + "</body>" + "</html>";
private static void GetData(String param,OutputStream os) throws IOException {//Channel核心:与内网服务通讯
System.out.println("param"+param);
new DataOutputStream(socket.getOutputStream()).writeUTF(param);//发送参数
ReceiveData receiveData=new ReceiveData(os);//线程创建
receiveData.run();//进行线程run
while (check){// 等待堵塞
try {
Thread.sleep(10);
if(receiveData.error){break;}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class ReceiveData extends Thread{//接受Channel回调的线程,与本地socket对接
public boolean error=false;
OutputStream os;
ReceiveData(OutputStream os){
this.os=os;
}
@Override
public void run() {
try {
Socket s=serverSocket.accept();
check=true;
res="";
int len=s.getInputStream().read();
while (len!=-1){
os.write(len);
len=s.getInputStream().read();
}
s.close();
check=false;
} catch (IOException e) {
error=true;
// e.printStackTrace();
}
}
}
public void GetAndSend(String param, OutputStream os)throws IOException {//发送参数且返回到os中
if(param.equals("/404-l.jpg")||param.equals("/404-r.png")){
FileInputStream fis=new FileInputStream(param.substring(1));
int len=fis.read();
while (len!=-1){
os.write(len);
len=fis.read();
}
fis.close();
}else if(param.endsWith("favicon.ico")){
FileInputStream fis=new FileInputStream("favicon.ico");
int len=fis.read();
while (len!=-1){
os.write(len);
len=fis.read();
}
fis.close();
}
else{
GetData(param,os);//这里为就可以,上面内容可以DIY设置
}
}
public void KeepAlice(){//保持socket长连
ExecutorService es =Executors.newCachedThreadPool();//创建Future非阻塞线程
es.submit(()->{
while (true){
Thread.sleep(1000);
try {
new DataOutputStream(socket.getOutputStream()).writeUTF("");//发送空字符判断socket是否断开
}catch (Exception e){
System.err.println("内网服务异常断开,重连中");
socket=serverSocket.accept();//重连
System.err.println("内网服务恢复0");
}
}
});
}
}
已上传到GitHubEnter