Netty 快速入门系列 - Chapter 7 数据包协议【第十八讲】解决方案-经典协议包结构

本文介绍了一个基于 Netty 实现的 RPC 框架设计,包括数据包结构、编解码处理、响应机制及客户端和服务端的交互流程。通过具体的 Java 代码示例展示了如何构建一个简单的 RPC 通信系统。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


通过定义经典数据包结构:

 * +——----——+——-----——+——----——+——----——+——-----——+
 * | 包头 | 模块号  | 命令号 |  长度  |   数据  |

 * +——----——+——-----——+——----——+——----——+——-----——+

包头:4个字节 -- Int
模块号: 2个字节 -- short
命令号: 2个字节 --short

长度:4个字节 -(仅仅描述数据长度,也可以整个协议长度,这里使用数据长度


通用协议:Request 和 Response

Request 

package com.john.netty.learn.ch09.framework.protocol;


public class Request {

  /**
   * 请求ID
   */
  private long requestId;


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


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


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


  public Request() {


  }


  public short getModule() {
    return module;
  }


  public void setModule(int module) {
    this.module = (short) module;
  }


  public short getCmd() {
    return cmd;
  }


  public void setCmd(int cmd) {
    this.cmd = (short) cmd;
  }


  public byte[] getData() {
    return data;
  }


  public void setData(byte[] data) {
    this.data = data;
  }


  public int size() {


    return this.data == null ? 0 : data.length;
  }


  public void setRequestId(long requestId) {
    this.requestId = requestId;
  }
  
  public long getRequestId() {
    return requestId;
  }


}

Response

package com.john.netty.learn.ch09.framework.protocol;

import com.john.netty.learn.ch09.framework.constants.ResponseStatus;
import com.john.netty.learn.ch09.framework.constants.SystemConstants;


public class Response {

  //Request ID
  private long requestId;


  private short module;


  private short cmd;


  private int status;


  private byte[] data;


  public Response() {


  }


  public Response(Request request) {


     this.requestId = request.getRequestId();
     this.module = request.getModule();
     this.cmd = request.getCmd();
  }


  public void setRequestId(long requestId) {
     this.requestId = requestId;
  }
  
  public long getRequestId() {
     return requestId;
  }


  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 getStatus() {
     return status;
  }


  public void setStatus(int status) {
     this.status = status;
  }


  public byte[] getData() {
     return data;
  }


  public void setData(byte[] data) {
     this.data = data;
  }


  public int size() {


     return this.data == null ? 0 : data.length;
  }


  public boolean isSuccess() {


     return this.status == ResponseStatus.Success_Code;
  }
}

 

编解码 :实现数据Encode 和 Decode (字节流和数据格式的转换)

RequestEncoder -- ChannelDownstreamHandler (下行流处理 )

package com.john.netty.learn.ch09.framework.code;


import java.util.concurrent.atomic.AtomicLong;

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.john.netty.learn.ch09.framework.constants.SystemConstants;
import com.john.netty.learn.ch09.framework.protocol.Request;


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


	public RequestEncoder() {


	}


	@Override
	protected Object encode(ChannelHandlerContext ctx, Channel channel, Object request) throws Exception {


		Request req = (Request) request;


		ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();


		// 写包头
		buffer.writeInt(SystemConstants.Protocol_Header_Flag);

               // 请求ID
		buffer.writeLong(req.getRequestId());


		// Module
		buffer.writeShort(req.getModule());


		// Cmd
		buffer.writeShort(req.getCmd());


		// Data size
		buffer.writeInt(req.size());


		if (req.size() > 0) {


			// data
			buffer.writeBytes(req.getData());
		}


		return buffer;
	}


	

}


RequestDecoder:  -- ChannelUpstreamHandler (上行流处理 )

包头查找

             while (true) {

// 直到找到包头 
if (buffer.readInt() == SystemConstants.Protocol_Header_Flag) {

break;
}

}


package com.john.netty.learn.ch09.framework.code;
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.frame.FrameDecoder;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;


import com.john.netty.learn.ch09.framework.constants.SystemConstants;
import com.john.netty.learn.ch09.framework.protocol.Request;


