2019独角兽企业重金招聘Python工程师标准>>>

Netty实现自定义简单的编解码器(二)

关于编解码器请参见:http://my.oschina.net/xinxingegeya/blog/282878

主要思路:

* 实现了一个IntegerEncoder编码器和一个IntegerDecoder解码器

* 服务器端发送一个数字,此时客户端解码器会编码为一个字符串,发送到服务器端

* 服务器先用解码器解码字符串为整形,打印出来。然后服务器端通过服务器端编码器编码后向客户端发送数字

* 客户端通过客户端解码器解码后接收数据,打印出来

编码器

package codec2.encoder;import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;import java.util.List;public class IntegerEncoder extends MessageToMessageEncoder<Integer> {/*** encode Integer messages to String messages** @param ctx* @param msg* @param out* @throws Exception*/@Overridepublic void encode(ChannelHandlerContext ctx, Integer msg,List<Object> out) throws Exception {System.err.println("IntegerEncoder encode msg is " + msg);//把int转换为字节数组byte[] result = new byte[4];result[0] = (byte) (msg.intValue() >>> 24);//取最高8位放到0下标result[1] = (byte) (msg.intValue() >>> 16);//取次高8为放到1下标result[2] = (byte) (msg.intValue() >>> 8); //取次低8位放到2下标result[3] = (byte) (msg.intValue());      //取最低8位放到3下标ByteBuf encoded = ctx.alloc().buffer(Integer.BYTES);encoded.writeBytes(result);out.add(encoded);}
}

解码器

package codec2.decoder;import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;import java.util.List;public class IntegerDecoder extends MessageToMessageDecoder<ByteBuf> {@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf msg,List<Object> out) throws Exception {System.err.println("IntegerDecoder decode msg is " + msg);out.add(msg.readInt());}
}

服务器端程序

package codec2;import codec2.decoder.IntegerDecoder;
import codec2.encoder.IntegerEncoder;
import io.netty.bootstrap.ServerBootstrap;
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;/*** 主要思路:* 实现了一个IntegerEncoder编码器和一个IntegerDecoder解码器* 服务器端发送一个数字,此时客户端解码器会编码为一个字符串,发送到服务器端* 服务器先用解码器解码字符串为整形,打印出来。然后服务器端通过服务器端编码器编码后向客户端发送数字* 客户端通过客户端解码器解码后接收数据,打印出来*/
public class HelloServer {public void start(int port) throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 128).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {// 注册handlerch.pipeline().addLast(new IntegerEncoder(),new IntegerDecoder(),new HelloServerInHandler());}});ChannelFuture f = b.bind(port).sync();f.channel().closeFuture().sync();} finally {workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();}}public static void main(String[] args) throws Exception {HelloServer server = new HelloServer();server.start(12345);}
}
package codec2;import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;// 该handler是InboundHandler类型
public class HelloServerInHandler extends ChannelInboundHandlerAdapter {@Overridepublic boolean isSharable() {System.out.println("==============handler-sharable==============");return super.isSharable();}@Overridepublic void channelRegistered(ChannelHandlerContext ctx) throws Exception {System.out.println("==============channel-register==============");}@Overridepublic void channelUnregistered(ChannelHandlerContext ctx) throws Exception {System.out.println("==============channel-unregister==============");}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("==============channel-active==============");}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {System.out.println("==============channel-inactive==============");}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {System.out.println("==============channel-read==============");System.out.println("the msg type is " + msg.getClass().getName());Integer integer = (Integer) msg;System.out.println("服务器端接收到的客户端的数字是" + integer);System.out.println("服务器向客户端写入整型数字2001");ctx.writeAndFlush(new Integer(2001));ctx.close();}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {System.out.println("==============channel-read-complete==============");ctx.flush();}
}

客户端程序

package codec2;import codec2.decoder.IntegerDecoder;
import codec2.encoder.IntegerEncoder;
import io.netty.bootstrap.Bootstrap;
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.NioSocketChannel;/*** 主要思路:* 实现了一个IntegerToStringEncoder编码器和一个StringToIntegerDecoder解码器* 服务器端发送一个数字2000,此时客户端解码器会编码为一个字符串,发送到服务器端* 服务器先用解码器解码字符串为整形,打印出来。然后服务器端通过服务器端编码器编码后向客户端发送数字* 客户端通过客户端解码器解码后接收数据,打印出来*/
public class HelloClient {public void connect(String host, int port) throws Exception {EventLoopGroup workerGroup = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();b.group(workerGroup);b.channel(NioSocketChannel.class);b.option(ChannelOption.AUTO_READ, true);b.handler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new IntegerEncoder(),new IntegerDecoder(),new HelloClientIntHandler());}});ChannelFuture f = b.connect(host, port).sync();f.channel().closeFuture().sync();} finally {workerGroup.shutdownGracefully();}}public static void main(String[] args) throws Exception {HelloClient client = new HelloClient();client.connect("192.168.0.102", 12345);}
}
package codec2;import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;//InboundHandler类型
public class HelloClientIntHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRegistered(ChannelHandlerContext ctx) throws Exception {System.out.println("==============channel--register==============");}@Overridepublic void channelUnregistered(ChannelHandlerContext ctx) throws Exception {System.out.println("==============channel--unregistered==============");}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {System.out.println("==============channel--inactive==============");}// 连接成功后,向server发送消息@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("==============channel--active==============");System.out.println("向服务器端写入2000数字");ctx.writeAndFlush(new Integer(2000));}// 接收server端的消息,并打印出来@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {System.out.println("==============channel--read==============");System.out.println("the msg type is " + msg.getClass().getName());Integer result = (Integer) msg;System.out.println("接收到服务器数据,该数字是" + result);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();}
}

