netty 自定义协议
netty 自定义协议
netty 是什么呢?
相信很多人都被人问过这个问题。如果快速准确的回复这个问题呢?网络编程框架,netty可以让你快速和简单的开发出一个高性能的网络应用。netty是一个网络编程框架。那netty又有什么框框呢?主要有二个框。
框1:客户和服务的启动
一切通讯都有收与发,所有的服务端和客户端都是这样的姿势启动。具体的参数可以看文档。
服务端
public void bind() throws Exception {
// 配置服务端的NIO线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
//需要两个线程组
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ServerInit());
// 绑定端口,同步等待成功
b.bind(NettyConstant.REMOTE_PORT).sync();
LOG.info("Netty server start : "
+ (NettyConstant.REMOTE_IP + " : " + NettyConstant.REMOTE_PORT));
}
客户端
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ClientInit());
// 发起异步连接操作
ChannelFuture future = b.connect(
new InetSocketAddress(host, port)).sync();
channel = future.sync().channel();
future.channel().closeFuture().sync();
框2:处理器ChannelHandler
netty将所有接收到或发出去的数据都交给处理器处理,hannelInboundHandler入站处理器,ChannelOutboundHandler出站处理器。入站既接收数据时触发,出站是发送时触发。包括编码器和解码器分别实现的也是这两个接口。所以我们要为服务端或客户端扩展功能的话!只要对应创建 对个类去实现这两个接口添加到通道上就行了。netty作为一个框架,当然也帮我们实现了很多经常的用的处理器了,如:StringDecoder(字串解码器),StringEncoder(字串编码器),LengthFieldPrepender(给数据添加长度解决黏包半包问题),ReadTimeoutHandler(超时检测)
服务端出入站处理器添加
**
* @author hdk
* 类说明:服务端入站处理器初始化类
*/
public class ServerInit extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
/*Netty提供的日志打印Handler,可以展示发送接收出去的字节*/
//ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
/*剥离接收到的消息的长度字段,拿到实际的消息报文的字节数组*/
ch.pipeline().addLast("frameDecoder",
new LengthFieldBasedFrameDecoder(65535,
0,2,0,
2));
/*给发送出去的消息增加长度字段*/
ch.pipeline().addLast("frameEncoder",
new LengthFieldPrepender(2));
/*反序列化,将字节数组转换为消息实体*/
ch.pipeline().addLast(new KryoDecoder());
/*序列化,将消息实体转换为字节数组准备进行网络传输*/
ch.pipeline().addLast("MessageEncoder",
new KryoEncoder());
/*超时检测*/
ch.pipeline().addLast("readTimeoutHandler",
new ReadTimeoutHandler(10));
/*登录应答*/
ch.pipeline().addLast(new LoginAuthRespHandler());
/*心跳应答*/
ch.pipeline().addLast("HeartBeatHandler",
new HeartBeatRespHandler());
/*服务端业务处理*/
ch.pipeline().addLast("ServerBusiHandler",
new ServerBusiHandler());
}
}
客户端出入站处理器添加
/**
* @author hdk
* 类说明:客户端Handler的初始化
*/
public class ClientInit extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
/*剥离接收到的消息的长度字段,拿到实际的消息报文的字节数组*/
ch.pipeline().addLast("frameDecoder",
new LengthFieldBasedFrameDecoder(65535,
0,2,0,
2));
/*给发送出去的消息增加长度字段*/
ch.pipeline().addLast("frameEncoder",
new LengthFieldPrepender(2));
/*反序列化,将字节数组转换为消息实体*/
ch.pipeline().addLast(new KryoDecoder());
/*序列化,将消息实体转换为字节数组准备进行网络传输*/
ch.pipeline().addLast("MessageEncoder",
new KryoEncoder());
/*超时检测*/
ch.pipeline().addLast("readTimeoutHandler",
new ReadTimeoutHandler(10));
/*发出登录请求*/
ch.pipeline().addLast("LoginAuthHandler",
new LoginAuthReqHandler());
/*发出心跳请求*/
ch.pipeline().addLast("HeartBeatHandler",
new HeartBeatReqHandler());
}
}
处理器注意事项
入站:在入站实现方法中ChannelInboundHandler.channelRead必需release下一个处理器会接着触发。释放netty的ByteBuf给其他处理器读取: ReferenceCountUtil.release(msg);如果不想下个处理器处理就调用ctx.fireChannelRead(msg);
出站:在入站实现方法中ChannelOutboundHandler.write同样要调用ReferenceCountUtil.release(msg),在其他的处理器中才可以读取本处理器处理过的数据
处理器的扩展编码器与解码器
在网络编程中定义一种高效编码规则是很重要的,节省带宽提交传输效率。提高传输速度。所以netty封装了两种特殊的处理器叫:ByteToMessageDecoder解码器和MessageToByteEncoder编码器。使用方法也很简单,继承重写一下decode和encode就可以了.。
解码器 ByteToMessageDecoder
/**
* @author hdk
* 类说明:反序列化的Handler
*/
public class KryoDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in,
List<Object> out) throws Exception {
Object obj = KryoSerializer.deserialize(in);
//数据信息处理后添加目标编码格式的数据到ByteBuf中就供后面的处理器处理。
out.add(obj);
}
}
编码器 MessageToByteEncoder
/**
* @author hdk
* 类说明:序列化的Handler
*/
public class KryoEncoder extends MessageToByteEncoder<MyMessage> {
@Override
protected void encode(ChannelHandlerContext ctx, MyMessage message,
ByteBuf out) throws Exception {
KryoSerializer.serialize(message, out);
//发送ByteBuf到目标IP
ctx.flush();
}
}
总结
netty为什么那么流行,个人认为有几点:
- 1事件编程让代码变得很简洁。
- 2提供很多协议如mqtt,http,websocket,smtp,redis等等,所有可以很快速的就可以开发出这些协议的服务端程序,不用自己去实现了。
netty扩展-自定义协议
Netty协议栈消息定义包含两部分:消息头、消息体
Header
名称 | 类型 | 长度 | 描述 |
---|---|---|---|
crcCode | Int | 32 | Netty消息校验码 |
Length | Int | 32 | 整个消息长度 |
sessionID | Long | 64 | 会话ID |
Type | Byte | 8 | 0:业务请求消息1:业务响应消息2:业务one way消息3握手请求消息4握手应答消息5:心跳请求消息6:心跳应答消息 |
Priority | Byte | 8 | 消息优先级:0~255 |
Attachment | Map<String,Object> | 变长 | 可选字段,由于推展消息头 |
/**
* @author hdk
* 类说明:消息头
*/
public final class MyHeader {
private int crcCode = 0xabef0101;
private int length;// 消息长度
private long sessionID;// 会话ID
private byte type;// 消息类型
private byte priority;// 消息优先级
private Map<String, Object> attachment = new HashMap<String, Object>(); // 附件
public final int getCrcCode() {
return crcCode;
}
public final void setCrcCode(int crcCode) {
this.crcCode = crcCode;
}
public final int getLength() {
return length;
}
public final void setLength(int length) {
this.length = length;
}
public final long getSessionID() {
return sessionID;
}
public final void setSessionID(long sessionID) {
this.sessionID = sessionID;
}
public final byte getType() {
return type;
}
public final void setType(byte type) {
this.type = type;
}
public final byte getPriority() {
return priority;
}
public final void setPriority(byte priority) {
this.priority = priority;
}
public final Map<String, Object> getAttachment() {
return attachment;
}
public final void setAttachment(Map<String, Object> attachment) {
this.attachment = attachment;
}
@Override
public String toString() {
return "MyHeader [crcCode=" + crcCode + ", length=" + length
+ ", sessionID=" + sessionID + ", type=" + type + ", priority="
+ priority + ", attachment=" + attachment + "]";
}
}
/**
* @author hdk
* 类说明:消息实体类
*/
public final class MyMessage {
private MyHeader myHeader;
private Object body;
public final MyHeader getMyHeader() {
return myHeader;
}
public final void setMyHeader(MyHeader myHeader) {
this.myHeader = myHeader;
}
public final Object getBody() {
return body;
}
public final void setBody(Object body) {
this.body = body;
}
@Override
public String toString() {
return "MyMessage [myHeader=" + myHeader + "][body="+body+"]";
}
}
源码
https://github.com/huangdongkui/netty_project
netty 自定义协议的更多相关文章
- Netty自定义协议解析原理与应用
目前,大家都选择Netty做为游戏服务器框架网络通信的框架,而且目前也有很多优秀的产品是基于Netty开发的.它的稳定性,易用性和高效率性已得到广泛的认同.在游戏服务器开发中,选择netty一般就意味 ...
- 《精通并发与Netty》学习笔记(14 - 解决TCP粘包拆包(二)Netty自定义协议解决粘包拆包)
一.Netty粘包和拆包解决方案 Netty提供了多个解码器,可以进行分包的操作,分别是: * LineBasedFrameDecoder (换行) LineBasedFrameDecoder是回 ...
- netty自定义协议 心跳 断线重连源码
https://github.com/aa1356889/NettyHeartbeat
- 利用Netty构建自定义协议的通信
在复杂的网络世界中,各种应用之间通信需要依赖各种各样的协议,比如:HTTP,Telnet,FTP,SMTP等等. 在开发过程中,有时候我们需要构建一些适应自己业务的应用层协议,Netty作为一个非常优 ...
- 【转】Netty之解决TCP粘包拆包(自定义协议)
1.什么是粘包/拆包 一般所谓的TCP粘包是在一次接收数据不能完全地体现一个完整的消息数据.TCP通讯为何存在粘包呢?主要原因是TCP是以流的方式来处理数据,再加上网络上MTU的往往小于在应用处理的消 ...
- Netty之解决TCP粘包拆包(自定义协议)
1.什么是粘包/拆包 一般所谓的TCP粘包是在一次接收数据不能完全地体现一个完整的消息数据.TCP通讯为何存在粘包呢?主要原因是TCP是以流的方式来处理数据,再加上网络上MTU的往往小于在应用处理的消 ...
- netty使用MessageToByteEncoder 自定义协议(四)
开发应用程序与应用程序之间的通信,程序之前通信 需要定义协议,比如http协议. 首先我们定义一个协议类 package com.liqiang.SimpeEcode; import java.sql ...
- netty源码解解析(4.0)-20 ChannelHandler: 自己实现一个自定义协议的服务器和客户端
本章不会直接分析Netty源码,而是通过使用Netty的能力实现一个自定义协议的服务器和客户端.通过这样的实践,可以更深刻地理解Netty的相关代码,同时可以了解,在设计实现自定义协议的过程中需要解决 ...
- 物联网架构成长之路(35)-利用Netty解析物联网自定义协议
一.前言 前面博客大部分介绍了基于EMQ中间件,通信协议使用的是MQTT,而传输的数据为纯文本数据,采用JSON格式.这种方式,大部分一看就知道是熟悉Web开发.软件开发的人喜欢用的方式.由于我也是做 ...
随机推荐
- vue 项目 使用sass以及注意事项
vue 项目 使用sass以及注意事项 1,安装依赖: npm install node-sass --save-dev npm install sass-loader --save-dev 注: 通 ...
- 【工具】sqlmap 中文手册 使用教程
日期:2019-07-28 09:27:27 更新: 作者:Bay0net 介绍:自己翻译了一下,做个备忘. 0x01. 基本信息 官网 sqlmap: automatic SQL injection ...
- JAVA 基础编程练习题36 【程序 36 移动位置】
36 [程序 36 移动位置] 题目:有 n 个整数,使其前面各数顺序向后移 m 个位置,最后 m 个数变成最前面的 m 个数 package cskaoyan; public class cskao ...
- Go 微服务架构Micro相关概念理解
Micro是一个微服务框架(或者说是工具集):提供了各类组件,解决微服务架构中的不同问题,服务监控.服务发现.熔断机制,负载均衡等等,自己一个个解决这些问题几乎不可能,这时候就需要借助go-micro ...
- 【c++基础】C++编写Config类读取配置文件
前言 系统程序一般需要读取参数文件,看到一个很好的Config类记录在此. 头文件Config.h //Config.h //re: https://blog.csdn.net/David_xtd/a ...
- js 高级程序设计 第三章学习笔记——Number数据类型需要注意的事项
1.浮点数值 虽然小数点前面可以没有整数,但是并不推荐这种写法. 由于保存浮点数值需要的内存空间是保存整数值的两倍,因此ECMAScript会不失时机地将浮点数值转化为整数数值.显然,如果小数点后面没 ...
- 【VS开发】文件共享内存2
在32位的Windows系统中,每一个进程都有权访问他自己的4GB(232=4294967296)平面地址空间,没有段,没有选择符,没有near和far指针,没有near和far函数调用,也没有内存模 ...
- 1. PHP基本语法规则
1.1 PHP标记: PHP语言,是一种可以嵌入到“html”代码中的后台处理语言(程序) 有以下几种标记形式,只推荐第一种. 1,<?php php代码写在这里..... ?> ...
- storm常见问题
一.storm ui 不显示 supervisor 信息 在zk节点上删掉storm信息,重新启动storm集群即可
- SQLite进阶-17.视图
目录 视图(View) 操作视图 更新视图 删除视图 查看所有的视图 视图(View) 视图是一个预定义的SQLite查询的形式存在的表的组合. 可以包含一个表的所有行或从一个或多个表选定行.可以从一 ...