/**
 * 
 * 数据包格式 +——----——+——-----——+——----——+——----——+——-----——+ | 包头 | 模块号 | 命令号 | 长度
 * | 数据 | +——----——+——-----——+——----——+——----——+——-----——+
 * 
 * 包头4字节 模块号2字节short 命令号2字节short 长度4字节(描述数据部分字节长度)
 * 
 * FrameDecoder 这个decoder可以协助我们解决粘包分包问题
 * 
 */
public class RequestDecoder extends FrameDecoder {


	@Override
	protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {


		// 可读长度必须大于基本长度
		if (buffer.readableBytes() < Base_Protocol_Length) {


			// 数据包不完成,继续等待数据包
			return null;
		}


		// 记录包头开始位置
		int beginReader = buffer.readerIndex();


		while (true) {


			// 直到找到包头 
			if (buffer.readInt() == SystemConstants.Protocol_Header_Flag) {


				break;
			}


		}


		long requsetId = buffer.readLong();
		short module = buffer.readShort();
		short cmd = buffer.readShort();
		int length = buffer.readInt();


		// 判断请求数据是否到齐
		if (buffer.readableBytes() < length) {


			// reset 已经读取Base_Protocol_Length12字节


			buffer.readerIndex(beginReader);


			return null;
		}


		// 读取数据
		byte[] data = new byte[length];


		buffer.readBytes(data);


		Request req = new Request();


		req.setModule(module);
		req.setCmd(cmd);
		req.setData(data);
		req.setRequestId(requsetId);


		return req;


	}


	/**
	 * 数据包最小长度
	 */
	private static int Base_Protocol_Length = 4 + 8 + 2 + 2 + 4;



}


ResponseEncoder (OneToOneEncoder)

package com.john.netty.learn.ch09.framework.code;


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.john.netty.learn.ch09.framework.constants.SystemConstants;
import com.john.netty.learn.ch09.framework.protocol.Request;
import com.john.netty.learn.ch09.framework.protocol.Response;


/**
 * 数据包格式 +——----——+——-----——+——----——+——----——+——-----——+ | 包头 | 模块号 | 命令号 | 长度
 * | 数据 | +——----——+——-----——+——----——+——----——+——-----——+
 * 
 * 包头4字节 模块号2字节short 命令号2字节short 长度4字节(描述数据部分字节长度)
 *
 */
public class ResponseEncoder extends OneToOneEncoder {


	public ResponseEncoder() {


	}


	@Override
	protected Object encode(ChannelHandlerContext ctx, Channel channel, Object response) throws Exception {


		Response resp = (Response) response;


		ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();


		// 写包头
		buffer.writeInt(SystemConstants.Protocol_Header_Flag);
		
		buffer.writeLong(resp.getRequestId());


		// Module
		buffer.writeShort(resp.getModule());


		// Cmd
		buffer.writeShort(resp.getCmd());


		buffer.writeInt(resp.getStatus());


		// Data size
		buffer.writeInt(resp.size());


		if (resp.size() > 0) {


			// data
			buffer.writeBytes(resp.getData());
		}


		return buffer;
	}


}

ResponseDecoder

package com.john.netty.learn.ch09.framework.code;


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.frame.FrameDecoder;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;


import com.john.netty.learn.ch09.framework.constants.SystemConstants;
import com.john.netty.learn.ch09.framework.protocol.Request;
import com.john.netty.learn.ch09.framework.protocol.Response;


/**
 * 
 * 数据包格式 +——----——+——-----——+——----——+——----——+——-----——+ | 包头 | 模块号 | 命令号 | 长度
 * | 数据 | +——----——+——-----——+——----——+——----——+——-----——+
 * 
 * 包头4字节 模块号2字节short 命令号2字节short 长度4字节(描述数据部分字节长度)
 * 
 * FrameDecoder 这个decoder可以协助我们解决粘包分包问题
 * 
 */
public class ResponseDecoder extends FrameDecoder {


