package com.cn.codc;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder; import com.cn.constant.ConstantValue;
import com.cn.model.Request; /**
* 请求解码器
* <pre>
* 数据包格式
* +——----——+——-----——+——----——+——----——+——-----——+
* | 包头 | 模块号 | 命令号 | 长度 | 数据 |
* +——----——+——-----——+——----——+——----——+——-----——+
* </pre>
* 包头4字节
* 模块号2字节short
* 命令号2字节short
* 长度4字节(描述数据部分字节长度)
*/
public class RequestDecoder extends FrameDecoder{// FrameDecoder 这个decoder可以协助我们解决粘包分包问题 /**
* 数据包基本长度
*/
public static int BASE_LENTH = 4 + 2 + 2 + 4; //ChannelBuffer里面有一个读指针和写指针。读指针和写指针初始值是0,写多少数据写指针就移动多少
//调用readShort方法,readInt方法就会移动读指针, 0 =< readerIndex =< writerIndex
@Override
protected Object decode(ChannelHandlerContext arg0, Channel arg1, ChannelBuffer buffer) throws Exception { //可读长度readableBytes必须大于基本长度才处理
if(buffer.readableBytes() >= BASE_LENTH){
//防止socket字节流攻击
if(buffer.readableBytes() > 2048){
buffer.skipBytes(buffer.readableBytes());
} //记录包头开始的index
int beginReader; while(true){//循环读取,直到包头读取完毕
beginReader = buffer.readerIndex();//获取读指针
buffer.markReaderIndex();
if(buffer.readInt() == ConstantValue.FLAG){
break;
} //未读到包头,略过一个字节
buffer.resetReaderIndex();
buffer.readByte(); //长度又变得不满足
if(buffer.readableBytes() < BASE_LENTH){
return null;
}
} //包头读取完毕,读取模块号
short module = buffer.readShort();
//读取命令号
short cmd = buffer.readShort();
//读取长度
int length = buffer.readInt(); //readableBytes现在可读的长度小于数据的长度。判断请求数据包数据部分是否到齐
if(buffer.readableBytes() < length){
//还原读指针,已经读取了12个字节,但是没用,所以要还原buffer的读指针,
buffer.readerIndex(beginReader);
return null;//等待后面的数据包来
} //比length要长,就读取data数据
byte[] data = new byte[length];
buffer.readBytes(data);//数据读取完毕 //封装request对象继续向下传递
Request request = new Request();
request.setModule(module);
request.setCmd(cmd);
request.setData(data); //继续往下传递 ,调用sendUpStreamEvent方法向下传递
return request; }
//长度短了,数据包不完整,需要等待后面的包来
return null;
//FrameDecoder: return null就是等待后面的包,return一个解码的对象就是向下传递。
} }
package com.cn.codc;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder; import com.cn.constant.ConstantValue;
import com.cn.model.Request; /**
* 请求编码器
* <pre>
* 数据包格式
* +——----——+——-----——+——----——+——----——+——-----——+
* | 包头 | 模块号 | 命令号 | 长度 | 数据 |
* +——----——+——-----——+——----——+——----——+——-----——+
* </pre>
* 包头4字节
* 模块号2字节short
* 命令号2字节short
* 长度4字节(描述数据部分字节长度)
*/
public class RequestEncoder extends OneToOneEncoder{ //把一个request对象转换成了一个ChannelBuffer二进制数据
@Override
protected Object encode(ChannelHandlerContext context, Channel channel, Object rs) throws Exception {
Request request = (Request)(rs);
ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
//包头,确定数据包的开始
buffer.writeInt(ConstantValue.FLAG);
//module
buffer.writeShort(request.getModule());
//cmd
buffer.writeShort(request.getCmd());
//长度
buffer.writeInt(request.getDataLength());
//data
if(request.getData() != null){
buffer.writeBytes(request.getData());
}
return buffer;//返回一个ChannelBuffer继续向下传递。
} }
package com.cn.codc;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
import com.cn.constant.ConstantValue;
import com.cn.model.Response; /**
* response解码器
* <pre>
* 数据包格式
* +——----——+——-----——+——----——+——----——+——-----——+——-----——+
* | 包头 | 模块号 | 命令号 | 状态码 | 长度 | 数据 |
* +——----——+——-----——+——----——+——----——+——-----——+——-----——+
* </pre>
* 包头4字节
* 模块号2字节short
* 命令号2字节short
* 长度4字节(描述数据部分字节长度)
*/
public class ResponseDecoder extends FrameDecoder{ /**
* 数据包基本长度
*/
public static int BASE_LENTH = 4 + 2 + 2 + 4; @Override
protected Object decode(ChannelHandlerContext arg0, Channel arg1, ChannelBuffer buffer) throws Exception { //可读长度必须大于基本长度
if(buffer.readableBytes() >= BASE_LENTH){ //记录包头开始的index
int beginReader = buffer.readerIndex(); while(true){
if(buffer.readInt() == ConstantValue.FLAG){
break;
}
} //模块号
short module = buffer.readShort();
//命令号
short cmd = buffer.readShort();
//状态码
int stateCode = buffer.readInt();
//长度
int length = buffer.readInt(); if(buffer.readableBytes() < length){
//还原读指针
buffer.readerIndex(beginReader);
return null;
} byte[] data = new byte[length];
buffer.readBytes(data); //封装Response对象
Response response = new Response();
response.setModule(module);
response.setCmd(cmd);
response.setStateCode(stateCode);
response.setData(data); //继续往下传递
return response; }
//数据包不完整,需要等待后面的包来
return null;
} }
package com.cn.codc;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
import com.cn.constant.ConstantValue;
import com.cn.model.Response; /**
* 请求编码器
* <pre>
* 数据包格式
* +——----——+——-----——+——----——+——----——+——-----——+——-----——+
* | 包头 | 模块号 | 命令号 | 状态码 | 长度 | 数据 |
* +——----——+——-----——+——----——+——----——+——-----——+——-----——+
* </pre>
* 包头4字节
* 模块号2字节short
* 命令号2字节short
* 长度4字节(描述数据部分字节长度)
*/
public class ResponseEncoder extends OneToOneEncoder{ @Override
protected Object encode(ChannelHandlerContext context, Channel channel, Object rs) throws Exception {
Response response = (Response)(rs); ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
//包头
buffer.writeInt(ConstantValue.FLAG);
//module
buffer.writeShort(response.getModule());
//cmd
buffer.writeShort(response.getCmd());
//状态码
buffer.writeInt(response.getStateCode());
//长度
buffer.writeInt(response.getDataLength());
//data
if(response.getData() != null){
buffer.writeBytes(response.getData());
} return buffer;
} }
package com.cn.constant;

