netty自定義數據包(報文協議)

1、請求編碼器 RequestEncoder

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字節(描述數據部分字節長度)
 * 
 * @author 
 *
 */
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;
	}

}

2、請求解碼器 RequestDecoder

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字節(描述數據部分字節長度)
 * 
 * @author 
 *
 */
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;
	}

}

3、response解碼器  ResponseDecoder

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字節(描述數據部分字節長度)
 * 
 * @author 
 *
 */
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 = new Response();
			response.setModule(module);
			response.setCmd(cmd);
			response.setStateCode(stateCode);
			response.setData(data);
			
			//繼續往下傳遞 
			return response;
			
		}
		//數據包不完整,需要等待後面的包來
		return null;
	}

}

 

4、響應編碼器 ResponseEncoder

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字節(描述數據部分字節長度)
 * 
 * @author
 *
 */
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;
	}

}

5、netty  server 

 

package com.server;

import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;

import com.cn.codc.RequestDecoder;
import com.cn.codc.ResponseEncoder;
/**
 * netty服務端入門
 * @author 
 *
 */
public class Server {

	public static void main(String[] args) {

		//服務類
		ServerBootstrap bootstrap = new ServerBootstrap();
		
		//boss線程監聽端口,worker線程負責數據讀寫
		ExecutorService boss = Executors.newCachedThreadPool();
		ExecutorService worker = Executors.newCachedThreadPool();
		
		//設置niosocket工廠
		bootstrap.setFactory(new NioServerSocketChannelFactory(boss, worker));
		
		//設置管道的工廠
		bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
			
			@Override
			public ChannelPipeline getPipeline() throws Exception {

				ChannelPipeline pipeline = Channels.pipeline();
				pipeline.addLast("decoder", new RequestDecoder());
				pipeline.addLast("encoder", new ResponseEncoder());
				pipeline.addLast("helloHandler", new HelloHandler());
				return pipeline;
			}
		});
		
		bootstrap.bind(new InetSocketAddress(10101));
		
		System.out.println("start!!!");
		
	}

}

6、netty client

package com.client;

import java.net.InetSocketAddress;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import com.cn.codc.RequestEncoder;
import com.cn.codc.ResponseDecoder;
import com.cn.model.Request;
import com.cn.module.fuben.request.FightRequest;
/**
 * netty客戶端入門
 * @author 
 *
 */
public class Client {

	public static void main(String[] args) throws InterruptedException {
		
		//服務類
		ClientBootstrap bootstrap = new  ClientBootstrap();
		
		//線程池
		ExecutorService boss = Executors.newCachedThreadPool();
		ExecutorService worker = Executors.newCachedThreadPool();
		
		//socket工廠
		bootstrap.setFactory(new NioClientSocketChannelFactory(boss, worker));
		
		//管道工廠
		bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
			
			@Override
			public ChannelPipeline getPipeline() throws Exception {
				ChannelPipeline pipeline = Channels.pipeline();
				pipeline.addLast("decoder", new ResponseDecoder());
				pipeline.addLast("encoder", new RequestEncoder());
				pipeline.addLast("hiHandler", new HiHandler());
				return pipeline;
			}
		});
		
		//連接服務端
		ChannelFuture connect = bootstrap.connect(new InetSocketAddress("127.0.0.1", 10101));
		Channel channel = connect.sync().getChannel();
		
		System.out.println("client start");
		
		Scanner scanner = new Scanner(System.in);
		while(true){
			System.out.println("請輸入");
			int fubenId = Integer.parseInt(scanner.nextLine());
			int count = Integer.parseInt(scanner.nextLine());
			
			FightRequest fightRequest = new FightRequest();
			fightRequest.setFubenId(fubenId);
			fightRequest.setCount(count);
			
			Request request = new Request();
			request.setModule((short) 1);
			request.setCmd((short) 1);
			request.setData(fightRequest.getBytes());
			//發送請求
			channel.write(request);
		}
	}

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章