Netty 实现自定义消息格式

Netty 实现基于google-protocol-buffer自定义消息格式

首先自己定义一个消息格式:

package fhq;

option java_package = "com.wesker.protocol";
option java_outer_classname = "ProtocolTypeMessage";

enum ProtocolType{
	EXCEPTION = 1;
	INFO = 2;
	SHUTDOWN = 3;
	EVALUATE_TO_TYPESET = 4;
	EVALUATE_TO_MATHML = 5;
}
package fhq;

option java_package = "com.wesker.protocol";
option java_outer_classname = "ProtocolMessage";
import "ProtocolTypeMessage";

message Protocol {
	required ProtocolType type = 1;
	required bytes data = 2;
}

这里的Protocol就是我们要处理的消息了。type是消息类型,data是数据。接下来生成java代码:

protoc --java_out=/home/michael/protocol/ ProtocolTypeMessage
protoc --java_out=/home/michael/protocol/ ProtocolMessage

160629_DmfA_147822.png

接下来就是定义基于netty的消息转换器了,一个编码:将自定义的消息转换成byte[]。 这里用范型指定我们刚才定义好的消息类型。

public class MessageEncoder extends MessageToByteEncoder<Protocol>{

	@Override
	protected void encode(ChannelHandlerContext context, Protocol protocol, ByteBuf out)
			throws Exception {
		byte[] data = protocol.toByteArray();
        out.writeInt(data.length);
        out.writeBytes(data);
	}
}

一个解码:将byte[]转换成自定义的消息

public class MessageDecoder extends ByteToMessageDecoder {

	@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
		if (in.readableBytes() < 4) {
			return;
		}
		in.markReaderIndex();
		int dataLength = in.readInt();
		if (in.readableBytes() < dataLength) {
			in.resetReaderIndex();
			return;
		}
		byte[] decoded = new byte[dataLength];
		in.readBytes(decoded);
		out.add(Protocol.parseFrom(decoded));
	}

}

在初始化server的时候将这2个东西放进去,和一个server处理自定义消息的handler

public class MyServerHandler extends SimpleChannelInboundHandler<Protocol>{

	@Override
	protected void messageReceived(ChannelHandlerContext arg0, Protocol arg1) throws Exception {
		//do something.....
	}

}
ServerBootstrap boot = new ServerBootstrap();
		boot.group(core.getBoss(), core.getWorker()).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>(){
			@Override
					protected void initChannel(SocketChannel ch)
							throws Exception {
						ChannelPipeline p = ch.pipeline();
						SSLEngine engine = core.getSslContext().createSSLEngine();
						engine.setUseClientMode(false);
						p.addLast("ssl", new SslHandler(engine));
						p.addLast(new LoggingHandler(LogLevel.INFO));
						p.addLast("encoder", new MessageEncoder());//在这里
						p.addLast("decoder", new MessageDecoder());//在这里
                                                p.addLast("MyServerHandler", new MyServerHandler());//server端处理消息
					}});

同样客户端也要做同样的事情:

public class MyClientHandler extends SimpleChannelInboundHandler<Protocol>{

	@Override
	protected void messageReceived(ChannelHandlerContext arg0, Protocol arg1) throws Exception {
		//do something.....
	}

}
Bootstrap bootstrap = new Bootstrap();
		bootstrap.group(core.getGroup()).channel(NioSocketChannel.class)
				.handler(new ChannelInitializer<SocketChannel>(){
					@Override
					protected void initChannel(SocketChannel ch)
							throws Exception {
						ChannelPipeline p = ch.pipeline();
						SSLEngine engine = core.getSslContext().createSSLEngine();
						engine.setUseClientMode(true);
						p.addLast("ssl", new SslHandler(engine));
						p.addLast("encoder", new MessageEncoder());//这里
						p.addLast("decoder", new MessageDecoder());//这里
						p.addLast("MyClientHandler", new MyClientHandler());//client端处理消息
					}});

到这里你就可以使用自己的消息格式了。

Netty 4以后都自带了对google-protocol-buffer的解析器 : 

ProtobufDecoder ProtobufEncoder

懒得自己定义就用这个。需要注意的是,ProtobufDecoder需要一个protocol-buffer的实例来才能初始化。(调用getDefaultInstance())

写的非常仓促。。。。。。可能好多地方没有写明白。。有什么问题大家可以圈我。

转载于:https://my.oschina.net/grrrr/blog/187450

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty框架提供了很多编码器和解码器,但有时候我们需要自定义编码器和解码器,以满足特定的业务需求。在Netty中,自定义编码器和解码器非常简单,只需要继承ByteToMessageDecoder或MessageToByteEncoder,并实现其中的抽象方法即可。 以下是一个自定义编码器的示例代码: ```java public class MyEncoder extends MessageToByteEncoder<MyMessage> { @Override protected void encode(ChannelHandlerContext ctx, MyMessage msg, ByteBuf out) throws Exception { byte[] data = msg.getData(); out.writeInt(data.length); out.writeBytes(data); } } ``` 在这个示例中,我们定义了一个名为MyEncoder的编码器,它继承自MessageToByteEncoder,并实现了encode方法。在encode方法中,我们首先获取消息的数据,然后将消息的数据长度写入到ByteBuf中,最后将消息的数据写入到ByteBuf中。 以下是一个自定义解码器的示例代码: ```java public class MyDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { if (in.readableBytes() < 4) { return; } int length = in.readInt(); if (in.readableBytes() < length) { in.resetReaderIndex(); return; } byte[] data = new byte[length]; in.readBytes(data); MyMessage message = new MyMessage(length, data); out.add(message); } } ``` 在这个示例中,我们定义了一个名为MyDecoder的解码器,它继承自ByteToMessageDecoder,并实现了decode方法。在decode方法中,我们首先判断ByteBuf中是否有足够的字节可读,如果不够则直接返回。然后从ByteBuf中读取消息的长度和数据,并将它们封装成MyMessage对象,加入到解码结果列表中。 在使用自定义编码器和解码器时,只需要将它们注册到ChannelPipeline中即可。以下是注册的示例代码: ```java ChannelPipeline pipeline = channel.pipeline(); pipeline.addLast(new MyDecoder()); pipeline.addLast(new MyEncoder()); ``` 这样,在ChannelPipeline中的所有ChannelHandler都可以使用MyMessage对象,而无需关心它们与字节流的转换过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值