公网ip可以被互联网访问,而本机的私有ip则不被允许,如何实现将公网ip的请求映射到本机的室友ip呢,我们基于websocket技术,将访问服务器的请求全部转发到本机上
websocket实现的话,是需要分为两个端,第一个是放在公网的服务端,第二个是放在本机的客户端,客户端则需要主动的去请求公网的服务端,实现连接成功后,服务端会把所有的请求推给客户端,客户端处理完成后,则将处理结果返回给服务端,再由服务端返回给请求端
客户端篇
<!-- okhttp -->
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.10.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.java-websocket/Java-WebSocket -->
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.5.0</version>
</dependency>
okhttp请求工具类,实现将客户端获取到的请求转发出去
package com.example.config;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import okhttp3.*;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* @author Xiongx
* @version 1.0
* @date 2021/7/2 10:35
* @since JDK 1.8
*/
public class OkHttpUtils {
private static volatile OkHttpClient okHttpClient = null;
private static volatile Semaphore semaphore = null;
private Map<String, String> headerMap;
private Map<String, String> paramMap;
private String url;
private Request.Builder request;
/**
* 初始化okHttpClient,并且允许https访问
*/
private OkHttpUtils() {
if (okHttpClient == null) {
synchronized (OkHttpUtils.class) {
if (okHttpClient == null) {
TrustManager[] trustManagers = buildTrustManagers();
okHttpClient = new OkHttpClient.Builder()
.connectTimeout(150, TimeUnit.MINUTES)
.writeTimeout(200000, TimeUnit.SECONDS)
.readTimeout(200000, TimeUnit.SECONDS)
.sslSocketFactory(createSSLSocketFactory(trustManagers), (X509TrustManager) trustManagers[0])
.hostnameVerifier((hostName, session) -> true)
.retryOnConnectionFailure(true)
.build();
addHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
}
}
}
}
/**
* 用于异步请求时,控制访问线程数,返回结果
*
* @return
*/
private static Semaphore getSemaphoreInstance() {
//只能1个线程同时访问
synchronized (OkHttpUtils.class) {
if (semaphore == null) {
semaphore = new Semaphore(0);
}
}
return semaphore;
}
/**
* 创建OkHttpUtils
*
* @return
*/
public static OkHttpUtils builder() {
return new OkHttpUtils();
}
/**
* 添加url
*
* @param url
* @return
*/
public OkHttpUtils url(String url) {
this.url = url;
return this;
}
/**
* 添加参数
*
* @param key 参数名
* @param value 参数值
* @return
*/
public OkHttpUtils addParam(String key, String value) {
if (paramMap == null) {
paramMap = new LinkedHashMap<>(16);
}
paramMap.put(key, value);
return this;
}
public OkHttpUtils addParamMap(Map<String, Object> map){
if(paramMap==null){
paramMap= new LinkedHashMap<>(16);
}
map.forEach((k,v)->{
String value= JSONObject.toJSONString(v, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteMapNullValue);
paramMap.put(k,value);
});
return this;
}
public OkHttpUtils addJson(JSONObject json){
if(paramMap==null){
paramMap= new LinkedHashMap<>(16);
}
json.forEach((k, v) -> {
String value= JSONObject.toJSONString(v, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteMapNullValue);
paramMap.put(k,value);
});
return this;
}
/**
* 添加请求头
*
* @param key 参数名
* @param value 参数值
* @return
*/
public OkHttpUtils addHeader(String key, String value) {
if (headerMap == null) {
headerMap = new LinkedHashMap<>(16);
}
headerMap.put(key, value);
return this;
}
public OkHttpUtils addHeader(Map<String,String> heards){
if (headerMap == null) {
headerMap = new LinkedHashMap<>(16);
}
if(heards!=null){
for (Map.Entry<String, String> entry : heards.entrySet()) {
headerMap.put(entry.getKey(), entry.getValue());
}
}
return this;
}
/**
* 初始化get方法
*
* @return
*/
public OkHttpUtils get() {
request = new Request.Builder().get();
StringBuilder urlBuilder = new StringBuilder(url);
if (paramMap != null) {
urlBuilder.append("?");
try {
for (Map.Entry<String, String> entry : paramMap.entrySet()) {
urlBuilder.append(URLEncoder.encode(entry.getKey(), "utf-8")).
append("=").
append(URLEncoder.encode(entry.getValue(), "utf-8")).
append("&");
}
} catch (Exception e) {
e.printStackTrace();
}
urlBuilder.deleteCharAt(urlBuilder.length() - 1);
}
request.url(urlBuilder.toString());
return this;
}
/**
* 初始化post方法
*
* @param isJsonPost true等于json的方式提交数据,类似postman里post方法的raw
* false等于普通的表单提交
* @return
*/
public OkHttpUtils post(boolean isJsonPost) {
RequestBody requestBody;
if (isJsonPost) {
String json = "";
if (paramMap != null) {
json = JSON.toJSONString(paramMap);
}
requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
} else {
FormBody.Builder formBody = new FormBody.Builder();
if (paramMap != null) {
paramMap.forEach(formBody::add);
}
requestBody = formBody.build();
}
request = new Request.Builder().post(requestBody).url(url);
return this;
}
public OkHttpUtils post(Map<String, Object> objectMap) {
RequestBody requestBody;
String json = "";
if (objectMap != null) {
json = JSON.toJSONString(objectMap);
}
requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
request = new Request.Builder().post(requestBody).url(url);
return this;
}
/**
* 同步请求
*
* @return
*/
public String sync() {
setHeader(request);
try {
Response response = okHttpClient.newCall(request.build()).execute();
assert response.body() != null;
return response.body().string();
} catch (IOException e) {
e.printStackTrace();
return "请求失败:" + e.getMessage();
}
}
/**
* 异步请求,有返回值
*/
public String async() {
StringBuilder buffer = new StringBuilder("");
setHeader(request);
okHttpClient.newCall(request.build()).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
buffer.append("请求出错:").append(e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
assert response.body() != null;
buffer.append(response.body().string());
getSemaphoreInstance().release();
}
});
try {
getSemaphoreInstance().acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
return buffer.toString();
}
/**
* 异步请求,带有接口回调
*
* @param callBack
*/
public void async(ICallBack callBack) {
setHeader(request);
okHttpClient.newCall(request.build()).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
callBack.onFailure(call, e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
assert response.body() != null;
callBack.onSuccessful(call, response.body().string());
}
});
}
/**
* 为request添加请求头
*
* @param request
*/
private void setHeader(Request.Builder request) {
if (headerMap != null) {
try {
for (Map.Entry<String, String> entry : headerMap.entrySet()) {
request.addHeader(entry.getKey(), entry.getValue());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 生成安全套接字工厂,用于https请求的证书跳过
*
* @return
*/
private static SSLSocketFactory createSSLSocketFactory(TrustManager[] trustAllCerts) {
SSLSocketFactory ssfFactory = null;
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
ssfFactory = sc.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
return ssfFactory;
}
private static TrustManager[] buildTrustManagers() {
return new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
};
}
/**
* 自定义一个接口回调
*/
public interface ICallBack {
void onSuccessful(Call call, String data);
void onFailure(Call call, String errorMsg);
}
public void Demo(){
OkHttpUtils.builder().url("请求地址,http/https都可以")
// 有参数的话添加参数,可多个
.addParam("参数名", "参数值")
.addParam("参数名", "参数值")
// 也可以添加多个
.addHeader("Content-Type", "application/json; charset=utf-8")
.get()
// 可选择是同步请求还是异步请求
//.async();
.sync();
// post请求,分为两种,一种是普通表单提交,一种是json提交
OkHttpUtils.builder().url("请求地址,http/https都可以")
// 有参数的话添加参数,可多个
.addParam("参数名", "参数值")
.addParam("参数名", "参数值")
// 也可以添加多个
.addHeader("Content-Type", "application/json; charset=utf-8")
// 如果是true的话,会类似于postman中post提交方式的raw,用json的方式提交,不是表单
// 如果是false的话传统的表单提交
.post(true)
.sync();
// 选择异步有两个方法,一个是带回调接口,一个是直接返回结果
OkHttpUtils.builder().url("")
.post(false)
.async();
OkHttpUtils.builder().url("").post(false).async(new ICallBack() {
@Override
public void onSuccessful(Call call, String data) {
// 请求成功后的处理
}
@Override
public void onFailure(Call call, String errorMsg) {
// 请求失败后的处理
}
});
}
}
websocketconfig工具类
import com.alibaba.fastjson.JSONObject;
import com.example.utils.FileUtils;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.stereotype.Component;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.time.LocalDate;
/**
* @Classname WebSockerConfig
* @Description TODO
* @Date 2023/3/8 20:34
* @Created by XiongXiong
* @Author: X.I.O
*/
@Component
public class WebSockerConfig {
private static String urlAddr="ws://ip:8090/wsconnection";
//服务网关
private static String getWayUrl="http://127.0.0.1:8004";
private static WebSocketClient mWs;
public void sendMessage() throws URISyntaxException {
if(mWs==null){
URI uri = new URI(urlAddr);
mWs= new WebSocketClient(uri) {
@Override
public void onOpen(ServerHandshake serverHandshake) {
}
@Override
public void onMessage(ByteBuffer bytes) {
super.onMessage(bytes);
}
@Override
public void send(byte[] data) {
super.send(data);
}
@Override
public void onMessage(String s) {
System.out.println("收到消息"+s);
System.out.println(s+" 收到服务器的消息了");
if("file".equals(s)){
byte[] file= FileUtils.getByteByFile(new File("D:\\Users\\X.I.O\\Pictures\\微信图片_20230115133944.jpg"));
ByteBuffer buffer=FileUtils.byte2Byffer(file);
System.out.println("开始发送文件数据"+file.length);
this.send(buffer);
}else {
JSONObject obj=JSONObject.parseObject(s);
if(obj.containsKey("code") && "200".equals(obj.getString("code"))){
RequestModel requestModel=JSONObject.parseObject(s,RequestModel.class);
String url=requestModel.getUrl();
url=getWayUrl+url;
if("GET".equals(requestModel.getMethod())){
String queryString=requestModel.getQueryString();
if(!"".equals(queryString) && queryString!=null){
url=url+"?"+queryString;
}
System.out.println("请求地址:"+url);
OkHttpUtils okHttpUtils=OkHttpUtils.builder();
okHttpUtils.url(url);
if(requestModel.getQueryMap()!=null){
okHttpUtils.addParamMap(requestModel.getQueryMap());
}
okHttpUtils.addHeader(requestModel.getHearders());
String str=okHttpUtils.get().sync();
System.out.println(str+" 执行结果");
this.send(str);
}
if("POST".equals(requestModel.getMethod())){
String queryString=requestModel.getQueryString();
if(!"".equals(queryString) && queryString!=null){
url=url+"?"+queryString;
}
System.out.println("请求地址:"+url);
OkHttpUtils okHttpUtils=OkHttpUtils.builder();
okHttpUtils.url(url);
okHttpUtils.addHeader(requestModel.getHearders());
JSONObject json=requestModel.getBody();
if(json != null && !json.isEmpty()){
okHttpUtils.addJson(requestModel.getBody());
okHttpUtils.post(true);
String rsult=okHttpUtils.sync();
this.send(rsult);
}else {
if(requestModel.getQueryMap()!=null){
okHttpUtils.addParamMap(requestModel.getQueryMap());
}
okHttpUtils.post(false);
String result=okHttpUtils.sync();
this.send(result);
}
}
}
}
}
@Override
public void onClose(int i, String s, boolean b) {
System.out.println(s+" 我关闭了");
}
@Override
public void onError(Exception e) {
System.out.println(e.getMessage()+" 为啥阿");
}
};
mWs.connect();
}
while (!mWs.isOpen()){
//先阻塞会
}
if(mWs.isOpen()){
JSONObject obj=new JSONObject();
obj.put("code",0);
obj.put("msg","开始连接");
mWs.send(obj.toJSONString());
}
}
}
FileUtils
/**
* @Classname FileUtils
* @Description TODO
* @Date 2023/3/8 13:51
* @Created by XiongXiong
* @Author: X.I.O
*/
public class FileUtils {
/**
* byte 数组转byteBuffer
* @param byteArray
*/
public static ByteBuffer byte2Byffer(byte[] byteArray) {
//初始化一个和byte长度一样的buffer
ByteBuffer buffer=ByteBuffer.allocate(byteArray.length);
// 数组放到buffer中
buffer.put(byteArray);
//重置 limit 和postion 值 否则 buffer 读取数据不对
buffer.flip();
return buffer;
}
public static byte[] bytebuffer2ByteArray(ByteBuffer buffer) {
//重置 limit 和postion 值
buffer.flip();
//获取buffer中有效大小
int len=buffer.limit() - buffer.position();
byte [] bytes=new byte[len];
for (int i = 0; i < bytes.length; i++) {
bytes[i]=buffer.get();
}
return bytes;
}
public static byte[] getByteByFile(File file){
FileInputStream fis=null;
try {
byte[] bytesArray = new byte[(int) file.length()];
fis = new FileInputStream(file);
fis.read(bytesArray);
return bytesArray;
}catch (IOException e) {
e.printStackTrace();
}finally {
if (fis != null) {
try {
fis.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public static void byteToFile(byte[] bytes,File file){
OutputStream out = null;
InputStream is = null;
try {
out = new FileOutputStream(file);
is = new ByteArrayInputStream(bytes);
byte[] buff = new byte[1024];
int len = 0;
while((len=is.read(buff))!=-1){
out.write(buff, 0, len);
}
}catch (IOException e) {
e.printStackTrace();
}finally {
if (is != null) {
try {
is.close();
}catch (IOException e) {
e.printStackTrace();
}
}
if(out != null){
try {
out.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
初始化配置
@Component
public class InitConfig {
@Autowired
private WebSockerConfig webSockerConfig;
@PostConstruct
public void init() throws URISyntaxException {
webSockerConfig.sendMessage();
}
}
RequestModel
import com.alibaba.fastjson.JSONObject;
import java.io.Serializable;
import java.util.Map;
/**
* @Classname RequestModel
* @Description TODO
* @Date 2023/3/8 20:06
* @Created by XiongXiong
* @Author: X.I.O
*/
public class RequestModel implements Serializable {
private Integer code;
private String url;
private Map<String,String> hearders;
private String method;
private Map<String,Object> queryMap;
private JSONObject body;
private String queryString;
private String scheme;
private String remoteAddress;
private String remoteHost;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getRemoteHost() {
return remoteHost;
}
public void setRemoteHost(String remoteHost) {
this.remoteHost = remoteHost;
}
public String getQueryString() {
return queryString;
}
public void setQueryString(String queryString) {
this.queryString = queryString;
}
public String getScheme() {
return scheme;
}
public void setScheme(String scheme) {
this.scheme = scheme;
}
public String getRemoteAddress() {
return remoteAddress;
}
public void setRemoteAddress(String remoteAddress) {
this.remoteAddress = remoteAddress;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Map<String, String> getHearders() {
return hearders;
}
public void setHearders(Map<String, String> hearders) {
this.hearders = hearders;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Map<String, Object> getQueryMap() {
return queryMap;
}
public void setQueryMap(Map<String, Object> queryMap) {
this.queryMap = queryMap;
}
public JSONObject getBody() {
return body;
}
public void setBody(JSONObject body) {
this.body = body;
}
public RequestModel(String url, Map<String, String> hearders, String method, Map<String, Object> queryMap, JSONObject body) {
this.url = url;
this.hearders = hearders;
this.method = method;
this.queryMap = queryMap;
this.body = body;
}
public RequestModel() {
}
}