Netty FixedChannelPool
如今越来越多的应用采用Netty作为服务端高性能异步通讯框架,对于客户端而言,大部分需求只需和服务端建立一条链接收发消息。但如果客户端需要和服务端建立多条链接的例子就比较少了。
最简单的实现就是一个for循环,建立多个NioEventLoopGroup与服务端交互。另外还有如果要和多个服务端进行交互又该如何解决。
其实Netty从4.0版本就提供了连接池ChannelPool,可以解决与多个服务端交互以及与单个服务端建立连接池的问题。

服务端代码
首先我们完成服务端的代码,用户测试客户端的连接池。服务端不需要做任何特殊处理,代码如下。
package tk.yuqibit.nio.pool;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
public class NettyServer {
public void run(final int port) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter))
.addLast(new StringDecoder()).addLast(new StringEncoder())
.addLast(new DefaultEventExecutorGroup(8),
new NettyServerHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture future = b.bind(port).sync();
future.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 8080;
if (args.length > 0) {
try {
port = Integer.parseInt(args[0]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
new NettyServer().run(port);
}
}
服务端Handler,打印客户端发送的字符串,并回复另一个字符串
package tk.yuqibit.nio.pool;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by YuQi on 2017/7/31.
*/
public class NettyServerHandler extends SimpleChannelInboundHandler<Object> {
static AtomicInteger count = new AtomicInteger(1);
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActived");
super.channelActive(ctx);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
String body = (String) msg;
System.out.println(count.getAndIncrement() + ":" + body);
ctx.writeAndFlush("Welcome to Netty.$_");
}
}
客户端代码
重点是以下客户端代码,首先要实现自己的ChannelPoolHandler,主要是channelCreated,当链接创建的时候添加channelhandler。
package tk.yuqibit.nio.pool;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.pool.ChannelPoolHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* Created by YuQi on 2017/7/31.
*/
public class NettyChannelPoolHandler implements ChannelPoolHandler {
@Override
public void channelReleased(Channel ch) throws Exception {
System.out.println("channelReleased. Channel ID: " + ch.id());
}
@Override
public void channelAcquired(Channel ch) throws Exception {
System.out.println("channelAcquired. Channel ID: " + ch.id());
}
@Override
public void channelCreated(Channel ch) throws Exception {
ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());
System.out.println("channelCreated. Channel ID: " + ch.id());
SocketChannel channel = (SocketChannel) ch;
channel.config().setKeepAlive(true);
channel.config().setTcpNoDelay(true);
channel.pipeline()
.addLast(new DelimiterBasedFrameDecoder(1024, delimiter))
.addLast(new StringDecoder()).addLast(new StringEncoder()).addLast(new NettyClientHander());
}
}
客户端Handler,打印服务端的response。
package tk.yuqibit.nio.pool;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.concurrent.atomic.AtomicInteger;
public class NettyClientHander extends ChannelInboundHandlerAdapter {
static AtomicInteger count = new AtomicInteger(1);
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println(count.getAndIncrement() + ":" + msg);
}
}
客户端实现连接池,其中ChannelPoolMap可用于与多个服务端建立链接,本例中采用FixedChannelPool建立与单个服务端最大连接数为2的连接池。在main函数里通过向连接池获取channel发送了十条消息。
package tk.yuqibit.nio.pool;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.pool.AbstractChannelPoolMap;
import io.netty.channel.pool.ChannelPoolMap;
import io.netty.channel.pool.FixedChannelPool;
import io.netty.channel.pool.SimpleChannelPool;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import java.net.InetSocketAddress;
/**
* Created by YuQi on 2017/7/31.
*/
public class NettyPoolClient {
final EventLoopGroup group = new NioEventLoopGroup();
final Bootstrap strap = new Bootstrap();
InetSocketAddress addr1 = new InetSocketAddress("127.0.0.1", 8080);
InetSocketAddress addr2 = new InetSocketAddress("10.0.0.11", 8888);
ChannelPoolMap<InetSocketAddress, SimpleChannelPool> poolMap;
public void build() throws Exception {
strap.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_KEEPALIVE, true);
poolMap = new AbstractChannelPoolMap<InetSocketAddress, SimpleChannelPool>() {
@Override
protected SimpleChannelPool newPool(InetSocketAddress key) {
return new FixedChannelPool(strap.remoteAddress(key), new NettyChannelPoolHandler(), 2);
}
};
}
public static void main(String[] args) throws Exception {
NettyPoolClient client = new NettyPoolClient();
client.build();
final String ECHO_REQ = "Hello Netty.$_";
for (int i = 0; i < 10; i++) {
// depending on when you use addr1 or addr2 you will get different pools.
final SimpleChannelPool pool = client.poolMap.get(client.addr1);
Future<Channel> f = pool.acquire();
f.addListener((FutureListener<Channel>) f1 -> {
if (f1.isSuccess()) {
Channel ch = f1.getNow();
ch.writeAndFlush(ECHO_REQ);
// Release back to pool
pool.release(ch);
}
});
}
}
}
输出结果
首先启动服务端,然后启动客户端,for循环里向服务端发送了10条消息。
服务端的输出如下,可以看到总共与服务端建立了两个channel,收到10条消息。
channelActived
channelActived
1:Hello Netty.
2:Hello Netty.
3:Hello Netty.
4:Hello Netty.
5:Hello Netty.
6:Hello Netty.
7:Hello Netty.
8:Hello Netty.
9:Hello Netty.
10:Hello Netty.
客户端输入如下,可以看到channelCreated了两次,剩下都是从连接池里请求连接和释放连接
channelCreated. Channel ID: ea8504a8
channelCreated. Channel ID: 77c8857b
channelReleased. Channel ID: ea8504a8
channelReleased. Channel ID: 77c8857b
channelAcquired. Channel ID: ea8504a8
channelAcquired. Channel ID: 77c8857b
channelReleased. Channel ID: ea8504a8
channelReleased. Channel ID: 77c8857b
channelAcquired. Channel ID: 77c8857b
channelAcquired. Channel ID: ea8504a8
channelReleased. Channel ID: ea8504a8
channelAcquired. Channel ID: ea8504a8
channelReleased. Channel ID: 77c8857b
channelReleased. Channel ID: ea8504a8
channelAcquired. Channel ID: 77c8857b
channelAcquired. Channel ID: ea8504a8
channelReleased. Channel ID: 77c8857b
channelAcquired. Channel ID: 77c8857b
channelReleased. Channel ID: ea8504a8
channelReleased. Channel ID: 77c8857b
1:Welcome to Netty.
2:Welcome to Netty.
3:Welcome to Netty.
4:Welcome to Netty.
5:Welcome to Netty.
6:Welcome to Netty.
7:Welcome to Netty.
8:Welcome to Netty.
9:Welcome to Netty.
10:Welcome to Netty.
Netty FixedChannelPool的更多相关文章
- 教你正确地利用Netty建立连接池
一.问题描述 Netty是最近非常流行的高性能异步通讯框架,相对于Java原生的NIO接口,Netty封装后的异步通讯机制要简单很多. 但是小K最近发现并不是所有开发人员在使用的过程中都了解其内部实现 ...
- Netty自带连接池的使用
一.类介绍1.ChannelPool——连接池接口 2.SimpleChannelPool——实现ChannelPool接口,简单的连接池实现 3.FixedChannelPool——继承Simple ...
- 谈谈如何使用Netty开发实现高性能的RPC服务器
RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议.说的再直白一点,就是客户端在不必知道 ...
- 基于netty http协议栈的轻量级流程控制组件的实现
今儿个是冬至,所谓“冬大过年”,公司也应景五点钟就放大伙儿回家吃饺子喝羊肉汤了,而我本着极高的职业素养依然坚持留在公司(实则因为没饺子吃没羊肉汤喝,只能呆公司吃食堂……).趁着这一个多小时的时间,想跟 ...
- 从netty-example分析Netty组件续
上文我们从netty-example的Discard服务器端示例分析了netty的组件,今天我们从另一个简单的示例Echo客户端分析一下上个示例中没有出现的netty组件. 1. 服务端的连接处理,读 ...
- 源码分析netty服务器创建过程vs java nio服务器创建
1.Java NIO服务端创建 首先,我们通过一个时序图来看下如何创建一个NIO服务端并启动监听,接收多个客户端的连接,进行消息的异步读写. 示例代码(参考文献[2]): import java.io ...
- 从netty-example分析Netty组件
分析netty从源码开始 准备工作: 1.下载源代码:https://github.com/netty/netty.git 我下载的版本为4.1 2. eclipse导入maven工程. netty提 ...
- Netty实现高性能RPC服务器优化篇之消息序列化
在本人写的前一篇文章中,谈及有关如何利用Netty开发实现,高性能RPC服务器的一些设计思路.设计原理,以及具体的实现方案(具体参见:谈谈如何使用Netty开发实现高性能的RPC服务器).在文章的最后 ...
- Netty构建分布式消息队列(AvatarMQ)设计指南之架构篇
目前业界流行的分布式消息队列系统(或者可以叫做消息中间件)种类繁多,比如,基于Erlang的RabbitMQ.基于Java的ActiveMQ/Apache Kafka.基于C/C++的ZeroMQ等等 ...
随机推荐
- JWT攻击手册
JSON Web Token(JWT)对于渗透测试人员而言可能是一种非常吸引人的攻击途径,因为它们不仅是让你获得无限访问权限的关键,而且还被视为隐藏了通往以下特权的途径:特权升级,信息泄露,SQLi, ...
- 你不知道的Golang map
在开发过程中,map是必不可少的数据结构,在Golang中,使用map或多或少会遇到与其他语言不一样的体验,比如访问不存在的元素会返回其类型的空值.map的大小究竟是多少,为什么会报"can ...
- 「你学习,我买单」i春秋四周年精品课程福利专场
i春秋:中国专业的网络安全在线教育平台,累计用户超过60万. i春秋课程:资深专家团队教研支持,人才培养结合企业需求,针对不同岗位和技术方向的课程总计:600+门,1500+章,5700+节,时长74 ...
- 轻量级流程图控件GoJS示例连载(一):最小化
GoJS是一款功能强大,快速且轻量级的流程图控件,可帮助你在JavaScript 和 HTML5 Canvas程序中创建流程图,且极大地简化你的JavaScript / Canvas 程序. 慧都网小 ...
- swift(二)swift字符串和字符和逻辑运算
/* 1.swift字符串和字符 2.构造字符串 3.字符串比较 4.数值运算 5.复制运算 6.关系运算 7.逻辑运算 8.区间运算 */ /* //数据 + 数据的处理 //字符信息+ 字符信息的 ...
- RIP路由协议:基础设置/通信练习/兼容问题
RIP工作原理 首先路由器学习到直连网段 路由器开始运行RIP,当路由器的更新周期30秒到了的时候,会向邻居发送路由表 Metric:度量值,衡量一条路由好坏的值.发送路由表时Metric值会加1 学 ...
- java引用的强制转型
在java的面向对象的特性里,父类的引用可以指向子类的实例对象.但是,如果一个引用b(b本身指向了一个对象)想赋值给引用a,b不是a的类型且不是a的子类类型,那么就需要强制转换,并有失败的可能性,这个 ...
- kibana和中文分词器analysis-ik的安装使用
Centos7安装elasticSearch6 上面讲述了elasticSearch6的安装和使用教程. 下面讲一下elasticsearch6的管理工具Kibana. Kibana是一个开源的分析和 ...
- 逆向破解之160个CrackMe —— 010-011
CrackMe —— 010 160 CrackMe 是比较适合新手学习逆向破解的CrackMe的一个集合一共160个待逆向破解的程序 CrackMe:它们都是一些公开给别人尝试破解的小程序,制作 c ...
- conan使用(三)--打包只有头文件的库
参考:https://docs.conan.io/en/latest/howtos/header_only.html?highlight=header%20only 对于只含头文件的库打包非常简单,以 ...