	@Override
	protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {


		// 可读长度必须大于基本长度
		if (buffer.readableBytes() < Base_Protocol_Length) {


			// 数据包不完成,继续等待数据包
			return null;
		}


		// 记录包头开始位置
		// 0 =< readerIndex =< writerIndex
		int beginReader = buffer.readerIndex();


		while (true) {


			// 直到找到包头
			if (buffer.readInt() == SystemConstants.Protocol_Header_Flag) {


				break;
			}
		}


		long reqId = buffer.readLong();
		short module = buffer.readShort();
		short cmd = buffer.readShort();
		int status = buffer.readInt();
		int length = buffer.readInt();


		// 判断请求数据是否到齐
		if (buffer.readableBytes() < length) {


			// reset 已经读取Base_Protocol_Length12字节


			buffer.readerIndex(beginReader);


			return null;
		}


		// 读取数据
		byte[] data = new byte[length];


		buffer.readBytes(data);


		Response resp = new Response();


		resp.setModule(module);
		resp.setCmd(cmd);
		resp.setStatus(status);
		resp.setData(data);
		resp.setRequestId(reqId);


		return resp;


	}


	/**
	 * 数据包最小长度
	 */
	private static int Base_Protocol_Length = 4 + 8 + 2 + 2 + 4 + 4;

}


Constants 常亮

ResponseStatus 

package com.john.netty.learn.ch09.framework.constants;

public class ResponseStatus {


	public static final short Success_Code = 0;

	public static final short Failure_Code = 1;

	private ResponseStatus() {

	}

}

SystemConstants 

package com.john.netty.learn.ch09.framework.constants;

public class SystemConstants {

	public static final int Protocol_Header_Flag = -3225489;
	
	private SystemConstants() {
		
	}



}

Future 模式: ResponseFuture 仅仅是一个凭证,通过 wait() 等待数据,当处理数据线程完成数据后,通过setValue 完成 Future notify (CAS - 避免重复notify)

package com.john.netty.learn.ch09.future;
import java.util.concurrent.atomic.AtomicBoolean;

public class ResponseFuture {

	private AtomicBoolean flag;
	private Object value;
	private Object error;

	public ResponseFuture() {
		flag = new AtomicBoolean(false);
	}


	public synchronized Object get() throws InterruptedException {

		if (flag.get()) {

			return isError() ? this.error : value;
		}

		while (!flag.get()) {

			this.wait();
		}

		return isError() ? this.error : value;
	}


	public boolean isError() {

		return this.error != null;
	}


	public synchronized void setValue(Object val) {

		if (flag.compareAndSet(false, true)) {

			this.value = val;
			this.notify();
		}

	}


	public synchronized void setError(Object error) {

		if (flag.compareAndSet(false, true)) {

			this.error = error;
			this.notify();
		}
	}

}

ResponseFutures: 

   public static ResponseFuture getResponseFuture(Request request)  : 通过ConcurrentHashMap 保存当前凭证 request ID

   public static ResponseFuture getResponseFutureById(Long requestId): 通过 Request Id 获取 Future凭证,用于setValue 激活 wait等待

package com.john.netty.learn.ch09.future;

import java.util.concurrent.ConcurrentHashMap;
import com.john.netty.learn.ch09.framework.protocol.Request;

public class ResponseFutures {

	public ResponseFutures() {
	}

	public static ResponseFuture getResponseFuture(Request request) {

		ResponseFuture responseFuture = new ResponseFuture();
		responseFutures.put(request.getRequestId(), responseFuture);
		return responseFuture;

	}


	public static ResponseFuture getResponseFutureById(Long requestId) {

		ResponseFuture responseFuture = responseFutures.get(requestId);
		return responseFuture;
	}

	private static ConcurrentHashMap<Long, ResponseFuture> responseFutures = new ConcurrentHashMap<>();

}

Server 业务处理的服务

Channel Pipelines:

channelPipeline.addLast("Decode", new RequestDecoder());  -- Upstream
channelPipeline.addLast("Encode", new ResponseEncoder());  -- Downstream
channelPipeline.addLast("Handler", new ServerChannelHandler()); -- Simple Channel handler

package com.john.netty.learn.ch09.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 com.john.netty.learn.ch09.framework.code.RequestDecoder;
import com.john.netty.learn.ch09.framework.code.ResponseEncoder;


public class Server {

	public Server(int port) {
		this.port = port;
		serverBootstrap = new ServerBootstrap();
	}


