粘包和分包出现的原因是:没有一个稳定数据结构

解决办法: 分割符

     长度 + 数据

* <pre>  
* 数据包格式
* +——----——+——-----——+——----——+——----——+——-----——+
* | 包头 | 模块号 | 命令号 | 长度 | 数据 |
* +——----——+——-----——+——----——+——----——+——-----——+
* </pre>
* 包头4字节
* 模块号2字节short
* 命令号2字节short
* 长度4字节(描述数据部分字节长度)

创建encoder  和 decoder  分别 加入pipeline 中

public class RpcDecoder extends ByteToMessageDecoder {

    private Class<?> genericClass;

    public RpcDecoder(Class<?> genericClass) {
this.genericClass = genericClass;
} @Override
public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (in.readableBytes() < 4) {
return;
}
in.markReaderIndex();
int dataLength = in.readInt();
if (dataLength < 0) {
ctx.close();
}
if (in.readableBytes() < dataLength) {
in.resetReaderIndex();
return;
}
byte[] data = new byte[dataLength];
in.readBytes(data); Object obj = SerializationUtil.deserialize(data, genericClass);
out.add(obj);
}
}
public class RpcEncoder extends MessageToByteEncoder {

    private Class<?> genericClass;

    public RpcEncoder(Class<?> genericClass) {
this.genericClass = genericClass;
} @Override
public void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) throws Exception {
if (genericClass.isInstance(in)) {
byte[] data = SerializationUtil.serialize(in);
out.writeInt(data.length);
out.writeBytes(data);
}
}
}
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (in.readableBytes() >= BASE_LENGTH) { //防止socket字节流攻击
if (in.readableBytes() > 2048) {
in.skipBytes(in.readableBytes());
} //记录包头开始的index
int beginReader; //读取包头
while (true) {
beginReader = in.readerIndex();
in.markReaderIndex();
if (in.readInt() == Constantvalue.FLAG) {
break;
} //未读到包头, 略过一个字节
in.resetReaderIndex();
in.readByte(); //长度又变得不满足
if (in.readableBytes() < BASE_LENGTH) {
return;
}
}
} // 模块号
short module = in.readShort();
//命令好
short cmd = in.readShort();
// 长度
int dataLength = in.readInt(); if (in.readableBytes() < dataLength) {
//还原读指针
in.resetReaderIndex();
return;
}
byte[] data = new byte[dataLength];
in.readBytes(data);
Request request = new Request();
request.setModule(module);
request.setCmd(cmd);
request.setData(data);
//继续往下传递
out.add(request); }

buffer里面数据未被读取完怎么办

protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
try {
while (in.isReadable()) {
int outSize = out.size();
int oldInputLength = in.readableBytes();
decode(ctx, in, out); // Check if this handler was removed before continuing the loop.
// If it was removed, it is not safe to continue to operate on the buffer.
//
// See https://github.com/netty/netty/issues/1664
if (ctx.isRemoved()) {
break;
} if (outSize == out.size()) { // 这里会对照长度 先判断读到东西了没有, 没有跳出
if (oldInputLength == in.readableBytes()) { // 读取位置变化没
break;
} else {
continue;
}
} if (oldInputLength == in.readableBytes()) {
throw new DecoderException(
StringUtil.simpleClassName(getClass()) +
".decode() did not read anything but decoded a message.");
} if (isSingleDecode()) {
break;
}
}

数据缓存在 cumulation中

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof ByteBuf) {
RecyclableArrayList out = RecyclableArrayList.newInstance();
try {
ByteBuf data = (ByteBuf) msg;
first = cumulation == null; //第一次请求 cumulation 为 null true
if (first) {
cumulation = data;
} else {
cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data); // 第二次请求时进入 将新的信息追加到cumulation后面
}
callDecode(ctx, cumulation, out);
} catch (DecoderException e) {
throw e;
} catch (Throwable t) {
throw new DecoderException(t);
} finally {
if (cumulation != null && !cumulation.isReadable()) {
cumulation.release();
cumulation = null;
}
int size = out.size(); for (int i = 0; i < size; i ++) {
ctx.fireChannelRead(out.get(i));
}
out.recycle();
}
} else {
ctx.fireChannelRead(msg);
}
}