public interface ConstantValue {

    /**
* 包头
*/
public static final int FLAG = -32523523; }
package com.cn.model;
/**
* 客户端请求服务端的对象
*/
public class Request { /**
* 请求模块
*/
private short module; /**
* 命令号
*/
private short cmd; /**
* 数据部分
*/
private byte[] data; public short getModule() {
return module;
} public void setModule(short module) {
this.module = module;
} public short getCmd() {
return cmd;
} public void setCmd(short cmd) {
this.cmd = cmd;
} public byte[] getData() {
return data;
} public void setData(byte[] data) {
this.data = data;
} public int getDataLength(){
if(data == null){
return 0;
}
return data.length;
}
}
package com.cn.model;
/**
* 服务端返回给客户端的对象
*/
public class Response {
/**
* 请求模块
*/
private short module; /**
* 命令号
*/
private short cmd; /**
* 状态码
*/
private int stateCode; /**
* 数据部分
*/
private byte[] data; public short getModule() {
return module;
} public void setModule(short module) {
this.module = module;
} public short getCmd() {
return cmd;
} public void setCmd(short cmd) {
this.cmd = cmd;
} public int getStateCode() {
return stateCode;
} public void setStateCode(int stateCode) {
this.stateCode = stateCode;
} public byte[] getData() {
return data;
} public void setData(byte[] data) {
this.data = data;
} public int getDataLength(){
if(data == null){
return 0;
}
return data.length;
}
}
package com.cn.model;

