2026/1/28 9:26:16
网站建设
项目流程
广告联盟网站建设,装饰设计公司网站,wordpress 活动模板,运涛网站建设#x1f680; 前言#xff1a;周末加班的痛
周末在家#xff0c;老板突然打来电话#xff1a;“线上的测试环境出 Bug 了#xff0c;赶紧连一下数据库查查数据。”
你打开电脑#xff0c;准备连接公司的 MySQL#xff0c;突然意识到一个尴尬的问题#xff1a;公司的数据… 前言周末加班的痛周末在家老板突然打来电话“线上的测试环境出 Bug 了赶紧连一下数据库查查数据。”你打开电脑准备连接公司的 MySQL突然意识到一个尴尬的问题公司的数据库在内网没有公网 IP。怎么办跑去公司太惨了用 TeamViewer 远程控制公司电脑卡顿体验极差买花生壳/Ngrok要钱限速还不稳定作为一个 Java 程序员求人不如求己。我们手里的Netty可是高性能网络通信的神器。今天我就带大家用 Netty 手搓一个**“私有版 Ngrok”**。只需一台几十块钱的云服务器就能让你在家像在公司一样丝滑访问内网的所有服务 核心原理外网是怎么“钻”进内网的一般来说外网无法直接访问内网因为有 NAT网络地址转换网关挡着。但是内网是可以主动访问外网的。内网穿透的核心逻辑就是反向代理 (Reverse Proxy) 长连接。我们需要三个角色Proxy Server (中转站)部署在有公网 IP 的云服务器上。Proxy Client (内网助手)运行在公司的电脑上能访问公司内网服务如 MySQL。User (你)在家里的电脑。数据流向图解家里的你公网服务器公司内网助手公司数据库1. 建立长连接通道主动连接 Server (7000端口)认证通过保持连接2. 发起请求连接 Server (8080端口)3. 转发请求收到 User 请求通过长连接转发给 Client4. 内网代理Client 连接本地数据库 (3306)返回查询结果5. 转发响应将结果发回给 Server6. 响应用户Server 将结果发给 User家里的你公网服务器公司内网助手公司数据库一句话总结内网 Client 像一根管子一头插在公司的数据库上一头插在公网 Server 上。你在家访问 ServerServer 就通过这根管子把数据“偷”回来。 实战开发Netty 代码撸起来我们将项目分为server和client两个模块。1. Server 端开发 (公网中转)Server 需要监听两个端口7000 端口用于接收内网 Client 的注册和长连接。8080 端口暴露给 User 使用也就是你在家访问的端口。核心 Handler 逻辑publicclassUserRequestHandlerextendsChannelInboundHandlerAdapter{privatefinalChannelclientChannel;// 指向内网 Client 的连接publicUserRequestHandler(ChannelclientChannel){this.clientChannelclientChannel;}OverridepublicvoidchannelRead(ChannelHandlerContextctx,Objectmsg){// 收到 User 发来的数据比如 MySQL 的握手包// 直接转发给内网 Clientif(clientChannel.isActive()){clientChannel.writeAndFlush(msg);}}}2. Client 端开发 (内网搬运工)Client 启动后主动连接 Server 的 7000 端口。当 Server 发来数据时Client 创建一个新的连接去连本地的 MySQL (3306)然后当个**“双向搬运工”**。publicclassProxyClientHandlerextendsChannelInboundHandlerAdapter{OverridepublicvoidchannelRead(ChannelHandlerContextctx,Objectmsg){// 收到 Server 转发来的 User 请求// 这里的 msg 就是 ByteBuf 数据// 建立连接去连本地 MySQLBootstrapbnewBootstrap();b.group(ctx.channel().eventLoop())// 复用 EventLoop.channel(NioSocketChannel.class).handler(newChannelInitializerSocketChannel(){OverrideprotectedvoidinitChannel(SocketChannelch){ch.pipeline().addLast(newLocalProxyHandler(ctx.channel()));}});ChannellocalChannelb.connect(localhost,3306).sync().channel();// 将数据发给 MySQLlocalChannel.writeAndFlush(msg);}}注意这里的重点是流量透传。我们不需要解析协议HTTP/MySQL只需要把ByteBuf原封不动地从 A 搬到 B。️ 进阶优化让轮子更稳简单的转发很容易断开我们需要加亿点点细节。1. 心跳检测 (HeartBeat)公网环境复杂长连接很容易被防火墙切断。利用 Netty 的IdleStateHandler每隔 30 秒发送一个心跳包。// Server 端管道添加pipeline.addLast(newIdleStateHandler(60,0,0));// Client 端管道添加pipeline.addLast(newIdleStateHandler(0,30,0));2. 断线重连Client 端需要监听连接断开事件channelInactive。一旦断开开启一个定时任务每隔 5 秒尝试重新连接 Server。OverridepublicvoidchannelInactive(ChannelHandlerContextctx){System.out.println(❌ 与服务器断开5秒后重连...);ctx.channel().eventLoop().schedule(()-{connectToServer();},5,TimeUnit.SECONDS);} 效果演示部署把 Server 包丢到阿里云IP: 1.2.3.4启动。启动在公司电脑启动 Client配置目标指向localhost:3306。连接回到家打开 Navicat。主机1.2.3.4(Server IP)端口8080(暴露端口)用户名/密码公司的数据库账号。点击“测试连接” —— 连接成功速度取决于你的云服务器带宽。一般 5Mbps 的带宽足够跑满查询体验吊打免费版的花生壳。 总结通过这个项目我们不仅解决了一个实际痛点更深入理解了TCP 长连接与反向代理原理。Netty 的 ByteBuf 零拷贝特性透传数据的核心。多路复用一个端口处理 N 个连接。技术本该如此既要有底层的深度也要有解决生活的温度。以后再也不用担心回家加班连不上库了虽然这听起来像个悲伤的故事…