	public void start() {


		serverBootstrap.setFactory(new NioServerSocketChannelFactory(this.boss, this.workers));
		serverBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
			@Override
			public ChannelPipeline getPipeline() throws Exception {

				ChannelPipeline channelPipeline = Channels.pipeline();
				channelPipeline.addLast("Decode", new RequestDecoder());
				channelPipeline.addLast("Encode", new ResponseEncoder());
				channelPipeline.addLast("Handler", new ServerChannelHandler());

				return channelPipeline;
			}
		});


		serverBootstrap.bind(new InetSocketAddress(port));
		System.out.println("server bind " + port);
	}


	private ServerBootstrap serverBootstrap;


	private ExecutorService boss = Executors.newCachedThreadPool();
	private ExecutorService workers = Executors.newCachedThreadPool();


	private int port;
	
	public static void main(String[] args) {
		
		new Server(23).start();
	}
 


}


ServerChannelHandler : 通过 Module 和 Cmd 定位不同的业务服务,然后处理不同的业务。这里方法仅仅Demo,无法商业化。 商业化设计思想:通过Spring Java Scan 和 Annotation 完成业务定位和处理 (使用后置处理器将Server中所有业务module 和 method 保存 RemoteServiceMethodScanContainer 中完成业务处理) -- 如下是我设计RPC Framework Annotation 设计, 以后我将给大家讲解 基于netty RPC Framework 如何设计,这里仅仅介绍冰山一角。


RemoteBundleServiceBeanPostProcessor  后置处理器



package com.john.netty.learn.ch09.server;



import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;


import com.john.netty.learn.ch09.framework.protocol.Request;
import com.john.netty.learn.ch09.framework.protocol.Response;
import com.john.netty.learn.ch09.model.fube.FightRequest;
import com.john.netty.learn.ch09.model.fube.FightResponse;


public class ServerChannelHandler extends SimpleChannelHandler {


	/**
	 * 接收到消息
	 */
	@Override
	public void messageReceived(final ChannelHandlerContext ctx, final MessageEvent e) throws Exception {


		executorService.execute(new Runnable() {


			@Override
			public void run() {


				try {


					execute(ctx, e);


				} catch (Exception e) {


					e.printStackTrace();
				}


			}
		});


	}


	private void execute(ChannelHandlerContext ctx, MessageEvent e) throws Exception {


		Request request = (Request) e.getMessage();
		Response response = new Response(request);


		System.out.println(request.getCmd() + " : " + request.getModule() + " req id:" + response.getRequestId());
		System.out.println("data size :" + request.getData().length);


		if (request.getModule() == 1) {


			if (request.getCmd() == 1) {


				FightRequest fightRequest = new FightRequest();
				fightRequest.decode(request);


				Thread.sleep(1000);


				FightResponse fightResponse = new FightResponse();


				if (fightRequest.getCount() > 100) {


					response.setStatus(1);


					ctx.getChannel().write(response);


					return;
				}


				fightResponse.setGold(999 * fightRequest.getCount());


				response.setData(fightResponse.decode());


				ctx.getChannel().write(response);


				return;
			}
		}
	}


	@Override
	public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		System.out.println("channelConnected");
		super.channelConnected(ctx, e);
	}


	/**
	 * 建立Channel成功,关闭通道时候,才会触发Disconnect
	 */
	@Override
	public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {


		System.out.println("channelDisconnected");


		super.channelDisconnected(ctx, e);
	}


	/**
	 * Channel 关闭
	 */
	@Override
	public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {


		System.out.println("channelClosed");


		super.channelClosed(ctx, e);
	}


	/**
	 * 捕获异常
	 */


	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
		e.getCause().printStackTrace();
		super.exceptionCaught(ctx, e);
	}


	private Executor executorService = Executors.newFixedThreadPool(10);
}


Client 请求业务服务器       

channelPipeline.addLast("encode", new RequestEncoder()); -- Downstream
channelPipeline.addLast("decode", new ResponseDecoder()); -- Upstream
channelPipeline.addLast("handler", new ClientChannelHandler()); --Simple Channel handler

package com.john.netty.learn.ch09.client;


import java.net.InetSocketAddress;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;


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.john.netty.learn.ch09.framework.code.RequestEncoder;
import com.john.netty.learn.ch09.framework.code.ResponseDecoder;
import com.john.netty.learn.ch09.framework.protocol.Request;
import com.john.netty.learn.ch09.future.ResponseFuture;
import com.john.netty.learn.ch09.future.ResponseFutures;
import com.john.netty.learn.ch09.model.fube.FightRequest;
import com.john.netty.learn.ch09.model.fube.FightResponse;