public interface StateCode {

    /**
* 成功
*/
public static int SUCCESS = 0; /**
* 失败
*/
public static int FAIL = 1; }
package com.cn.module.fuben.request;

import com.cn.serial.Serializer;

//FightRequest是模块名
public class FightRequest extends Serializer{ /**
* 副本id
*/
private int fubenId; /**
* 次数
*/
private int count; public int getFubenId() {
return fubenId;
} public void setFubenId(int fubenId) {
this.fubenId = fubenId;
} public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} @Override
protected void read() {
this.fubenId = readInt();
this.count = readInt();
} @Override
protected void write() {
writeInt(fubenId);
writeInt(count);
} }
package com.cn.module.fuben.response;

import com.cn.serial.Serializer;

public class FightResponse extends Serializer{

    /**
* 获取金币
*/
private int gold; public int getGold() {
return gold;
} public void setGold(int gold) {
this.gold = gold;
} @Override
protected void read() {
this.gold = readInt();
} @Override
protected void write() {
writeInt(gold);
}
}
package com.cn.serial;

import java.nio.ByteOrder;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
/**
* buff工厂
*/
public class BufferFactory { public static ByteOrder BYTE_ORDER = ByteOrder.BIG_ENDIAN; /**
* 获取一个buffer
*/
public static ChannelBuffer getBuffer() {
ChannelBuffer dynamicBuffer = ChannelBuffers.dynamicBuffer();
return dynamicBuffer;
} /**
* 将数据写入buffer
*/
public static ChannelBuffer getBuffer(byte[] bytes) {
ChannelBuffer copiedBuffer = ChannelBuffers.copiedBuffer(bytes);
return copiedBuffer;
} }
package com.cn.serial;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.jboss.netty.buffer.ChannelBuffer;
/**
* 自定义序列化接口
*/
public abstract class Serializer { public static final Charset CHARSET = Charset.forName("UTF-8"); protected ChannelBuffer writeBuffer; protected ChannelBuffer readBuffer; /**
* 反序列化具体实现
*/
protected abstract void read(); /**
* 序列化具体实现
*/
protected abstract void write(); /**
* 从byte数组获取数据
* @param bytes 读取的数组
*/
public Serializer readFromBytes(byte[] bytes) {
readBuffer = BufferFactory.getBuffer(bytes);
read();
readBuffer.clear();
return this;
} /**
* 从buff获取数据
* @param readBuffer
*/
public void readFromBuffer(ChannelBuffer readBuffer) {
this.readBuffer = readBuffer;
read();
} /**
* 写入本地buff
* @return
*/
public ChannelBuffer writeToLocalBuff(){
writeBuffer = BufferFactory.getBuffer();
write();
return writeBuffer;
} /**
* 写入目标buff
* @param buffer
* @return
*/
public ChannelBuffer writeToTargetBuff(ChannelBuffer buffer){
writeBuffer = buffer;
write();
return writeBuffer;
} /**
* 返回buffer数组
*
* @return
*/
public byte[] getBytes() {
writeToLocalBuff();
byte[] bytes = null;
if (writeBuffer.writerIndex() == 0) {
bytes = new byte[0];
} else {
bytes = new byte[writeBuffer.writerIndex()];
writeBuffer.readBytes(bytes);
}
writeBuffer.clear();
return bytes;
} public byte readByte() {
return readBuffer.readByte();
} public short readShort() {
return readBuffer.readShort();
} public int readInt() {
return readBuffer.readInt();
} public long readLong() {
return readBuffer.readLong();
} public float readFloat() {
return readBuffer.readFloat();
} public double readDouble() {
return readBuffer.readDouble();
} public String readString() {
int size = readBuffer.readShort();
if (size <= 0) {
return "";
} byte[] bytes = new byte[size];
readBuffer.readBytes(bytes); return new String(bytes, CHARSET);
} public <T> List<T> readList(Class<T> clz) {
List<T> list = new ArrayList<>();
int size = readBuffer.readShort();
for (int i = 0; i < size; i++) {
list.add(read(clz));
}
return list;
} public <K,V> Map<K,V> readMap(Class<K> keyClz, Class<V> valueClz) {
Map<K,V> map = new HashMap<>();
int size = readBuffer.readShort();
for (int i = 0; i < size; i++) {
K key = read(keyClz);
V value = read(valueClz);
map.put(key, value);
}
return map;
} @SuppressWarnings("unchecked")
public <I> I read(Class<I> clz) {
Object t = null;
if ( clz == int.class || clz == Integer.class) {
t = this.readInt();
} else if (clz == byte.class || clz == Byte.class){
t = this.readByte();
} else if (clz == short.class || clz == Short.class){
t = this.readShort();
} else if (clz == long.class || clz == Long.class){
t = this.readLong();
} else if (clz == float.class || clz == Float.class){
t = readFloat();
} else if (clz == double.class || clz == Double.class){
t = readDouble();
} else if (clz == String.class ){
t = readString();
} else if (Serializer.class.isAssignableFrom(clz)){
try {
byte hasObject = this.readBuffer.readByte();
if(hasObject == 1){
Serializer temp = (Serializer)clz.newInstance();
temp.readFromBuffer(this.readBuffer);
t = temp;
}else{
t = null;
}
} catch (Exception e) {
e.printStackTrace();
} } else {
throw new RuntimeException(String.format("不支持类型:[%s]", clz));
}
return (I) t;
} public Serializer writeByte(Byte value) {
writeBuffer.writeByte(value);
return this;
} public Serializer writeShort(Short value) {
writeBuffer.writeShort(value);
return this;
} public Serializer writeInt(Integer value) {
writeBuffer.writeInt(value);
return this;
} public Serializer writeLong(Long value) {
writeBuffer.writeLong(value);
return this;
} public Serializer writeFloat(Float value) {
writeBuffer.writeFloat(value);
return this;
} public Serializer writeDouble(Double value) {
writeBuffer.writeDouble(value);
return this;
} public <T> Serializer writeList(List<T> list) {
if (isEmpty(list)) {
writeBuffer.writeShort((short) 0);
return this;
}
writeBuffer.writeShort((short) list.size());
for (T item : list) {
writeObject(item);
}
return this;
} public <K,V> Serializer writeMap(Map<K, V> map) {
if (isEmpty(map)) {
writeBuffer.writeShort((short) 0);
return this;
}
writeBuffer.writeShort((short) map.size());
for (Entry<K, V> entry : map.entrySet()) {
writeObject(entry.getKey());
writeObject(entry.getValue());
}
return this;
} public Serializer writeString(String value) {
if (value == null || value.isEmpty()) {
writeShort((short) 0);
return this;
} byte data[] = value.getBytes(CHARSET);
short len = (short) data.length;
writeBuffer.writeShort(len);
writeBuffer.writeBytes(data);
return this;
} public Serializer writeObject(Object object) { if(object == null){
writeByte((byte)0);
}else{
if (object instanceof Integer) {
writeInt((int) object);
return this;
} if (object instanceof Long) {
writeLong((long) object);
return this;
} if (object instanceof Short) {
writeShort((short) object);
return this;
} if (object instanceof Byte) {
writeByte((byte) object);
return this;
} if (object instanceof String) {
String value = (String) object;
writeString(value);
return this;
}
if (object instanceof Serializer) {
writeByte((byte)1);
Serializer value = (Serializer) object;
value.writeToTargetBuff(writeBuffer);
return this;
} throw new RuntimeException("不可序列化的类型:" + object.getClass());
} return this;
} private <T> boolean isEmpty(Collection<T> c) {
return c == null || c.size() == 0;
}
public <K,V> boolean isEmpty(Map<K,V> c) {
return c == null || c.size() == 0;
}
}