运行结果:

服务器端

==============handler-sharable==============

==============channel-register==============

==============channel-active==============

IntegerDecoder decode msg is SimpleLeakAwareByteBuf(UnpooledUnsafeDirectByteBuf(ridx: 0, widx: 4, cap: 1024))

IntegerEncoder encode msg is 2001

==============channel-read==============

the msg type is java.lang.Integer

服务器端接收到的客户端的数字是2000

服务器向客户端写入整型数字2001

==============channel-read-complete==============

==============channel-inactive==============

==============channel-unregister==============

客户端

==============channel--register==============

IntegerEncoder encode msg is 2000

==============channel--active==============

向服务器端写入2000数字

==============channel--read==============

the msg type is java.lang.Integer

接收到服务器数据,该数字是2001

==============channel--inactive==============

==============channel--unregistered==============

IntegerDecoder decode msg is UnpooledUnsafeDirectByteBuf(ridx: 0, widx: 4, cap: 1024)

Process finished with exit code 0

后记:

我想到netty中有两个现成的编解码器是StringEncoder和StringDecoder,看代码:

/** Copyright 2012 The Netty Project** The Netty Project licenses this file to you under the Apache License,* version 2.0 (the "License"); you may not use this file except in compliance* with the License. You may obtain a copy of the License at:**   http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the* License for the specific language governing permissions and limitations* under the License.*/
package io.netty.handler.codec.string;import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.MessageToMessageEncoder;import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.List;/*** Encodes the requested {@link String} into a {@link ByteBuf}.* A typical setup for a text-based line protocol in a TCP/IP socket would be:* <pre>* {@link ChannelPipeline} pipeline = ...;** // Decoders* pipeline.addLast("frameDecoder", new {@link LineBasedFrameDecoder}(80));* pipeline.addLast("stringDecoder", new {@link StringDecoder}(CharsetUtil.UTF_8));** // Encoder* pipeline.addLast("stringEncoder", new {@link StringEncoder}(CharsetUtil.UTF_8));* </pre>* and then you can use a {@link String} instead of a {@link ByteBuf}* as a message:* <pre>* void channelRead({@link ChannelHandlerContext} ctx, {@link String} msg) {*     ch.write("Did you say '" + msg + "'?\n");* }* </pre>*/
@Sharable
public class StringEncoder extends MessageToMessageEncoder<CharSequence> {// TODO Use CharsetEncoder instead.private final Charset charset;/*** Creates a new instance with the current system character set.*/public StringEncoder() {this(Charset.defaultCharset());}/*** Creates a new instance with the specified character set.*/public StringEncoder(Charset charset) {if (charset == null) {throw new NullPointerException("charset");}this.charset = charset;}@Overrideprotected 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));}
}
/** Copyright 2012 The Netty Project** The Netty Project licenses this file to you under the Apache License,* version 2.0 (the "License"); you may not use this file except in compliance* with the License. You may obtain a copy of the License at:**   http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the* License for the specific language governing permissions and limitations* under the License.*/
package io.netty.handler.codec.string;import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.MessageToMessageDecoder;import java.nio.charset.Charset;
import java.util.List;/*** Decodes a received {@link ByteBuf} into a {@link String}.  Please* note that this decoder must be used with a proper {@link ByteToMessageDecoder}* such as {@link DelimiterBasedFrameDecoder} or {@link LineBasedFrameDecoder}* if you are using a stream-based transport such as TCP/IP.  A typical setup for a* text-based line protocol in a TCP/IP socket would be:* <pre>* {@link ChannelPipeline} pipeline = ...;** // Decoders* pipeline.addLast("frameDecoder", new {@link LineBasedFrameDecoder}(80));* pipeline.addLast("stringDecoder", new {@link StringDecoder}(CharsetUtil.UTF_8));** // Encoder* pipeline.addLast("stringEncoder", new {@link StringEncoder}(CharsetUtil.UTF_8));* </pre>* and then you can use a {@link String} instead of a {@link ByteBuf}* as a message:* <pre>* void channelRead({@link ChannelHandlerContext} ctx, {@link String} msg) {*     ch.write("Did you say '" + msg + "'?\n");* }* </pre>*/
@Sharable
public class StringDecoder extends MessageToMessageDecoder<ByteBuf> {// TODO Use CharsetDecoder instead.private final Charset charset;/*** Creates a new instance with the current system character set.*/public StringDecoder() {this(Charset.defaultCharset());}/*** Creates a new instance with the specified character set.*/public StringDecoder(Charset charset) {if (charset == null) {throw new NullPointerException("charset");}this.charset = charset;}@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {out.add(msg.toString(charset));}
}