public class Client {


	public Client(String ip, int port) {
		this.ip = ip;
		this.port = port;
	}


	public void connect() throws InterruptedException {


		bootstrap = new ClientBootstrap();


		bootstrap.setFactory(new NioClientSocketChannelFactory(boss, workers));


		bootstrap.setPipelineFactory(new ChannelPipelineFactory() {


			@Override
			public ChannelPipeline getPipeline() throws Exception {


				ChannelPipeline channelPipeline = Channels.pipeline();
				channelPipeline.addLast("encode", new RequestEncoder());
				channelPipeline.addLast("decode", new ResponseDecoder());
				channelPipeline.addLast("handler", new ClientChannelHandler());


				return channelPipeline;
			}
		});


		channelFuture = bootstrap.connect(new InetSocketAddress(this.ip, port)).sync();
	}


	public void console() throws InterruptedException {


		Channel channel = channelFuture.getChannel();


		Scanner scanner = new Scanner(System.in);


		while (true) {


			System.out.println("Please input a fight fube:");


			FightRequest fightRequest = new FightRequest();


			fightRequest.setFubenId(scanner.nextInt());
			fightRequest.setCount(scanner.nextInt());


			fightRequest.writeToLocalBuff();


			byte[] bytes = fightRequest.getSerializerBytes();


			// FutureGet...


			for (int i = 0; i < 1000; i++) {


				final int index = i;


				jobs.submit(new Runnable() {


					@Override
					public void run() {


						try {


							System.out.println("test " + index);


							Request request = new Request();
							request.setModule(1);
							request.setCmd(1);


							request.setData(bytes);


							request.setRequestId(Math.abs(Request_Id.incrementAndGet()));


							System.out.println("request id " + request.getRequestId());


							ResponseFuture responseFuture = ResponseFutures.getResponseFuture(request);


							channel.write(request);


							Object val = responseFuture.get();


							if (responseFuture.isError()) {


								throw new RuntimeException("Error:" + val);
							}


							FightResponse response = (FightResponse) val;


							System.out.println(response.getGold());


						} catch (InterruptedException e) {


							e.printStackTrace();
						}
					}
				});


			}


		}
	}


	private AtomicLong Request_Id = new AtomicLong();


	private String ip;


	private int port;


	private ClientBootstrap bootstrap;


	private ChannelFuture channelFuture;


	private ExecutorService jobs = Executors.newCachedThreadPool();


	private ExecutorService boss = Executors.newSingleThreadExecutor();


	private ExecutorService workers = Executors.newCachedThreadPool();


	public static void main(String[] args) throws InterruptedException {


		Client client = new Client("127.0.0.1", 23);


		client.connect();


		client.console();


	}

}

ClientChannelHandler :

ResponseFuture responseFuture = ResponseFutures.getResponseFutureById(response.getRequestId());

	if (response.isSuccess()) {

			FightResponse fightResponse = new FightResponse();

			fightResponse.decode(response);

                        responseFuture.setValue(fightResponse);
                        return;

         }

	responseFuture.setError(response.getStatus());

package com.john.netty.learn.ch09.client;


import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;


import com.john.netty.learn.ch09.framework.protocol.Response;
import com.john.netty.learn.ch09.future.ResponseFuture;
import com.john.netty.learn.ch09.future.ResponseFutures;
import com.john.netty.learn.ch09.model.fube.FightResponse;


public class ClientChannelHandler extends SimpleChannelHandler {


	/**
	 * 接收到消息
	 */
	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {


		// 没有过滤器
		// ChannelBuffer channelBuffer = (ChannelBuffer) e.getMessage();
		// System.out.println("接收到消息:" + new String(channelBuffer.array()));


		// 回写数据
		// ctx.getChannel().write(ChannelBuffers.wrappedBuffer(("Hi " +
		// e.getMessage()).getBytes()));


		// channelPipeline.addLast("Decoder", new StringDecoder());


		Response response = (Response) e.getMessage();


		ResponseFuture responseFuture = ResponseFutures.getResponseFutureById(response.getRequestId());


		if (response.getModule() == 1) {


			if (response.getCmd() == 1) {


				System.out.println("接收到消息:" + responseFuture);


				if (response.isSuccess()) {


					FightResponse fightResponse = new FightResponse();
					fightResponse.decode(response);


					responseFuture.setValue(fightResponse);


					return;


				}


				responseFuture.setError(response.getStatus());


				return;
			}
		}


	}


