突然之间想搭建一个内网穿透的服务

313 阅读2分钟

背景

在大模型环境下,我们可能想把本地的部署的模型想对外使用时,这是时候就需要内网穿透,把端口暴露到公网中,让外部使用。当然内网穿透的工具有很多,我使用了免费的Ngrok,感觉不错,但是Ngrok有个问题初次访问应用时,他会跳转一个验证的界面,导致API请求返回格式错误。刚好我有空闲的云服务器,尝试去实现一下。

效果

output.gif

流程图

sequenceDiagram
title http请求
电脑->>云服务器: http http://127.0.0.1:8080(协议+本地应用地址)
云服务器-->>电脑: 6deddb19.demo.online(域名)
用户->>云服务器: 访问域名(6deddb19.demo.online)
云服务器-->>电脑: 告知电脑有用户连接
电脑->>云服务器: 马上连接云服务器
云服务器->>云服务器: 电脑连接和访问连接交换数据
电脑-->>用户: 返回数据给用户
用户->>电脑: 交换数据
电脑-->>用户: 交换数据

大致流程如图上的,上面是http请求的,首先电脑上的Java应用会连接云服务器,发送请求:协议+本地应用地址,云服务器收到信息,就会随机生成一个uuid+顶级域名的域名给Java应用。用户用这个域名去访问云服务器,当云服务器在80端口收到这个域名信息时,解析前缀拿到这个uuid,通过这个uuid找到对应的Java应用,通过这个Java应用告知有用户连接,电脑端就会连接到云服务端,收到到云服务端的数据,就转发到本地的应用,完成了连接的交换数据。

sequenceDiagram
title tcp请求
电脑->>云服务器: tcp 127.0.0.1:8080(协议+本地应用地址)
云服务器-->>电脑: www.demo.online:49152(地址)
用户->>云服务器: 访问地址(www.demo.online:49152)
云服务器-->>电脑: 告知电脑有用户连接
电脑->>云服务器: 马上连接云服务器
云服务器->>云服务器: 电脑连接和访问连接交换数据
电脑-->>用户: 返回数据给用户
用户->>电脑: 交换数据
电脑-->>用户: 交换数据

上面tcp请求和http差不多,主要是tcp协议是拿不到域名的,域名是被dns解析成ip的,才通过ip和端口去tcp访问的。所以tcp请求协议访问云服务器的时候,就返回一个域名和随机端口。

代码

我这里使用的是JDK17、kotlin、协程、NIO。使用kotlin编写代码确实少很多代码量,但是编译真的好久。协程倒是还好,主要NIO代码编写比较麻烦,跳来跳去的,使用NIO还是为了省内存空间,主要他是一个线程去管理多个连接,就用一个bytebuffer。如果想简单点还是选择AIO编程相对简单。

代码还是不粘贴出来了,感兴趣的话去仓库看看,就两个类。

完整代码:portway: 内网穿透服务

推荐一下我之前写的AIO内网穿透文章: 使用Java自己简单搭建内网穿透内网穿透是一种网络技术,适用于需要远程访问本地部署服务的场景,比如你在家里搭建了一个网站 - 掘金

遇到问题

  1. 使用协程的Dispatchers.Default导致协程数量不足,阻塞了应用。默认是协程数量等于核心数。
  2. Socket连接需要心跳,不然会变成假死状态,会导致可以给Socket发信息,不报错但是对面也收不到。
  3. 使用Docker部署Server时,因为要用大量端口导致Docker卡死,所以只能通过外部部署了。
  4. 阿里的免费证书不支持通配符,所以使用acme

路漫漫其修远兮