7 Commits

Author SHA1 Message Date
wujiawei
3f4a05ba5c [fix] fix 2025-11-11 21:40:49 +08:00
wujiawei
a42694af58 [fix] fix 2025-11-08 21:19:28 +08:00
wujiawei
eee7b9e511 【update】 1.3.6-JDK24 2025-11-03 20:59:19 +08:00
wujiawei
3b231083fe Merge remote-tracking branch 'origin/master' 2025-10-25 00:02:28 +08:00
wujiawei
8938bfca6a [update] <version>1.3.6-JDK24-SNAPSHOT</version> 2025-10-25 00:02:20 +08:00
macbookpro
55ca1974da Merge remote-tracking branch 'origin/master' 2025-09-01 22:28:15 +08:00
macbookpro
f28efb5fe8 【fix】官网描述调整 2025-08-28 22:37:01 +08:00
16 changed files with 419 additions and 36 deletions

33
pom.xml
View File

@@ -8,12 +8,12 @@
<parent>
<artifactId>wu-framework-parent</artifactId>
<groupId>top.wu2020</groupId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</parent>
<artifactId>wu-lazy-cloud-network</artifactId>
<packaging>pom</packaging>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
<description>云上云下</description>
<name>wlcn项目</name>
<url>https://gitee.com/wujiawei1207537021/wu-lazy-cloud-network</url>
@@ -93,7 +93,7 @@
<dependency>
<groupId>top.wu2020</groupId>
<artifactId>wu-framework-dependencies</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -102,5 +102,32 @@
<profiles>
<profile>
<id>windows</id>
<activation>
<os>
<family>windows</family>
</os>
</activation>
<properties>
<packaging.type>msi</packaging.type>
</properties>
</profile>
<profile>
<id>mac</id>
<activation>
<os>
<family>mac</family>
</os>
</activation>
<properties>
<packaging.type>dmg</packaging.type>
</properties>
</profile>
<!-- 可以添加更多针对不同操作系统的 profile -->
</profiles>
</project>

View File

@@ -56,4 +56,6 @@
[add]默认客户端ID为当前设备唯一标识
#### 下一版本计划
#### 下一版本计划
[add] 流媒体抓取
[add] 监听本地网卡进行代理

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>top.wu2020</groupId>
<artifactId>wu-lazy-cloud-network</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -79,7 +79,7 @@
<dependency>
<groupId>top.wu2020</groupId>
<artifactId>wu-framework-javafx-spring-starter</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</dependency>
</dependencies>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>top.wu2020</groupId>
<artifactId>wu-lazy-cloud-network</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</parent>
<artifactId>wu-lazy-cloud-heartbeat-common</artifactId>
@@ -56,14 +56,14 @@
<dependency>
<groupId>top.wu2020</groupId>
<artifactId>wu-framework-queue</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</dependency>
<!-- log -->
<dependency>
<groupId>top.wu2020</groupId>
<artifactId>wu-framework-log-spring-starter</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>top.wu2020</groupId>-->
<!-- <artifactId>wu-framework-log-spring-starter</artifactId>-->
<!-- <version>1.3.6-JDK24</version>-->
<!-- </dependency>-->
</dependencies>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>top.wu2020</groupId>
<artifactId>wu-lazy-cloud-network</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>top.wu2020</groupId>
<artifactId>wu-lazy-cloud-network</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -81,7 +81,7 @@
<dependency>
<groupId>top.wu2020</groupId>
<artifactId>wu-framework-queue</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</dependency>
</dependencies>

View File