	@Override
	public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		System.out.println("channelConnected");
		super.channelConnected(ctx, e);
	}


	/**
	 * 建立Channel成功,关闭通道时候,才会触发Disconnect
	 */
	@Override
	public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {


		System.out.println("channelDisconnected");


		super.channelDisconnected(ctx, e);
	}


	/**
	 * Channel 关闭
	 */
	@Override
	public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {


		System.out.println("channelClosed");


		super.channelClosed(ctx, e);
	}


	/**
	 * 捕获异常
	 */


	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
		e.getCause().printStackTrace();
		super.exceptionCaught(ctx, e);
	}

}

Module:

package com.john.netty.learn.ch09.model.fube;


import com.john.netty.learn.ch09.framework.serialization.AbstractSerializer;


public class FightRequest extends AbstractSerializer {


	private int fubenId;


	private int count;


	public FightRequest() {


	}


	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() throws InstantiationException, IllegalAccessException {


		this.fubenId = this.readIntValue();
		this.count = this.readIntValue();


	}


	@Override
	protected void write() {


		this.writeInt(this.fubenId);
		this.writeInt(this.count);


	}



}



package com.john.netty.learn.ch09.model.fube;


import org.jboss.netty.buffer.ChannelBuffers;


import com.john.netty.learn.ch09.framework.protocol.Response;
import com.john.netty.learn.ch09.framework.serialization.AbstractSerializer;


public class FightResponse extends AbstractSerializer {


	/**
	 * 获取Gold
	 */
	private int gold;


	public FightResponse() {


	}


	public void decode(Response response) throws InstantiationException, IllegalAccessException {
		
		readByBuffer(ChannelBuffers.wrappedBuffer(response.getData()));
	}


	public int getGold() {
		return gold;
	}


	public void setGold(int gold) {
		this.gold = gold;
	}


	@Override
	protected void read() throws InstantiationException, IllegalAccessException {
		this.gold = this.readIntValue();


	}


	@Override
	protected void write() {
		this.writeInt(this.gold);


	}


}

serialization

Serializer 

package com.john.netty.learn.ch09.framework.serialization;


import org.jboss.netty.buffer.ChannelBuffer;


public interface Serializer {


	public void writeToBuffer(ChannelBuffer writeChanneBuffer);


	public void readByBuffer(ChannelBuffer channelBuffer) throws InstantiationException, IllegalAccessException;



}

AbstractSerializer 

package com.john.netty.learn.ch09.framework.serialization;


import java.lang.reflect.Array;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;


import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;


import com.john.netty.learn.ch09.framework.protocol.Request;


public abstract class AbstractSerializer implements Serializer {


	public static final Charset CHARSET = Charset.forName("UTF-8");


	protected ChannelBuffer writeBuffer;


	protected ChannelBuffer readBuffer;


	protected AbstractSerializer() {


	}


	public void readByBuffer(ChannelBuffer channelBuffer) throws InstantiationException, IllegalAccessException {


		this.readBuffer = channelBuffer;
		this.read();


	}


	public void decode(Request req) throws InstantiationException, IllegalAccessException {


		readByBuffer(ChannelBuffers.wrappedBuffer(req.getData()));
	}


	public byte[] decode() {


		this.writeToLocalBuff();


		return getSerializerBytes();
	}


	public byte[] getSerializerBytes() {


		byte[] bytes = new byte[writeBuffer.writerIndex()];


		writeBuffer.readBytes(bytes);


		writeBuffer.clear();


		return bytes;
	}


	public int readIntValue() {


		return readBuffer.readInt();
	}


	public Integer readInt() {


		byte b = readBuffer.readByte();


		if (b == 0) {


			return null;
		}


		return readBuffer.readInt();
	}