netty8---自定义编码解码器的更多相关文章

  1. netty系列之:自定义编码解码器

    目录 简介 自定义编码器 自定义解码器 添加编码解码器到pipeline 计算2的N次方 总结 简介 在之前的netty系列文章中,我们讲到了如何将对象或者String转换成为ByteBuf,通过使用 ...

  2. Android Mina框架的学习笔记

    Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络 ...

  3. Android集成Mina NIO Socket

    Mina简介 Apache MINA(Multipurpose Infrastructure 多功能框架 for Network Applications) 是 Apache 组织一个较新的项目,它为 ...

  4. Mina框架的学习笔记——Android客户端的实现

    Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络 ...

  5. SpringCloud升级之路2020.0.x版-26.OpenFeign的组件

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 首先,我们给出官方文档中的组件结构图: 官方文档中的组件,是以实现功能为维度的,我们这里是 ...

  6. Spring 实现策略模式--自定义注解方式解耦if...else

    策略模式 定义 定义一簇算法类,将每个算法分别封装起来,让他们可以互相替换,策略模式可以使算法的变化独立于使用它们的客户端 场景 使用策略模式,可以避免冗长的if-else 或 switch分支判断 ...

  7. netty系列之:netty中的懒人编码解码器

    目录 简介 netty中的内置编码器 使用codec要注意的问题 netty内置的基本codec base64 bytes compression json marshalling protobuf ...

  8. netty系列之:netty中常用的对象编码解码器

    目录 简介 什么是序列化 重构序列化对象 序列化不是加密 使用真正的加密 使用代理 Serializable和Externalizable的区别 netty中对象的传输 ObjectEncoder O ...

  9. 关于Unity3D自定义编辑器的学习

    被人物编辑器折腾了一个月,最终还是交了点成品上去(还要很多优化都还么做).  刚接手这项工作时觉得没概念,没想法,不知道.后来就去看<<Unity5.X从入门到精通>>中有关于 ...

  10. 一起学微软Power BI系列-使用技巧(5)自定义PowerBI时间日期表

    1.日期函数表作用 经常使用Excel或者PowerBI,Power Pivot做报表,时间日期是一个重要的纬度,加上做一些钻取,时间日期函数表不可避免.所以今天就给大家分享一个自定义的做日期表的方法 ...

