真正实现Netty私有协议开发
首先《Netty权威指南》私有协议开发那一章的样例代码是编译不通过的(但是这丝毫不影响本书的价值)
处理方案可以参考:http://www.itnose.net/detail/6112870.html
另外这一章的私有协议开发案例也过于理想化,为什么这么说呢?如果说服务端或客户端有一方基于历史原因是用其他语言实现的呢,比如C,Java和C的int类型字节长度是不一样的
那LineBasedFrameDecoder就用不上了,让我们看一个实际的私有协议案例:

这个协议在C/++程序员看来是个再正常不过的了,尤其注意协议对长度字段是采用字符串方式描述的(最多支持9999),如果用Netty来实现,又该如何处理呢?
public class NettyMessage {
private Header header;
private Object body;
//检验和
private byte crcCode;
public byte getCrcCode() {
return crcCode;
}
public void setCrcCode(byte crcCode) {
this.crcCode = crcCode;
}
public Header getHeader() {
return header;
}
public void setHeader(Header header) {
this.header = header;
}
public Object getBody() {
return body;
}
public void setBody(Object body) {
this.body = body;
}
public String toString(){
return ToStringBuilder.reflectionToString(this);
}
}
public class Header {
//固定头
private byte startTag;
//命令码,4位
private byte[] cmdCode;
//版本 2位
private byte[] version;
private int length;
public byte[] getVersion() {
return version;
}
public void setVersion(byte[] version) {
this.version = version;
}
public byte[] getCmdCode() {
return cmdCode;
}
public void setCmdCode(byte[] cmdCode) {
this.cmdCode = cmdCode;
}
public byte getStartTag() {
return startTag;
}
public void setStartTag(byte startTag) {
this.startTag = startTag;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public String toString(){
return ToStringBuilder.reflectionToString(this);
}
}
public class MessageEncoder extends MessageToByteEncoder<NettyMessage>{
@Override
protected void encode(ChannelHandlerContext ctx, NettyMessage msg, ByteBuf out) throws Exception {
try{
if(msg == null || msg.getHeader() == null){
throw new Exception("The encode message is null");
}
out.writeByte(msg.getHeader().getStartTag());
out.writeBytes(msg.getHeader().getCmdCode());
//占位
byte[] lengthBytes = new byte[]{0, 0, 0, 0};
out.writeBytes(lengthBytes);
out.writeBytes(msg.getHeader().getVersion());
String body = (String)msg.getBody();
int length = 0;
if(body != null){
byte[] bodyBytes = body.getBytes();
out.writeBytes(bodyBytes);
length = bodyBytes.length;
if(Constants.CRCCODE_DEFAULT != msg.getCrcCode()){
msg.setCrcCode(CRC8.calcCrc8(bodyBytes));
}
}
//长度从int转换为byte[4]
byte l1 = getIndexToByte(length, 3);
byte l2 = getIndexToByte(length, 2);
byte l3 = getIndexToByte(length, 1);
byte l4 = getIndexToByte(length, 0);
lengthBytes = new byte[]{l1, l2, l3, l4};
out.setBytes(5, lengthBytes);
out.writeByte(msg.getCrcCode());
}catch(Exception e){
e.printStackTrace();
throw e;
}
}
public static byte getIndexToByte(int i, int index){
if(index == 0){
return (byte)(i % 10);
}else{
int num = (int)Math.pow(10, index);
return (byte)((i / num) % 10);
}
}
}
public class MessageDecoder extends ByteToMessageDecoder {
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
try{
if(in.readableBytes() < 12){
return;
}
in.markReaderIndex();
NettyMessage message = new NettyMessage();
Header header = new Header();
header.setStartTag(in.readByte());
byte[] cmdCode = new byte[4];
in.readBytes(cmdCode);
header.setCmdCode(cmdCode);
//长度从byte[4]转int
byte[] lengthBytes = new byte[4];
in.readBytes(lengthBytes);
int length = toInt(lengthBytes);
header.setLength(length);
if(length < 0 || length > 10240){//过长消息或不合法消息
throw new IllegalArgumentException("wrong message length");
}
byte[] version = new byte[2];
in.readBytes(version);
header.setVersion(version);
if(header.getLength() > 0){
if(in.readableBytes() < length + 1){
in.resetReaderIndex();
return;
}
byte[] bodyBytes = new byte[header.getLength()];
in.readBytes(bodyBytes);
message.setBody(new String(bodyBytes));
}
message.setCrcCode(in.readByte());
message.setHeader(header);
out.add(message);
}catch(Exception e){
e.printStackTrace();
throw e;
}
}
public static int toInt(byte[] bytes){
int value = 0;
for(int i=0; i<bytes.length; i++){
int num = (int)Math.pow(10, bytes.length - 1 - i);
value += num * bytes[i];
}
return value;
}
}
服务端代码:
public class NettyServer implements Runnable{
private static final Logger logger = LoggerFactory.getLogger(NettyServer.class);
@Autowired
Config config;
public void bind(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, 1024)
.childHandler(new ChildChannelHandler());
ChannelFuture f = b.bind(port).sync();
logger.info("Push server started on port " + port);
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast(new MessageDecoder())
.addLast(new MessageEncoder())
}
}
@Override
public void run() {
try {
this.bind(config.getServerPort());
} catch (Exception e) {
logger.error(e.getMessage());
System.exit(1);
}
}
}
客户端代码:
/**
* 客户端
* @author peng
*/
public class NettyClient { public void connect(String remoteServer, int port) throws Exception {
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup)
.channel(NioSocketChannel.class)
.handler(new ChildChannelHandler());
ChannelFuture f = b.connect(remoteServer,port).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
}
} public static class ChildChannelHandler extends
ChannelInitializer<SocketChannel> { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new MessageDecoder())
.addLast(new MessageEncoder())
}
} public static void main(String[] args){
try {
new NettyClient().connect("127.0.0.1", 9080);
} catch (Exception e) {
e.printStackTrace();
}
}
}
总结:关键在于Encoder和Decoder的编码实现
真正实现Netty私有协议开发的更多相关文章
- netty——私有协议栈开发案例
netty--私有协议栈开发案例 摘要: 在学习李林峰老师的Netty权威指南中,觉得第十二章<私有协议栈开发>中的案例代码比较有代表性,讲的也不错,但是代码中个人认为有些简单的错误,个人 ...
- netty websocket协议开发
websocket的好处我们就不用多说了,就是用于解决长连接.服务推送等需要的一种技术. 以下我们来看一个例子: package com.ming.netty.http.websocket; impo ...
- WebSocket协议开发
一直以来,网络在很大程度上都是围绕着HTTP的请求/响应模式而构建的.客户端加载一个网页,然后直到用户点击下一页之前,什么都不会发生.在2005年左右,Ajax开始让网络变得更加动态了.但所有的HTT ...
- netty(4)高级篇-Websocket协议开发
一.HTTP协议的弊端 将HTTP协议的主要弊端总结如下: (1) 半双工协议:可以在客户端和服务端2个方向上传输,但是不能同时传输.同一时刻,只能在一个方向上传输. (2) HTTP消息冗长:相比于 ...
- netty高级篇(3)-HTTP协议开发
一.HTTP协议简介 应用层协议http,发展至今已经是http2.0了,拥有以下特点: (1) CS模式的协议 (2) 简单 - 只需要服务URL,携带必要的请求参数或者消息体 (3) 灵活 - 任 ...
- Netty实现简单私有协议
本文参考<Netty权威指南> 私有协议实现的功能: 1.基于Netty的NIO通信框架,提供高性能异步通信能力 2.提供消息的编码解码框架,实现POJO的序列化和反序列化 3.提供基于I ...
- netty 私有协议栈
通信协议从广义上区分,可以分为公有协议和私有协议.由于私有协议的灵活性,它往往会在某个公司或者组织内部使用,按需定制,也因为如此,升级起来会非常方便,灵活性好.绝大多数的私有协议传输层都基于TCP/I ...
- 通过私有协议Chrome浏览器页面打开本地程序
近期方有这样的要求:这两个系统,根据一组Chrome开展,根据一组IE开展,需要Chrome添加一个链接,然后进入IE该系统的开发.这,需要Chrome跳转到创建一个链接IE浏览器指定的页面.同时也实 ...
- EasyDarwin支持GB28181协议开发
本文转自:http://blog.csdn.net/gavin1010/article/details/77926853 EasyGB28181服务器开发 背景 当前的安防行业,除了私有协议,普遍使用 ...
随机推荐
- WebADI应用到Office 2016 64-bit
升级后的用户环境: Windows 2016 bit Office 2016 64 bit IE 11 64 bit 功能定义 功能:CUX_LINE_IMP_ADI 类型:SSWA servlet ...
- 安装windows后grub的恢复
问题: 原本是:双系统(linux和windows),后来换windows版本覆盖了grub2 解决方法: 进入windows后下载并安装EasyBCD并添加grub2的选项,重启看见了熟悉的启动项, ...
- D3.js:动态效果
D3 提供了 4 个方法用于实现图形的过渡: - transition() 启动过渡效果,其前后是图形变化前后的状态(形状.位置.颜色等等),例如: .attr("fill",&q ...
- Pos终端中的主密钥、工作密钥、pin密钥、mac密钥
下面介绍一下加密机中最主要的几种密钥: 1.加密机主密钥(MK) 加密机主密钥(Master Key - MK)是存入在HSM机内的由三个成分合成的一对最上层密钥.在HSM机器以外的地方不会以明文形式 ...
- es5 数组
一. 数组申明 var a = new Array(5) 会生成一个长度为5 每个元素都是undifined的数组 var a = new Array(1,2,3) 跟 var a = [1,2,3 ...
- python简易爬虫实现
目的:爬取昵称 目标网站:糗事百科 依赖的库文件:request.sys.beautifulSoup4.imp.io Python使用版本:3.4 说明:参考http://cn.python-requ ...
- CAD打开缓慢问题解决方法
打开AutoCAD很卡,大概需要1分钟 打开Internet Explorer,点击工具菜单,打开"Internet选项",去勾选"检查发行商的证书是否吊销", ...
- Ajax与CustomErrors的尴尬
在ASP.NET程序中,为了给用户显示友好的错误信息,通常在web.config中进行如下的设置: <customErrors mode="RemoteOnly" defau ...
- cdh 安装记录
安装文件准备 CDH 下载地址:http://archive.cloudera.com/cdh5/parcels/latest/ 下载操作系统对应的版本: 1.CDH-5.3.0-1.cdh5.3.0 ...
- 49、word2vec - tensorflow
Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:18:55) [MSC v.1900 64 bit (AMD64)] on win32Type & ...