Netty自定义数据包协议的更多相关文章

  1. 基于Netty的RPC架构学习笔记(十):自定义数据包协议

    文章目录 数据包简介 粘包.分包现象 数据包格式 举个

  2. IM通信协议逆向分析、Wireshark自定义数据包格式解析插件编程学习

    相关学习资料 http://hi.baidu.com/hucyuansheng/item/bf2bfddefd1ee70ad68ed04d http://en.wikipedia.org/wiki/I ...

  3. 在dubbo的一端,看Netty处理数据包,揭网络传输原理

    如今,我们想要开发一个网络应用,那是相当地方便.不过就是引入一个框架,然后设置些参数,然后写写业务代码就搞定了. 写业务代码自然很重要,但是你知道: 你的数据是怎么来的吗?通过网络传输过来的呗. 你知 ...

  4. WebSocket数据包协议详解

    其实我一直想不明白HTML5包装个应用层办议作为Socket通过基础目的是为了什么,其实直接支持Socket tcp相对来说更加简单灵活.既然标准已经制定而浏览器也支持那对于我们开发者来说只能用的分. ...

  5. 【求助】NdisSend,自定义数据包发送失败?

    做ndis hook的时候,自定义了一个数据包,包结构应该没有问题,填充NDIS_PACKET结构是这样的,先初始化:        NdisAllocatePacketPool(&nStat ...

  6. TCP/IP网络编程之数据包协议

    一.概要 在了解了网络字节序之后,接下来就是要讲最最重点的消息协议.数据包是什么呢,数据包可以理解为两个人讲电话说的每一句话的内容.通过大家约定好的方式去理解.达到只有接听电话两个人才懂的东西.在程序 ...

  7. asp.net core中遇到需要自定义数据包解密方法的时候

    最近将公司的项目用.netcore重写, 服务的http外部接口部分收发消息是DES加解密的, 那么在asp.net core mvc的action处理之前需要加入解密这个步骤. 我第一想到的是用fi ...

  8. 示例:Netty 处理 TCP数据分包协议

    一个.Netty解决TCP协议的数据分包的想法 我们知道通过TCP协议发送接收数据时,假设数据过大.接收到的数据会是分包的.比方:                                   ...

  9. 如何实现自定义sk_buff数据包并提交协议栈

    目录 一.自定义数据包的封装流程 1. 分配skb 2.初始定位(skb_reserve) 3.拷贝数据(skb_push / skb_pull / skb_put / ) 4.设置传输层头部 5.设 ...

随机推荐

  1. Readiness probe failed:connection refused

    我的K8S集群在启动一个POD的时候说死起不来,然后就报下面的错误 Events: Type Reason Age From Message ---- ------ ---- ---- ------- ...

  2. 用混入的方法引入vuex,并且解决vuex刷新页面值丢失的问题

    前段时间,做了个官网项目,客户要求将首页的域名后面的参数去除干净,然后就把#去掉了,一转脸,客户让去掉子页面地址栏上的参数,这很棘手,因为子页面的内容是根据子页面地址栏上的参数而定的,如果要去掉这些参 ...

  3. 使用AwesomeWM作为Mate(Gnome相同) Desktop的窗口管理器

    本文通过MetaWeblog自动发布,原文及更新链接:https://extendswind.top/posts/technical/using_awesomewm_as_wm_of_mate_des ...

  4. 使用dig进行DNS查询

    dig全称Domain Information Groper,是一个DNS域名信息查询的工具,可以使用来查看域名解析的过程. dig是linux下自带的工具,如果要在windows下使用需要自行下载和 ...

  5. python2和python3区别

    字符编码: py3中默认字符编码是unicode:py2中默认字符编码是 ASCII,如果文件中出现了中文,需要在顶部加入coding声明#coding:utf8 让用户输入:py3中直接使用inpu ...

  6. Linux中查看某个端口占用情况

    譬如在linux中排查某个端口是否被占用,可以通过如下命令进行排查,排查方法如下: 1: 排查 : 应用是否被人debug.  8787 为端口号 netstat -anp |grep 8787 图中 ...

  7. [WEB安全]给BurpSuite设置非本地的网络代理

    目录 0x01 一般情况 0x02 移动端流量抓取 0x03 多重代理的情形 0x04 参考链接 在Web渗透测试过程中,BurpSuite是不可或缺的神器之一. BurpSuite的核心是代理Pro ...

  8. java集合类型源码解析之ArrayList

    前言 作为一个老码农,不仅要谈架构.谈并发,也不能忘记最基础的语言和数据结构,因此特开辟这个系列的文章,争取每个月写1~2篇关于java基础知识的文章,以温故而知新. 如无特别之处,这个系列文章所使用 ...

  9. postgresql 的 .pgpass密码文件的使用

    pgpass 是 连接 postgresql 时使用的密码文件,通常位置为 ~/.pgpass.在使用某些组件时还真的必须使用.具体的格式为: hostname:port:database:usern ...

  10. What is the yield keyword used for in C#?

    What is the yield keyword used for in C#? https://stackoverflow.com/a/39496/3782855 The yield keywor ...