随机推荐

  1. php如何互换一个数组的首尾元素 中间不变 首尾互换

    群里有人提出一个问题 如何互换一个数组的首尾元素 中间不变 首尾互换 代码如下: <?php $array=array(1,2,3,4,5,6,7,8,9,10); $first=array_s ...

  2. 修改tomcat配置通过域名直接访问项目首页

    1.在自己项目的web.xml中配置欢迎页面 <welcome-file-list> <welcome-file>index.html</welcome-file> ...

  3. Perfmon - Windows 自带系统监测工具

    本文转载自oscar999 一. 简述 可以用于监视CPU使用率.内存使用率.硬盘读写速度.网络速度等. Perfmon提供了图表化的系统性能实时监视器.性能日志和警报管理,系统的性能日志可定义为二进 ...

  4. JavaMath方法、服务器与Tomcat安装与配置步骤

    一.Math Math.PI 记录的圆周率  Math.E 记录e的常量  Math中还有一些类似的常量,都是一些工程数学常用量. Math.abs 求绝对值  Math.sin 正弦函数 Math. ...

  5. AJAX Form Submit Framework 原生js post json

    https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest <!doctype ht ...

  6. jsonarray 循环

    JSONArray groupList = JSON.parseArray(st1); for (int i=0;i<groupList.size();i++){ JSONObject json ...

  7. ubuntu重新设置登陆界面|切换gdm kdm lightdm

    方法: $ sudo dpkg-reconfigure gdm 然后会出一个让你进行选择的提示,根据需要切换即可

  8. 【npm start 启动失败】ubuntu 将node和npm同时更新到最新的稳定版本

    https://blog.csdn.net/u010277553/article/details/80938829 npm start 启动失败,报错如下 错误提示 make sure you hav ...

  9. 【我的Android进阶之旅】 RxJava 理解Backpressure并解决异常 rx.exceptions.MissingBackpressureException

    今天测试人员在测试应用APP的时候应用crash了,查看了下crash log如下所示: java.lang.IllegalStateException: Exception thrown on Sc ...

  10. Hbase架构和读写流程

    转载自:http://www.cnblogs.com/muzili-ykt/p/muzili_ykt.html 在HBase读写时,相同Cell(RowKey/ColumnFamily/Column相 ...