通过定义经典数据包结构:
* +——----——+——-----——+——----——+——----——+——-----——+
* | 包头 | 模块号 | 命令号 | 长度 | 数据 |
* +——----——+——-----——+——----——+——----——+——-----——+
包头: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