	public String readString() {


		short length = this.readBuffer.readShort();


		if (length == -1) {


			return null;
		}


		if (length == 0) {
			return "";
		}
		byte[] bytes = new byte[length];
		readBuffer.readBytes(bytes);


		return new String(bytes);
	}


	public long readLongValue() {


		return readBuffer.readLong();
	}


	public Long readLong() {


		byte b = readBuffer.readByte();


		if (b == 0) {


			return null;
		}


		return readBuffer.readLong();
	}


	public Date readDate() {


		long l = readBuffer.readLong();


		if (l == 0) {


			return null;
		}


		return new Date(l);
	}


	public <T> List<T> readList(Class<T> clz) throws InstantiationException, IllegalAccessException {


		short s = readBuffer.readShort();


		if (s == -1) {


			return null;
		}


		List<T> list = new ArrayList<>(s);


		for (int i = 0; i < s; i++) {


			list.add(readObject(clz));


		}


		return list;
	}


	public <K, V> Map<K, V> readMap(Class<K> keyClz, Class<V> valClz)
			throws InstantiationException, IllegalAccessException {


		short s = readBuffer.readShort();


		if (s == -1) {


			return null;
		}


		Map<K, V> maps = new HashMap<>(s);


		for (int i = 0; i < s; i++) {


			maps.put(readObject(keyClz), readObject(valClz));
		}


		return maps;
	}


	public <T> T readObject(Class<T> clz) throws InstantiationException, IllegalAccessException {


		if (clz == Integer.class) {


			return (T) readInt();
		}


		if (clz == Long.class) {


			return (T) readLong();
		}


		if (clz == String.class) {


			return (T) this.readString();
		}


		if (clz == Date.class) {


			return (T) this.readDate();
		}


		if (List.class.isAssignableFrom(clz)) {


			return (T) this.readList(clz);
		}


		if (Serializer.class.isAssignableFrom(clz)) {


			byte b = this.readBuffer.readByte();


			if (b == 0) {


				return null;
			}


			Object obj = clz.newInstance();


			((Serializer) obj).readByBuffer(readBuffer);


			return (T) obj;


		}


		throw new IllegalArgumentException("不可序列化的类型:" + clz.getName());


	}


	/**
	 * 写入目标buff
	 * 
	 * @param buffer
	 * @return
	 */


	public void writeToBuffer(ChannelBuffer writeChanneBuffer) {


		this.writeBuffer = writeChanneBuffer;


		this.write();


	}


	public ChannelBuffer writeToLocalBuff() {


		writeBuffer = BufferFactory.getBuffer();


		writeToBuffer(writeBuffer);


		return writeBuffer;
	}


	public AbstractSerializer writeByte(byte value) {


		writeBuffer.writeByte(value);


		return this;
	}


	public AbstractSerializer writeByte(Byte value) {


		if (value == null) {


			writeBuffer.writeByte(0);
			return this;
		}


		writeBuffer.writeByte(1);
		writeBuffer.writeByte(value);


		return this;
	}


	public AbstractSerializer writeShort(short value) {


		writeBuffer.writeShort(value);


		return this;
	}


	public AbstractSerializer writeShort(Short value) {


		if (value == null) {


			writeBuffer.writeByte(0);


			return this;
		}


		writeBuffer.writeByte(1);
		writeBuffer.writeShort(value);


		return this;
	}


	public AbstractSerializer writeInt(int value) {


		writeBuffer.writeInt(value);


		return this;
	}


	public AbstractSerializer writeInt(Integer value) {


		if (value == null) {


			writeBuffer.writeByte(0);
			return this;
		}


		writeBuffer.writeByte(1);
		writeBuffer.writeInt(value);


		return this;
	}


	public AbstractSerializer writeDouble(Double value) {


		if (value == null) {


			writeBuffer.writeByte(0);
			return this;
		}


		writeBuffer.writeByte(1);
		writeBuffer.writeDouble(value);


		return this;
	}


	public AbstractSerializer writeDouble(double value) {


		writeBuffer.writeDouble(value);


		return this;
	}


	public AbstractSerializer writeLong(Long value) {


		if (value == null) {


			writeBuffer.writeByte(0);
			return this;
		}


		writeBuffer.writeByte(1);
		writeBuffer.writeLong(value);


		return this;
	}


