netty常用使用方式
最近在重新看netty,在这里总结一些netty的一些常用的使用方式,类似于模板,方便速查。
以netty 4.1.x的API作记录,不同版本可能API有略微差异,需要注意netty5被废弃掉了(辨别方式是看SimpleChannelInboundHandler是否有一个messageReceived方法 有的话就是5),netty3是以org.jboss开头为包名。
统一模板
大多数情况下使用netty的步骤是定义好EventLoopGroup,定义好Bootstrap(ServerBootstrap)以及使用的channel类型(一般就是NioSocketChannel,服务端是NioServerSocketChannel)。
剩下是业务相关,使用的ChannelInitializer和具体的handler。
主要就是2+N(N为自定义的handler数量)个类。
服务端启动模板(也可以不区分boss和worker 用一个):
public static void main(String[] args) throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new MyChannelInitializer());
ChannelFuture future = serverBootstrap.bind(8999).sync();
future.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
客户端启动模板:
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new MyChannelInitializer());
ChannelFuture future = bootstrap.connect("localhost", 8888).sync();
future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
ChannelInitializer模板(继承ChannelInitializer即可):
public class MyChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(...);
}
}
接下来的例子就以这个模板为骨架,主要涉及到初始化器的代码,启动代码一致。
处理Http请求
netty自带了对用的codec类比较方便。
pipeline.addLast("httpServerCodec", new HttpServerCodec());
自己实现的handler最简单的方式用SimpleChannelInboundHandler接收HttpRequest方法即可
class MyHttpHandler extends SimpleChannelInboundHandler<HttpRequest>
这里简单说下SimpleChannelInboundHandler这个类,他是简化处理接受信息并处理的一个类,主要做两件事。
第一件事是根据泛型决定是否处理这个消息,能够处理就自己处理,不行就交给下一个(可以参考acceptInboundMessage和channelRead方法)。
第二件事是消息的自动回收(有构造函数支持 默认是true),消息的引用计数会减一(所以在其他地方还要使用记得再retain一下)。
使用它可以节省很多冗余代码的编写。
一个简单例子:
public class MyHttpHandler extends SimpleChannelInboundHandler<HttpRequest> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) throws Exception {
System.out.println(msg.getClass());
System.out.println(msg.uri());
System.out.println(msg.method().name());
System.out.println(ctx.channel().remoteAddress());
System.out.println("headers:");
msg.headers().forEach(System.out::println);
ByteBuf buf = Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8);
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes());
ctx.writeAndFlush(response);
// ctx.channel().close();
}
}
不过只用这个handler并不能拿到content,还需要配合ChunkedWriteHandler和HttpObjectAggregator得到FullHttpRequest对象。
处理WebSocket请求
只需要在上面的基础上增加一个WebSocketServerProtocolHandler即可,完整如下:
pipeline.addLast("httpServerCodec", new HttpServerCodec());
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new HttpObjectAggregator(8096));
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
自己的处理器可以接收并处理WebSocketFrame的子类。
自定义文本协议
netty提供了几个比较方便的用于自定义文本协议的编解码器。
基于长度
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new MyHandler());
上述参数的意义直接搬了文档:
lengthFieldOffset = 0
lengthFieldLength = 2
lengthAdjustment = 0
initialBytesToStrip = 2 (= the length of the Length field)
BEFORE DECODE (14 bytes) AFTER DECODE (12 bytes)
+--------+----------------+ +----------------+
| Length | Actual Content |----->| Actual Content |
| 0x000C | "HELLO, WORLD" | | "HELLO, WORLD" |
+--------+----------------+ +----------------+
基于分隔符
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(4096, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
第二个参数需要一个ByteBuf[],自己指定下分隔符即可。
注意使用这种发消息的时候要带上那个分隔符,不然会处理失败(被当做未结束)。
广播实现
利用了netty提供的一个很便利的类,ChannelGroup.
首先要了解一下Channel生命周期函数的调用:
channel added -> channel registered -> channel active -> channel inactive -> channel unregistered -> channel removed
我们可以定义一个静态(保证共享和唯一)的ChannelGroup在channel added的时候把对应channel增加到ChannelGroup中即可(但不需要自己移除,这一点他自己实现了)
然后利用它的写方法就可以实现广播,或者forEach做下过滤做多播也可以。
这个实现和用什么协议无关,主要涉及到ChannelGroup使用。
心跳
netty自带的IdleStateHandler,超时后会向下一个handler发出IdleStateEvent消息,接收并处理即可。
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
super.userEventTriggered(ctx, evt);
if (evt instanceof IdleStateEvent) {
ctx.channel().writeAndFlush("超时").addListener((ChannelFuture ch) -> ch.channel().close());
}
}
它细分为3中类型的超时,读、写、读写,通过IdleStateEvent的state属性可以获取,可以单独判断。
其他的一些模式会在之后复习和使用过程中不断补完~
2017年10月08日00点53分 init
2017年10月10日10点02分 更新websocket
netty常用使用方式的更多相关文章
- jQuery中ajax的4种常用请求方式
jQuery中ajax的4种常用请求方式: 1.$.ajax()返回其创建的 XMLHttpRequest 对象. $.ajax() 只有一个参数:参数 key/value 对象,包含各配置及回调函数 ...
- iOS代码加密常用加密方式
iOS代码加密常用加密方式 iOS代码加密常用加密方式,常见的iOS代码加密常用加密方式算法包括MD5加密.AES加密.BASE64加密,三大算法iOS代码加密是如何进行加密的,且看下文 MD5 iO ...
- DataGridView 中添加CheckBox和常用处理方式 .
DataGridView 中添加CheckBox和常用处理方式 文章1 转载:http://blog.csdn.net/pinkey1987/article/details/5267934 DataG ...
- python常用执行方式&变量&input函数
linux系统中执行py文件方式: ./a.py 需要执行权限 chmod -R 777(最大权限) 常用执行方式: 1. ./a.py2. python a.py 文件内部头加上 #!/usr/b ...
- Linux 常用分区方式
1 分两个区 主目录:/ 交换分区:swap 2 常用分区方式,以使用100G空间安装linux为例 引导分区: 挂载点/boot,分区格式ext4,500M以内即可 交换分区: 无挂载点,分区格式选 ...
- python-django-ORM,常用查询方式
介绍django model 的一些常用查询方式 首先是一些文档性的帮助 __exact 精确等于 like ‘aaa’ __iexact 精确等于 忽略大小写 ilike ‘aaa’ __conta ...
- 【转】Verilog HDL常用建模方式——《Verilog与数字ASIC设计基础》读书笔记(四)
Verilog HDL常用建模方式——<Verilog与数字ASIC设计基础>读书笔记(四) Verilog HDL的基本功能之一是描述可综合的硬件逻辑电路.所谓综合(Synthesis) ...
- 前后端常用通讯方式-- ajax 、websocket
一.前后端常用通讯方式 1. ajax 浏览器发起请求,服务器返回数据,服务器不能主动返回数据,要实现实时数据交互只能是ajax轮询(让浏览器隔个几秒就发送一次请求,然后更新客户端显示.这种方式实际 ...
- SoapUI 的几种常用参数化方式
今天给大家来梳理下soapui这款工具关于参数化的几种方式以及具体的应用场景 1.properties 官方文档:https://www.soapui.org/docs/functional-test ...
随机推荐
- hdu 1542 线段树 求矩形并
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- spring框架总结(01)
1.spring是什么? sprint其实就是一个开源框架,是于2003年兴起的一个轻量级的java开发框架,是有Road Johnson创建的,简单的来说spring是一个分层的JavaSE/EE( ...
- 运行Vue在ASP.NET Core应用程序并部署在IIS上
前言 项目一直用的ASP.NET Core,但是呢我对ASP.NET Core一些原理也还未开始研究,仅限于会用,不过园子中已有大量文章存在,借着有点空余时间,我们来讲讲如何利用ASP.NET Cor ...
- 在jsp页面的js中使用Cookie的原理介绍以及相应方法的代码
1. 设置cookie 1.1 每个cookie都是一个名/值对,可以把下面这样一个字符串赋值给document.cookie: document.cookie="user_Id=828&q ...
- ActiveMQ——activemq的安装详情,修改密码
1.安装 下载 http://activemq.apache.org/download-archives.html, [推荐]ActiveMQ 5.13.4 Release与jdk1.7搭配(其它版本 ...
- 第八章 关于SQL查询出错的一些问题
问题一:在使用MySQL使用传参查询并返回结果集时,没错,小伙伴们都知道少不了Statement接口和PreparedStatement对象.问题来了,有时竟然查询不了,Debug进去,发现执行的SQ ...
- ASP.NET Core 认证与授权[3]:OAuth & OpenID Connect认证
在上一章中,我们了解到,Cookie认证是一种本地认证方式,通常认证与授权都在同一个服务中,也可以使用Cookie共享的方式分开部署,但局限性较大,而如今随着微服务的流行,更加偏向于将以前的单体应用拆 ...
- CSS3动画 transition和animation的用法和区别
transition和animation都是CSS3新增的特性,使用时需要加内核 浏览器 内核名称 W3C IE -ms- Chrome/Safari -webkit- Firefoc - ...
- CSS组件
下拉菜单 .dropdown:将下拉菜单触发器和下拉菜单包含在其中 .dropdown-menu:给<ul>制定下拉菜单的样式 .dropup:向上弹出菜单 .dropdown-menu- ...
- JS难点--面向对象(继承)
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Consolas; color: #a5b2b9 } 继承 让一个对象拥有另一个对象的属性或者 ...