Practical Netty (5) TCP反向代理服务器
- 作者:柳大·Poechant(钟超)
- 邮箱:zhongchao.ustc#gmail.com(# -> @)
- 博客:Blog.CSDN.net/Poechant
- 微博:weibo.com/lauginhom
- 日期:June 11th, 2012
以下针对 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 a Channel
's interestOps
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
他们的取值范围如下:
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);
}
}
}
这里可以概括一下。
frontend channelOpen
|
N/A | set frontend writable |
frontend messageReceived
|
backend nonwritable | set frontend nonreadable |
frontend channelInterestChanged
|
frontend writable | set backend readable |
backend messageReceived
|
frontend nonwritable | set backend nonreadable |
backend channelInterestChanged
|
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实现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 ...
Netty反向代理 使用 Netty 传输编写的反向代理 要运行该程序,请在位于 src/main/resources 目录内的 config.properties 文件中填写必要的属性,然后使用您的 IDE 运行 HexDumpProxy 类。 特性描述如下。 ...
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穿透,是一种允许内网设备通过公网进行通信的技术,这对于测试、...
在这个项目中,开发者使用Java和Netty框架实现了Socks5代理服务器,并结合了TLS加密,从而创建了一个安全的代理服务。具体实现可能包括以下步骤: 1. **设计协议解析器**:Netty的ChannelHandlerContext和...
本话题将探讨如何使用C++客户端与Java(通过Netty框架)服务器端实现TCP通讯,并涉及数据序列化工具Protocol Buffers(protobuf)在两者之间的交互。 首先,TCP(传输控制协议)是一种面向连接的、可靠的、基于字节...
本文将深入探讨如何使用Java的Netty框架实现一个基于DTU(Data Transfer Unit)的TCP服务器,该服务器具备多端口通信和多协议解析的能力。 首先,DTU是一种专门用于远程数据传输的设备,它能够通过GPRS、3G/4G等...
在本文中,我们将深入探讨如何利用 Netty 实现一个端口同时支持 TCP 和 WebSocket,从而减少资源消耗并简化服务器配置。 TCP(传输控制协议)是一种面向连接的、可靠的传输层协议,它保证了数据的顺序传输和错误...
【可靠有效】springboot使用netty搭建TCP服务器
Spring Boot集成Netty创建一个TCP服务器,接收16进制数据(自定义解码器和编码器)。
Netty实现TCP服务