真正实现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服务器开发 背景 当前的安防行业,除了私有协议,普遍使用 ...
随机推荐
- 网络叠加模式VLAN、VxLAN、GRE
什么是叠加网络 1.一个数据包(或帧)封装在另一个数据包内;被封装的包转发到隧道端点后再被拆装. 2.叠加网络就是使用这种所谓"包内之包"的技术安全地将一个网络隐藏在另一个 网络中 ...
- RFC Transactional RFC (tRFC) queue RFC(qRFC) 概念
Transactional RFC When using transactional RFC (tRFC), the called function module is executed exactl ...
- Javascript中 a.href 和 a.getAttribute('href') 结果不完全一致
今天无意中发现这个么问题,页面上对所有A标签的href属性为空的自动添加一个链接地址,结果发现if判断条件始终都没生效,莫名其妙. 原来Javascript中 a.href 和 a.getAttrib ...
- nio简介
上一篇 Java I/O演进与Linux网络I/O模型 一.传统BIO java传统bio编程概念: http://www.cnblogs.com/carl10086/p/6034563.html# ...
- 如何解决sql server定时作业调用Kettle job出错
错误信息: Unable to list jar files in plugin folder 'C:\Windows\system32\config\systemprofile\.kettle\pl ...
- Chapter 21_5.2 tab扩展
在Lua中,像这样()的空白捕获具有特殊意义.表示捕获它在目标字符串中的位置,返回一个数字: print(string.match("hello","()ll()&quo ...
- 我理解的session和cookie
tomcat管理session 理解tomcat是如何生成session的. 当用户请求到web资源有request.getSession()这段代码的时候,request首先会对请求的url判读是否 ...
- 记录下 js各种证件的正则验证
身份证 /(^\d{15}$)|(^\d{17}([0-9]|X)$)/ 护照 /^[a-zA-Z0-9]{3,21}$/ /^(P\d{7})|(G\d{8})$/ 军官证或士兵证 ...
- Hybrid App(二)Cordova+android入门
上一篇介绍了app开发如何选型,由于公司人员组织结构的原因(app native较少,每个月一次迭代),因此选型hybrid app. 接下来说一下环境搭建: 一.Java环境 (1)安装jdk (2 ...
- 转:iOS 屏幕适配,autoResizing autoLayout和sizeClass图文详解
1. autoResizing autoresizing是苹果早期的ui布局适配的解决办法,iOS6之前完全可以胜任了,因为苹果手机只有3.5寸的屏幕,在加上手机app很少支持横屏,所以iOS开发者基 ...