Practical Netty (5) TCP反向代理服务器
以下针对 TCP 反向代理服务器。
1. 前端连接被创建时,创建后端连接
一个平凡的 ServerBootstrap 会有如下的一个语句:
serverBootstrap.setPipelineFactory(
new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline p = pipeline();
p.addLast("handler", new PoechantProxyHandler());
return p;
}
});
这个PoechantProxyHandler
如何实现,就成了关键了。
每个 connection 建立后,会创建一个 channel 专门用于服务这个连接。此时会响应ChannelPipelineHandler
的此方法:
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e)
这时你可以为这个 connection(不妨称其为前端连接),创建一个与后端连接的 connection(不妨称其为后端连接)。此时对于后端服务器,你要扮演的是 client 的角色,所以需要一个 ClientBootstrap。该 client 连接成功后,就可以从前端连接中读取数据了。
private volatile Channel outboundChannel;
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
final Channel inboundChannel = e.getChannel();
inboundChannel.setReadable(false);
ClientBootstrap cb = new ClientBootstrap(cf);
cb.getPipeline().addLast("handler", new BackendChannelHandler(e.getChannel()));
ChannelFuture f = cb.connect(new InetSocketAddress(remoteHost, remotePort));
outboundChannel = f.getChannel();
f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
inboundChannel.setReadable(true);
} else {
inboundChannel.close();
}
}
});
}
ClientBootstrap.connect
后会创建一个 Channel,与后端服务器连接。对于 ClientBootstrap 是不存在 parent channel 和 child channel 这样需要考虑的策略的。
转载请注明来自柳大的CSDN博客:Blog.CSDN.net/Poechant,微博:weibo.com/lauginhom
2. 前端接收的消息,转发给后端
亲,请边看下面的代码,边读我写的这段话。msg
是从前端Channel
(因为这是一个为前端ServerBootstrap
服务的 ChannelPipelineHandler)拿到的消息,然后把它写入到后端连接的Channel
(outboundChannel
就是前面我们在前端连接被建立时创建的后端Channel
)。
@Override
public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e)
throws Exception {
ChannelBuffer msg = (ChannelBuffer) e.getMessage();
synchronized (trafficLock) {
outboundChannel.write(msg);
if (!outboundChannel.isWritable()) {
e.getChannel().setReadable(false);
}
}
}
2.1. 对后端通道的操作,要做同步
需要注意的是,凡是对 outboundHandler 的操作都是需要同步的,因为 PoechantProxyHandler 中的 outboundHandler 是 volatile,就是异变的,为什么呢?因为它的OP_READ
(相关的讨论可以参见这里)可能被改变,所以要同步。所以这里就用到了 java 的 synchronized 同步代码块,在每个 ProchantProxyHandler 的实例身上都有一个trafficLock
成员,当做锁来使用,这是一个 Object,如下:
final Object trafficLock = new Object();
2.2. 后端不可写,则前端不要读
当然,说的就是这段:
if (!outboundChannel.isWritable()) {
e.getChannel().setReadable(false);
}
转载请注明来自柳大的CSDN博客:Blog.CSDN.net/Poechant,微博:weibo.com/lauginhom
3. 连接可操作状态改变时触发 channelInterestChanged
public void channelInterestChanged(ChannelHandlerContext ctx,
ChannelStateEvent e)
throws Exception
简单说,就是“This function was invoked when aChannel
'sinterestOps
was changed.” 那什么是interestOps
呢?
The interestOps value which tells that only read operation has been suspended.
org.jboss.netty.channel.Channel.OP_NONE
org.jboss.netty.channel.Channel.OP_READ
org.jboss.netty.channel.Channel.OP_WRITE
org.jboss.netty.channel.Channel.OP_READ_WRITE
他们的取值范围如下:
Modifier and Type
Constant Field
Value
public static final int |
OP_NONE |
0 = 0000 |
public static final int |
OP_READ |
1 = 0001 |
public static final int |
OP_WRITE |
4 = 0100 |
public static final int |
OP_READ_WRITE |
5 = 0101 |
前端连接可写时,后端连接就需要可读。
@Override
public void channelInterestChanged(ChannelHandlerContext ctx,
ChannelStateEvent e) throws Exception {
synchronized (trafficLock) {
if (e.getChannel().isWritable()) {
if (outboundChannel != null) {
outboundChannel.setReadable(true);
}
}
}
}
转载请注明来自柳大的CSDN博客:Blog.CSDN.net/Poechant,微博:weibo.com/lauginhom
4. 后端连接的 ChannelPipelineHandler
后端连接有相应的 Handler,在创建后端连接时:
ClientBootstrap cb = new ClientBootstrap(cf);
cb.getPipeline().addLast("handler", new OutboundHandler(e.getChannel()));
所以可如下定义:
private class OutboundHandler extends SimpleChannelUpstreamHandler {
private final Channel inboundChannel;
OutboundHandler(Channel inboundChannel) {
this.inboundChannel = inboundChannel;
}
public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e)
throws Exception {…}
public void channelInterestChanged(ChannelHandlerContext ctx,
ChannelStateEvent e) throws Exception {…}
}
其中 messageReceived 和 channelInterestChanged 的实现方式如下:
@Override
public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e)
throws Exception {
ChannelBuffer msg = (ChannelBuffer) e.getMessage();
synchronized (trafficLock) {
inboundChannel.write(msg);
if (!inboundChannel.isWritable()) {
e.getChannel().setReadable(false);
}
}
}
@Override
public void channelInterestChanged(ChannelHandlerContext ctx,
ChannelStateEvent e) throws Exception {
synchronized (trafficLock) {
if (e.getChannel().isWritable()) {
inboundChannel.setReadable(true);
}
}
}
这里可以概括一下。
if
and if
then
frontendchannelOpen
|
N/A |
set frontend writable |
frontendmessageReceived
|
backend nonwritable |
set frontend nonreadable |
frontendchannelInterestChanged
|
frontend writable |
set backend readable |
backendmessageReceived
|
frontend nonwritable |
set backend nonreadable |
backendchannelInterestChanged
|
backend writable |
set frontend readable |
可以看到:
- 当一方收到消息时,关心的是另一方可不可写,如果另一方不可写则设置该方不可读(因为收到消息,自己一定是可读的,而对方的读状态不需考虑);
- 当一方
interestOps
改变时,关心的是自己是否变成可写,如果自己可写则设置对方可读(因为自己的读状态,只需要到messageReceived
时考虑即可,而对于自己变成不可写这种情况,在messageReceived
中已经考虑了)。
-
转载请注明来自柳大的CSDN博客:Blog.CSDN.net/Poechant,微博:weibo.com/lauginhom
-
分享到:
相关推荐
基于Netty实现的内网穿透&反向代理的工具 (支持TCP上层协议和HTTP的穿透式反向代理).zip
该项目是一款基于Netty框架开发的Java内网穿透与反向代理工具设计源码,总计包含117个文件,涵盖70个Java源文件、9个PNG图片文件、8个XML配置文件、4个Markdown文件、4个CRT证书文件、3个HTML文件以及少量其他类型...
在TCP(传输控制协议)方面,Netty提供了全面的API来创建服务器和客户端。TCP是一种面向连接的、可靠的传输协议,确保数据的顺序和完整性。使用Netty,你可以创建服务器Bootstrap,配置监听端口,然后绑定一个...
netty搭建tcp自定义协议websocket服务器, 支持ssl demo. 适用于netty初学者, netty搭建自定义协议, websocket服务器, 聊天室, 一个端口集成多协议,包括ssl协议
Netty反向代理 使用 Netty 传输编写的反向代理 要运行该程序,请在位于 src/main/resources 目录内的 config.properties 文件中填写必要的属性,然后使用您的 IDE 运行 HexDumpProxy 类。 特性描述如下。 ...
利用netty实现Modbus TCP client/server READ COILS | 0x01 READ DISCRETE INPUTS | 0x02 READ HOLDING REGISTERS | 0x03 READ INPUT REGISTERS | 0x04 WRITE SINGLE COIL | 0x05 WRITE SINGLE REGISTER | 0x06 ...
5. 使用Spring的Service或Repository层处理业务逻辑,与Netty服务器交互。 通过这个示例项目,开发者可以学习到如何在Spring Boot应用中整合Netty,利用Netty的强大性能处理TCP通信,这对于构建高效、实时的后端...
使用Netty解决TCP粘包和拆包问题过程详解 Netty是一个流行的Java网络编程框架,提供了简洁、灵活的API来处理网络编程的各种问题。其中,解决TCP粘包和拆包问题是Netty的一个重要应用场景。本文将详细介绍使用Netty...
基于Netty框架的Socks5代理服务器 内容概要 本项目是一个基于Netty框架实现的Socks5代理服务器,支持Socks5协议的代理功能。项目包含了多个模块,涵盖了从客户端连接处理到服务器端代理转发的完整流程。主要功能...
reactor-netty, TCP/HTTP/UDP 客户机/服务器,带有联网的反应器 反应器联网 http://projectreactor.io/docs/netty/release/api/在软件许可证 2.0许可,,,。
使用SpringBoot2.x集成Netty4.x创建基于TCP/IP协议的服务端和客户端的Demo代码案例 使用了SpringBoot+swaggerUI方式进行测试,客户端可以给服务端发送消息,服务端也可以给已经连上的客户端发送消息,使用了通道保活...
Netty是一个高性能、异步事件驱动的网络应用程序框架,常用于开发高并发、低延迟的网络应用,如TCP服务器。而Kafka是一款分布式流处理平台,它在大数据实时处理和消息传递中扮演着核心角色。 标题"使用netty实现TCP...
Netty是一个高性能、异步事件驱动的网络应用程序框架,常用于开发服务器和客户端的网络应用,如TCP、UDP和HTTP等协议的通信。内网穿透工具,又称为NAT穿透,是一种允许内网设备通过公网进行通信的技术,这对于测试、...
本话题将探讨如何使用C++客户端与Java(通过Netty框架)服务器端实现TCP通讯,并涉及数据序列化工具Protocol Buffers(protobuf)在两者之间的交互。 首先,TCP(传输控制协议)是一种面向连接的、可靠的、基于字节...
在这个项目中,开发者使用Java和Netty框架实现了Socks5代理服务器,并结合了TLS加密,从而创建了一个安全的代理服务。具体实现可能包括以下步骤: 1. **设计协议解析器**:Netty的ChannelHandlerContext和...
本文将深入探讨如何使用Java的Netty框架实现一个基于DTU(Data Transfer Unit)的TCP服务器,该服务器具备多端口通信和多协议解析的能力。 首先,DTU是一种专门用于远程数据传输的设备,它能够通过GPRS、3G/4G等...
在本文中,我们将深入探讨如何利用 Netty 实现一个端口同时支持 TCP 和 WebSocket,从而减少资源消耗并简化服务器配置。 TCP(传输控制协议)是一种面向连接的、可靠的传输层协议,它保证了数据的顺序传输和错误...
Netty实现TCP服务
springboot集成netty实现代理服务器,实现http和https请求的代理功能
反向代理 通过Netty基于Java NIO的https代理服务器的实现。 这是一个简单的工作原理: 要通过浏览器对其进行测试,我们将需要设置一个虚拟主机名... 为了向后端的Web服务器应用程序提供反向代理,我创建了一个Flask