@@ -0,0 +1,210 @@
package org.framework.lazy.cloud.network.heartbeat.protocol.test1;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.net.InetSocketAddress;
/**
* 流量拦截处理器:执行拦截策略,处理流量转发/丢弃/修改
*/
public class TrafficInterceptHandler extends ChannelDuplexHandler {
private final TrafficInterceptor.InterceptStrategy strategy;
private Channel forwardChannel; // 转发通道(连接原目标服务器)
private InetSocketAddress originalTarget; // 流量的原目标地址(需解析获取)
public TrafficInterceptHandler(TrafficInterceptor.InterceptStrategy strategy) {
this.strategy = strategy;
}
/**
* 客户端连接建立时,解析原目标地址(关键:透明代理需知道流量要发往的原目标)
* 注原目标地址的解析方式需根据场景调整如通过路由表、ARP 缓存、或 RAW socket 抓包解析 IP 头部)
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
InetSocketAddress clientAddr = (InetSocketAddress) ctx.channel().remoteAddress();
System.out.println("拦截到新连接:客户端 " + clientAddr);
// 关键步骤:解析流量的原目标地址(此处为模拟,实际需通过以下方式获取)
// 方式 1若拦截器作为网关原目标地址即客户端请求的目标 IP:Port需解析应用层协议如 HTTP Host 头)
// 方式 2用 RAW socket 抓包,解析 IP 头部的「目的地址」字段(推荐,适用于所有 TCP 流量)
// 方式 3通过 iptables 端口转发,原目标地址由 iptables 传递Linux 环境)
// 此处模拟:假设原目标是百度服务器(实际需动态解析)
originalTarget = new InetSocketAddress("220.181.38.251", 80);
// 根据策略初始化转发通道(若需要转发)
if (strategy == TrafficInterceptor.InterceptStrategy.FORWARD || strategy == TrafficInterceptor.InterceptStrategy.MODIFY) {
initForwardChannel(ctx);
}
super.channelActive(ctx);
}
/**
* 初始化转发通道:连接原目标服务器,实现透明转发
*/
private void initForwardChannel(ChannelHandlerContext ctx) {
Bootstrap bootstrap = new Bootstrap()
.group(ctx.channel().eventLoop()) // 复用客户端事件循环组,性能更优
.channel(NioSocketChannel.class)
.option(io.netty.channel.ChannelOption.SO_KEEPALIVE, true)
.handler(new ChannelDuplexHandler() {
// 接收原目标服务器的响应,转发回客户端
@Override
public void channelRead(ChannelHandlerContext forwardCtx, Object msg) throws Exception {
ByteBuf response = (ByteBuf) msg;
System.out.printf("收到原目标 %s 响应,长度:%d 字节%n", originalTarget, response.readableBytes());
// 若策略是「修改流量」,则修改响应内容
if (strategy == TrafficInterceptor.InterceptStrategy.MODIFY) {
modifyData(response, false); // false 表示修改响应流量
}
// 转发响应到客户端
ctx.channel().writeAndFlush(msg);
}
@Override
public void channelInactive(ChannelHandlerContext forwardCtx) throws Exception {
System.out.println("转发通道断开:原目标 " + originalTarget);
ctx.channel().close(); // 转发通道断开,关闭客户端连接
}
});
// 连接原目标服务器
bootstrap.connect(originalTarget).addListener((ChannelFutureListener) future -> {
if (future.isSuccess()) {
forwardChannel = future.channel();
System.out.println("成功连接原目标:" + originalTarget);
} else {
System.err.println("连接原目标失败:" + originalTarget + ",原因:" + future.cause().getMessage());
ctx.channel().close();
}
});
}
/**
* 拦截客户端发送的流量(出站流量)
*/
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
ByteBuf request = (ByteBuf) msg;
InetSocketAddress clientAddr = (InetSocketAddress) ctx.channel().remoteAddress();
System.out.printf("拦截到客户端 %s 发送的流量,长度:%d 字节%n", clientAddr, request.readableBytes());
switch (strategy) {
case DROP:
// 丢弃流量,释放缓冲区
request.release();
System.out.println("已丢弃该流量策略DROP");
break;
case MODIFY:
// 修改流量内容(示例:在 HTTP 请求头添加自定义字段)
modifyData(request, true); // true 表示修改请求流量
System.out.println("已修改流量,准备转发");
// fall through 到 FORWARD 逻辑
case FORWARD:
// 转发流量到原目标服务器
if (forwardChannel != null && forwardChannel.isActive()) {
forwardChannel.writeAndFlush(msg).addListener((ChannelFutureListener) future -> {
if (!future.isSuccess()) {
System.err.println("流量转发失败:" + future.cause().getMessage());
ctx.channel().close();
}
});
} else {
request.release();
System.err.println("转发通道未就绪,丢弃流量");
}
break;
case LOG_ONLY:
// 仅记录日志,不拦截,直接放行(透传流量)
super.write(ctx, msg, promise);
break;
}
}
/**
* 修改流量内容(示例:修改 HTTP 请求/响应)
* @param data 要修改的 ByteBuf 数据
* @param isRequest 是否为请求流量true请求false响应
*/
private void modifyData(ByteBuf data, boolean isRequest) {
// 示例:在 HTTP 请求头添加 X-Intercepted: true 字段
if (isRequest) {
// 切换为读模式,读取 HTTP 头
data.markReaderIndex();
byte[] temp = new byte[data.readableBytes()];
data.readBytes(temp);
String content = new String(temp);
// 找到 HTTP 头的结束位置("\r\n\r\n"),插入自定义字段
if (content.contains("\r\n\r\n")) {
content = content.replace("\r\n\r\n", "\r\nX-Intercepted: true\r\n\r\n");
// 重置 ByteBuf写入修改后的数据
data.resetReaderIndex();
data.clear();
data.writeBytes(content.getBytes());
System.out.println("已修改请求流量:添加 X-Intercepted 头");
}
} else {
// 示例:修改 HTTP 响应的内容
data.markReaderIndex();
byte[] temp = new byte[data.readableBytes()];
data.readBytes(temp);
String content = new String(temp);
if (content.contains("<body>")) {
content = content.replace("<body>", "<body><h1>流量已被 Netty 拦截并修改</h1>");
data.resetReaderIndex();
data.clear();
data.writeBytes(content.getBytes());
System.out.println("已修改响应流量:添加拦截提示");
}
}
}
/**
* 拦截客户端接收的流量(响应流量)
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 若策略为「仅记录日志」,直接放行;其他策略已在转发通道中处理
if (strategy == TrafficInterceptor.InterceptStrategy.LOG_ONLY) {
ByteBuf data = (ByteBuf) msg;
System.out.printf("记录流量:客户端接收数据,长度:%d 字节%n", data.readableBytes());
super.channelRead(ctx, msg);
} else {
((ByteBuf) msg).release(); // 已在转发通道中处理,此处释放缓冲区
}
}
/**
* 连接断开时,关闭转发通道
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("连接断开:客户端 " + ctx.channel().remoteAddress());
if (forwardChannel != null && forwardChannel.isActive()) {
forwardChannel.close();
}
super.channelInactive(ctx);
}
/**
* 异常处理:关闭所有连接
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.err.println("流量拦截异常:" + cause.getMessage());
ctx.close();
if (forwardChannel != null && forwardChannel.isActive()) {
forwardChannel.close();
}
}
}

View File

@@ -0,0 +1,134 @@
package org.framework.lazy.cloud.network.heartbeat.protocol.test1;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
/**
* 网络流量拦截器:绑定指定网卡,拦截该网卡的所有 TCP 流量,支持转发/丢弃/修改
*/
public class TrafficInterceptor {
// 绑定的网卡 IP必须是本地网卡已配置的 IP
private final String bindIp;
// 拦截策略(可自定义:转发、丢弃、修改等)
private final InterceptStrategy strategy;
// Netty 事件循环组
private EventLoopGroup bossGroup;
private EventLoopGroup workerGroup;
/**
* 构造拦截器
* @param bindIp 绑定的网卡 IP如 192.168.1.100
* @param strategy 拦截策略
*/
public TrafficInterceptor(String bindIp, InterceptStrategy strategy) {
this.bindIp = bindIp;
this.strategy = strategy;
validateBindIp(bindIp);
}
/**
* 启动拦截器(监听绑定网卡的所有 TCP 端口,实际通过端口复用实现)
* 注:全端口监听需操作系统支持,或通过「端口范围监听」模拟(此处用 1-65535 端口范围)
*/
public void start() throws InterruptedException {
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
try {
// 核心:启动服务端,绑定网卡 IP监听所有 TCP 端口(模拟全端口拦截)
// 实际生产中可优化为:监听常用端口 + 动态端口,或用 RAW socket 直接抓包
ServerBootstrap bootstrap = new ServerBootstrap()
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(bindIp, 0)) // 端口 0 表示随机端口,实际通过端口复用扩展
.option(ChannelOption.SO_REUSEADDR, true) // 允许端口复用(关键)
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.handler(new LoggingHandler(LogLevel.INFO)) // 日志打印(可选)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast(new LoggingHandler(LogLevel.DEBUG)) // 打印流量日志
.addLast(new TrafficInterceptHandler(strategy)); // 核心拦截处理器
}
});
// 绑定网卡 IP监听所有端口模拟实际需遍历端口或用 RAW socket此处以常用端口为例
System.out.printf("流量拦截器启动成功!绑定网卡:%s拦截策略%s%n", bindIp, strategy);
System.out.println("开始拦截该网卡的所有 TCP 流量...");
// 阻塞等待服务端关闭
bootstrap.bind().sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
System.out.println("流量拦截器已关闭");
}
}
/**
* 校验绑定的网卡是否存在
*/
private void validateBindIp(String bindIp) {
try {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
boolean exists = false;
while (interfaces.hasMoreElements()) {
NetworkInterface ni = interfaces.nextElement();
Enumeration<java.net.InetAddress> addresses = ni.getInetAddresses();
while (addresses.hasMoreElements()) {
java.net.InetAddress addr = addresses.nextElement();
if (addr.getHostAddress().equals(bindIp)) {
exists = true;
break;
}
}
if (exists) break;
}
if (!exists) {
throw new IllegalArgumentException("绑定的网卡 IP " + bindIp + " 不存在于本地网卡");
}
} catch (SocketException e) {
throw new RuntimeException("获取本地网卡信息失败:" + e.getMessage());
}
}
/**
* 拦截策略枚举(可扩展)
*/
public enum InterceptStrategy {
FORWARD("转发流量到原目标"),
DROP("丢弃流量"),
MODIFY("修改流量内容后转发"),
LOG_ONLY("仅记录日志,不拦截");
private final String desc;
InterceptStrategy(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
}
public static void main(String[] args) throws InterruptedException {
// 示例:绑定网卡 192.168.1.100,策略为「记录日志并转发」
String bindIp = "192.168.3.6";
TrafficInterceptor.InterceptStrategy strategy = TrafficInterceptor.InterceptStrategy.LOG_ONLY;
new TrafficInterceptor(bindIp, strategy).start();
}
}

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>top.wu2020</groupId>
<artifactId>wu-lazy-cloud-network</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>top.wu2020</groupId>
<artifactId>wu-lazy-cloud-network</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -116,7 +116,7 @@
<dependency>
<groupId>top.wu2020</groupId>
<artifactId>wu-framework-javafx-spring-starter</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</dependency>
</dependencies>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>top.wu2020</groupId>
<artifactId>wu-lazy-cloud-network</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</parent>
<artifactId>wu-lazy-cloud-heartbeat-start</artifactId>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>top.wu2020</groupId>
<artifactId>wu-lazy-cloud-heartbeat-start</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -99,10 +99,8 @@
<argument>--verbose</argument>
<argument>--type</argument>
<argument>dmg</argument>
<argument>${packaging.type}</argument>
<!-- 根据操作系统动态设置打包类型 -->
<!-- <argument>${os.name.contains("Windows") ? "msi" : (os.name.contains("Mac") ? "dmg" : "deb")}</argument>-->
<argument>--input</argument>
<argument>target</argument>
@@ -110,7 +108,7 @@
<argument>target/installer</argument>
<argument>--name</argument>
<argument>wlcn-client</argument>
<argument>wlcn-client-${os.name}-${project.version}</argument>
<argument>--main-jar</argument>
<argument>${project.build.finalName}.jar</argument>
@@ -122,7 +120,7 @@
<!-- <argument>src/main/resources/app${os.name.contains("Windows") ? ".ico" : (os.name.contains("Mac") ? ".icns" : ".png")}</argument>-->
<argument>--app-version</argument>
<argument>1.3.4</argument>
<argument>1.3.6</argument>
<argument>--vendor</argument>
<argument>小吴小吴bug全无${os.name}</argument>

