自定义数据包协议

自定义数据包协议

粘包 分包

两条消息

give me a coffee   give me a tea
give me a coffeegive me a tea   粘包现象
give me
 a coffeegive me a tea     分包现象

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

  • 分割符

give me a coffee|give me a tea|

give me a coffee|
give me a tea|
  • 长度 + 数据

16give me a coffee13give me a tea

16give me a coffee
13give me a tea

数据包结构

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

代码

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.common.constant.ConstantValue;
import com.cn.common.model.Request;

/**
 * 请求解码器
 * <pre>
 * 数据包格式
 * +——----——+——-----——+——----——+——----——+——-----——+
 * | 包头          | 模块号        | 命令号      |  长度        |   数据       |
 * +——----——+——-----——+——----——+——----——+——-----——+
 * </pre>
 * 包头4字节
 * 模块号2字节short
 * 命令号2字节short
 * 长度4字节(描述数据部分字节长度)
 *
 *
 *
 */
public class RequestDecoder 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){
			//防止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();

			//判断请求数据包数据是否到齐
			if(buffer.readableBytes() < length){
				//还原读指针
				buffer.readerIndex(beginReader);
				return null;
			}

			//读取data数据
			byte[] data = new byte[length];
			buffer.readBytes(data);

			Request request = new Request();
			request.setModule(module);
			request.setCmd(cmd);
			request.setData(data);

			//继续往下传递
			return request;

		}
		//数据包不完整,需要等待后面的包来
		return null;
	}

}
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.common.constant.ConstantValue;
import com.cn.common.model.Request;

/**
 * 请求编码器
 * <pre>
 * 数据包格式
 * +——----——+——-----——+——----——+——----——+——-----——+
 * | 包头          | 模块号        | 命令号      |  长度        |   数据       |
 * +——----——+——-----——+——----——+——----——+——-----——+
 * </pre>
 * 包头4字节
 * 模块号2字节short
 * 命令号2字节short
 * 长度4字节(描述数据部分字节长度)
 *
 *
 *
 */
public class RequestEncoder extends OneToOneEncoder{

	@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;
	}

}
/**
 * 请求对象
 *
 *
 */
public class Request {

	/**
	 * 请求模块
	 */
	private short module;

	/**
	 * 命令号
	 */
	private short cmd;

	/**
	 * 数据部分
	 */
	private byte[] data;


}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值