	public AbstractSerializer writeLong(long value) {


		writeBuffer.writeLong(value);


		return this;
	}


	public AbstractSerializer writeString(String value) {


		if (value == null) {


			writeBuffer.writeShort(-1);
			return this;
		}


		byte[] bytes = value.getBytes(CHARSET);


		writeBuffer.writeShort(bytes.length);


		if (bytes.length > 0) {


			writeBuffer.writeBytes(bytes);
		}


		return this;
	}


	public AbstractSerializer writeDate(Date date) {


		if (date == null) {


			writeBuffer.writeLong(0);


			return this;
		}


		writeBuffer.writeLong(date.getTime());


		return this;


	}


	public <T> AbstractSerializer writeList(List<T> list) {


		if (isEmpty(list)) {


			writeBuffer.writeShort(list == null ? -1 : 0);


			return this;
		}


		writeBuffer.writeShort((short) list.size());


		for (T item : list) {


			writeObject(item);


		}


		return this;
	}


	public <K, V> AbstractSerializer writeMap(Map<K, V> map) {


		if (isEmpty(map)) {


			writeBuffer.writeShort(map == null ? -1 : 0);


			return this;
		}


		writeBuffer.writeShort((short) map.size());


		for (Entry<K, V> entry : map.entrySet()) {


			this.writeObject(entry.getKey());
			this.writeObject(entry.getValue());
		}


		return this;
	}


	public AbstractSerializer writeArray(Array array) {


		if (isEmpty(array)) {


			writeBuffer.writeShort(array == null ? -1 : 0);


			return this;
		}


		int length = Array.getLength(array);


		writeBuffer.writeShort(length);


		for (int i = 0; i < length; i++) {


			this.writeObject(Array.get(array, i));


		}


		return this;


	}


	private boolean isEmpty(Array array) {


		return array == null || Array.getLength(array) == 0;
	}


	public AbstractSerializer writeObject(Object object) {


		if (object instanceof Array) {


			writeArray((Array) object);


			return this;
		}


		if (object instanceof Byte) {


			this.writeByte((Byte) object);


			return this;
		}


		if (object instanceof Short) {


			this.writeShort((Short) object);


			return this;
		}


		if (object instanceof Integer) {


			this.writeInt((Integer) object);


			return this;
		}


		if (object instanceof Date) {


			this.writeDate((Date) object);


			return this;
		}


		if (object instanceof String) {


			this.writeString((String) object);


			return this;
		}


		if (object instanceof List) {


			this.writeList((List) object);


			return this;
		}


		if (object instanceof Map) {


			this.writeMap((Map) object);


			return this;
		}


		if (object instanceof Serializer) {


			if (object == null) {


				writeByte((byte) 0);


				return this;
			}


			writeByte((byte) 1);


			((Serializer) object).writeToBuffer(writeBuffer);


			return this;


		}


		throw new IllegalArgumentException("不可序列化的类型:" + object.getClass());


	}


	/**
	 * 反序列化具体实现
	 */
	protected abstract void read() throws InstantiationException, IllegalAccessException;


	/**
	 * 序列化具体实现
	 */
	protected abstract void write();


	private boolean isEmpty(Map map) {


		return map == null || map.isEmpty();
	}


	private boolean isEmpty(List<?> list) {


		return list == null || list.isEmpty();
	}


}

BufferFactory

package com.john.netty.learn.ch09.framework.serialization;


import java.nio.ByteOrder;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;




public class BufferFactory {


	public static ByteOrder BYTE_ORDER = ByteOrder.BIG_ENDIAN;


	/**
	 * 获取一个buffer
	 * 
	 * @return
	 */
	public static ChannelBuffer getBuffer() {
		ChannelBuffer dynamicBuffer = ChannelBuffers.dynamicBuffer();
		return dynamicBuffer;
	}


	/**
	 * 将数据写入buffer
	 * 
	 * @param bytes
	 * @return
	 */
	public static ChannelBuffer getBuffer(byte[] bytes) {
		ChannelBuffer copiedBuffer = ChannelBuffers.copiedBuffer(bytes);
		return copiedBuffer;
	}


}
所有源码下载 :https://download.youkuaiyun.com/download/netcobol/10308871
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值