View File

@@ -42,4 +42,11 @@ spring:
javafx:
target-url: http://127.0.0.1:6004/netty-client-local-ui/index.html
window:
title: wlcn客户端
title: wlcn客户端
---
#虚拟线程
spring:
threads:
virtual:
enabled: true

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>top.wu2020</groupId>
<artifactId>wu-lazy-cloud-heartbeat-start</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>top.wu2020</groupId>
<artifactId>wu-lazy-cloud-heartbeat-start</artifactId>
<version>1.3.4-JDK24-SNAPSHOT</version>
<version>1.3.6-JDK24</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -86,10 +86,7 @@
<argument>--verbose</argument>
<argument>--type</argument>
<argument>dmg</argument>
<!-- 根据操作系统动态设置打包类型 -->
<!-- <argument>${os.name.contains("Windows") ? "msi" : (os.name.contains("Mac") ? "dmg" : "deb")}</argument>-->
<argument>${packaging.type}</argument>
<argument>--input</argument>
<argument>target</argument>
@@ -97,7 +94,7 @@
<argument>target/installer</argument>
<argument>--name</argument>
<argument>wlcn-server</argument>
<argument>wlcn-server-${os.name}-${project.version}</argument>
<argument>--main-jar</argument>
<argument>${project.build.finalName}.jar</argument>
@@ -105,7 +102,7 @@
<argument>--main-class</argument>
<argument>org.springframework.boot.loader.launch.JarLauncher</argument>
<argument>--app-version</argument>
<argument>1.3.4</argument>
<argument>1.3.6</argument>
<argument>--vendor</argument>
<argument>小吴小吴bug全无${os.name}</argument>

View File

@@ -77,4 +77,12 @@ spring:
columnName: zone_id
columnType: varchar(255)
comment: 区域ID
exist: true
exist: true
---
#虚拟线程
spring:
threads:
virtual:
enabled: true