你看吧,传输String还得有编解码器。

所以就根据这对编解码器实现了上述编解码器。

===========END===========

转载于:https://my.oschina.net/xinxingegeya/blog/282987

Netty实现自定义简单的编解码器(二)相关推荐

  1. 07 接头暗语:如何利用 Netty 实现自定义协议通信?

    文章目录 07 接头暗语:如何利用 Netty 实现自定义协议通信? 通信协议设计 1. 魔数 2. 协议版本号 3. 序列化算法 4. 报文类型 5. 长度域字段 6. 请求数据 7. 状态 8. ...

  2. 07 | 接头暗语:如何利用 Netty 实现自定义协议通信?

    既然是网络编程,自然离不开通信协议,应用层之间通信需要实现各种各样的网络协议.在项目开发的过程中,我们就需要去构建满足自己业务场景的应用层协议.在上节课中我们介绍了如何使用网络协议解决 TCP 拆包/ ...

  3. 教你用 Netty 实现一个简单的 RPC!

    众所周知,dubbo 底层使用了 Netty 作为网络通讯框架,而 Netty 的高性能我们之前也分析过源码,对他也算还是比较了解了. 今天我们就自己用 Netty 实现一个简单的 RPC 框架. 1 ...

  4. Netty内置处理器以及编解码器

    一.Netty已经为我们提供了常用协议的处理器,我们直接使用就可以 可以看到包括redis协议,http协议等主流协议的编码解码器,netty都为我们提供了. 二.代码测试 使用netty直接对red ...

  5. RPC系列之Netty实现自定义RPC框架

    进行这个章节之前,需要去看一下RMI的实现哈,如果了解过的童鞋可以直接跳过,如果没有或者不知道RMI的童鞋,移驾到下面的链接看完之后再回来继续看这篇 RPC系列之入门_阿小冰的博客-CSDN博客RPC ...

  6. Netty实现自定义协议

    关于协议,使用最为广泛的是HTTP协议,但是在一些服务交互领域,其使用则相对较少,主要原因有三方面: HTTP协议会携带诸如header和cookie等信息,其本身对字节的利用率也较低,这使得HTTP ...

  7. Soul网关源码阅读(十)自定义简单插件编写

    Soul网关源码阅读(十)自定义简单插件编写 简介     综合前面所分析的插件处理流程相关知识,此次我们来编写自定义的插件:统计请求在插件链中的经历时长 编写准备     首先我们先探究一下,一个P ...

  8. easy-mock写的一个简单的模拟二页的反馈

    用easy-mock写的一个简单的模拟二页的反馈,因为后端团队比较传统,所以设计的结构不太规范. 功能:每页10条,共2页,共12条记录,超出参数范围会返错误码: easy模板: {code: fun ...

  9. XamarinAndroid组件教程设置自定义子元素动画(二)

    XamarinAndroid组件教程设置自定义子元素动画(二) (9)打开MainActivity.cs文件,为RecylerView的子元素设置添加和删除时的透明动画效果.代码如下: --using ...

最新文章

  1. Java并发编程之线程状态总结
  2. flume快速入门及应用
  3. linux查询日志中页面返回状态码,[linux shell] Shell脚本实现apache日志中的状态码分析...
  4. Linux:守护进程详解及实现
  5. c#官方推荐md5通用加密类
  6. 父、子、兄弟节点查找方法
  7. UI控件之UITextField
  8. x9此计算机上没有hasp_中琅条码打印软件安装后弹出HASP错误代码处理方法
  9. 达梦DM7DM8下载地址 - 2022-03-16更新
  10. Go (Golang) 工具之单元测试 go-junit-report | go的单元测试
  11. Python 随机抽奖
  12. iOS 播放系统提示音和震动
  13. hadoop-uber作业模式
  14. Android裁剪图片为圆形
  15. 获取微信用户的openId
  16. Hbuilder安装及使用教程
  17. sql server 入门教程
  18. python爬虫某招聘数据进行可视化
  19. crm客户管理系统的功能有哪些?
  20. 《机器学习实战》——kNN

热门文章

  1. Java 注册SIGINT信号,处理CTRL+C
  2. mongorepository查询条件_MongoDB动态条件之分页查询
  3. 获取SpringBean对象工具类
  4. 【每日一题】航班预订统计
  5. 什么是随机存取与顺序存取?
  6. MongoDB:快速入门,掌握这些刚刚好!
  7. 知乎高赞怎么自学 python,大概要多久?
  8. 服务器系统打包,详解Docker 容器基础系统镜像打包
  9. docker rails mysql_MySQL 进行 Docker 容器化之体验与感悟
  10. weblogic修改java重启_修改weblogic域的jdk