netty系列之:netty中常用的字符串编码解码器
简介
字符串是我们程序中最常用到的消息格式,也是最简单的消息格式,但是正因为字符串string太过简单,不能附加更多的信息,所以在netty中选择的是使用byteBuf作为最底层的消息传递载体。
虽然底层使用的ByteBuf,但是对于程序员来说,还是希望能够使用这种最简单的字符串格式,那么有什么简单的方法吗?
netty中的字符串编码解码器
为了解决在netty的channel中传递字符串的问题,netty提供了针对于字符串的编码和解码器,分别是StringEncoder和StringDecoder。
我们来看下他们是怎么在程序中使用的,首先是将StringDecoder和StringEncoder加入channelPipeline中:
ChannelPipeline pipeline = ...;
// Decoders
pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(80));
pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8));
// Encoder
pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8));
注意,这里我们在使用StringDecoder之前还调用了LineBasedFrameDecoder,先把数据按行进行分割,然后再进行字符串的读取。
那么有人要问了,decoder加入了LineBasedFrameDecoder预处理,为什么写入的时候没有添加行的分割符呢?
事实上这里有两种处理方式,第一种就是在向channel中写入字符串的时候,手动加上行分隔符,如下所示:
void channelRead(ChannelHandlerContext ctx, String msg) {
ch.write("Did you say '" + msg + "'?\n");
}
如果不想每次都在msg后面加上换行符,那么可以将StringEncoder替换成为LineEncoder,上面的pipeline就变成下面这样:
ChannelPipeline pipeline = ...;
// Decoders
pipeline.addLast("frameDecoder", new LineBasedFrameDecoder(80));
pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8));
// Encoder
pipeline.addLast("lineEncoder", new LineEncoder(LineSeparator.UNIX, CharsetUtil.UTF_8));
这样,我们在handler中就不需要手动添加换行符了,如下所示:
void channelRead(ChannelHandlerContext ctx, String msg) {
ch.write("Did you say '" + msg + "'?");
}
不同平台的换行符
在unix和windows平台传递过文本文件的朋友可能会遇到一个问题,就是windows创建的文本文件,如果在unix下面打开的话,会发现每行后面多出了一个特殊字符,这是因为unix和windows平台定义的换行符是不同的。
在unix平台通常使用"\n"来换行,而在windows平台则使用""\r\n"来换行。
java程序因为是跨平台的,写出的程序可能运行在unix平台,也可能运行在windows平台,所以我们需要有一个办法来获取平台的换行符,netty提供了一个LineSeparator的类来完成这个工作。
LineSeparator中有三个换行符的定义,分别是:
public static final LineSeparator DEFAULT = new LineSeparator(StringUtil.NEWLINE);
public static final LineSeparator UNIX = new LineSeparator("\n");
public static final LineSeparator WINDOWS = new LineSeparator("\r\n");
UNIX和WINDOWS很好理解,他们就是我们刚刚讲到的不同的平台。
那么什么是DEFAULT呢?DEFAULT中传入的NEWLINE,实际上是从系统属性中获取到的,如果没有获取到,则使用默认的"\n"。
public static final String NEWLINE = SystemPropertyUtil.get("line.separator", "\n");
字符串编码的实现
上面我们讲到了和字符串编码解码相关的类分别是StringEncoder,LineEncoder和StringDecoder,我们来详细看下这三个类的实现。
首先是StringEncoder,StringEncoder继承了MessageToMessageEncoder:
public class StringEncoder extends MessageToMessageEncoder<CharSequence>
泛型中的CharSequence表示StringEncoder要encode的对象是CharSequence,也就是字符序列。
虽然大家常用String这个类,但是不一定大家都知道String其实是CharSequence的子类,所以StringEncoder也可以编码字符串。
StringEncoder的编码逻辑很简单,将传入的字符串msg转换成为CharBuffer,然后调用ByteBufUtil的encodeString方法就可以转换成为ByteBuf,并加入out中去:
protected void encode(ChannelHandlerContext ctx, CharSequence msg, List<Object> out) throws Exception {
if (msg.length() == 0) {
return;
}
out.add(ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(msg), charset));
}
LineEncoder和StringEncoder很类似,它也是继承自MessageToMessageEncoder:
public class LineEncoder extends MessageToMessageEncoder<CharSequence>
不同之处在于encoder方法:
protected void encode(ChannelHandlerContext ctx, CharSequence msg, List<Object> out) throws Exception {
ByteBuf buffer = ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(msg), charset, lineSeparator.length);
buffer.writeBytes(lineSeparator);
out.add(buffer);
}
ByteBufUtil的encodeString多了一个lineSeparator.length参数,用来预留lineSeparator的位置,然后在返回的ByteBuf后面加上lineSeparator作为最终的输出。
StringDecoder是和StringEncoder相反的过程:
public class StringDecoder extends MessageToMessageDecoder<ByteBuf>
这里的ByteBuf表示的是要解码的对象是ByteBuf,我们看下他的解码方法:
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
out.add(msg.toString(charset));
}
直接调用msg.toString方法即可将ByteBuf转换成为字符串。
总结
以上就是netty中对字符串的编码解码器,通过使用这几个编码解码器可以大大简化我们的工作。
本文已收录于 http://www.flydean.com/14-6-netty-codec-string/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
netty系列之:netty中常用的字符串编码解码器的更多相关文章
- Netty 系列之 Netty 高性能之道 高性能的三个主题 Netty使得开发者能够轻松地接受大量打开的套接字 Java 序列化
Netty系列之Netty高性能之道 https://www.infoq.cn/article/netty-high-performance 李林锋 2014 年 5 月 29 日 话题:性能调优语言 ...
- 【读后感】Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ?
[读后感]Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ? 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商 ...
- ES6系列之项目中常用的新特性
ES6系列之项目中常用的新特性 ES6常用特性 平时项目开发中灵活运用ES6+语法可以让开发者减少很多开发时间,提高工作效率.ES6版本提供了很多新的特性,接下来我列举项目中常用的ES6+的特性: l ...
- java中常用的字符串的截取方法
java中常用的字符串的截取方法 1.length() 字符串的长度 例:char chars[]={'a','b'.'c'}; String s=new String(chars); int l ...
- LoadRunner中常用的字符串操作函数
LoadRunner中常用的字符串操作函数有: strcpy(destination_string, source_string); strc ...
- Js中常用的字符串,数组,函数扩展
由于最近辞职在家,自己的时间相对多一点.所以就根据prototytpeJS的API,结合自己正在看的司徒大神的<javascript框架设计>,整理了下Js中常用一些字符串,数组,函数扩展 ...
- netty系列之:netty中常用的对象编码解码器
目录 简介 什么是序列化 重构序列化对象 序列化不是加密 使用真正的加密 使用代理 Serializable和Externalizable的区别 netty中对象的传输 ObjectEncoder O ...
- netty系列之:netty中各不同种类的channel详解
目录 简介 ServerChannel和它的类型 Epoll和Kqueue AbstractServerChannel ServerSocketChannel ServerDomainSocketCh ...
- netty系列之:netty中的核心编码器bytes数组
目录 简介 byte是什么 netty中的byte数组的工具类 netty中byte的编码器 总结 简介 我们知道netty中数据传输的核心是ByteBuf,ByteBuf提供了多种数据读写的方法,包 ...
随机推荐
- Math.round(11.5) 等于多少?Math.round(-11.5)等于 多少?
Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11.四舍五 入的原理是在参数上加 0.5 然后进行下取整.
- 怎么创建maven项目
1.Eclipse中用Maven创建项目 2.点击[next] 3.选maven-archetype-webapp后,next 4.填写相应的信息,Packaged是默认创建一个包,不写也可以 4右击 ...
- springboot使用策略模式实现一个基本的促销
策略模式 定义了算法族,分别封装起来,让它们之间可以互相替换, 此模式让算法的变化独立于使用算法的客户 源码:https://github.com/youxiu326/sb_promotion.git ...
- ElasticSearch-学习笔记01-docker安装
安装ElasticSearch docker 安装请参考: https://www.cnblogs.com/youxiu326/p/docker-01.html docker run -d --nam ...
- HTML5打造原生应用——Ionic框架简介与Ionic Hello World
试了试用Ionic框架打造了两个应用,然后在Google Play上架了. 程序语言答人 教你设计物联网 更有意思的是这是在一周的业余时间内完成的三个应用中的两个,接着让我们看看这个框架如何实现高效地 ...
- 深入理解 flex-grow & flex-shrink & flex-basis
前言 flex 有三个属性值,分别是 flex-grow, flex-shrink, flex-basis,默认值是 0 1 auto. 发现网上详细介绍他们的文章比较少, 今天就详细说说他们,先一个 ...
- 移动端调试工具weinre安装教程(java版)
先申明:本安装教程是基于java的jdk安装的,经过测试可以正常使用,基于nodejs的安装,小喵鼓弄了好几天也没有成功,如果哪位童鞋基于nodejs安装成功了,请联系小喵,小喵在这里先谢谢你了! 好 ...
- 纯JS实现KeyboardNav(学习笔记)二
纯JS实现KeyboardNav(学习笔记)二 这篇博客只是自己的学习笔记,供日后复习所用,没有经过精心排版,也没有按逻辑编写 这篇主要是添加css,优化js编写逻辑和代码排版 GitHub项目源码 ...
- Muse UI遇到的坑
写在前面:我只是一个前端小白,文章中的提到可能会有不足之处,仅提供一个参考.若有不完善的地方,欢迎各位大佬指出,希望对你有帮助! 故事背景是这样的,最近做一个Vue项目,使用到 Muse UI 组件库 ...
- java中抛出throw关键字是怎么用的? 举例?
5.抛出throw关键字 马克-to-win:我们先说5/0的原理,当程序运行到5/0的时候,java系统JVM会在后台new出一个除0异常实例,之后把这个实例传入catch块儿供开发者使用.马克-t ...