使用netty主要用于建立客户端、服务端,在两者发送字符串(字节)、文件或者对象等,来满足在应用中的需求,这里先说下字符串的传送。个人认为,netty的传送什么都不重要,重要的是采用什么样的转码、解码方式。本人在做日志分析组件的过程中开始将日志信息以字符串的形式通过客户端传送给服务端,主要的代码片段如下:
客户端:
//客户端通道和尝试连接的帮助类 bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); //配置一个子channel pipeline bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); pipeline.addLast("handler", new LogClientHandler()); return pipeline; } }); // 配置channel的选项集 bootstrap.setOption("tcpNoDelay", true); bootstrap.setOption("keepAlive", false); //连接超时时间为3s bootstrap.setOption("connectTimeoutMillis", 3000);
LogClientHandler没有什么特别的处理。
服务端:
//接受传入连接的帮助类 bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); //配置一个子channel pipeline //每个channel都会拥有自己的ChannelPipeline bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); //处理业务逻辑的帮组类 pipeline.addLast("handler", new LogServerHandler()); return pipeline; } }); //配置通道 // 子channel的属性集 //设置缓存区大小20M bootstrap.setOption("child.receiveBufferSize", 1048576*20); bootstrap.setOption("child.keepAlive", false); bootstrap.setOption("child.tcpNoDelay", true); //创建一个绑定到指定的本地地址的channel bootstrap.bind(configInet(host, port));
LogServerHandler中messageReceived(ChannelHandlerContext ctx, MessageEvent e)直接接受客户端发送的字符串。
netty中在传送字符串的长度有限制,貌似超过1024个字节就截断了,导致接收的信息部完整,经查阅后可采用传送字节数组的方式来解决这个问题:
1、首先在客户端、服务端将转码、解码的方式修改成如下:
pipeline.addLast("decoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
pipeline.addLast("encoder", new LengthFieldPrepender(4, false));
2、客户端传送字符串时需要这样:
ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
buffer.writeBytes(log.getBytes(ConstantSet.CHAR_DECODER));
//当与远程端建立连接以后即刻发送日志信息
channel.write(buffer);
buffer.clear();
3、服务端接收字符串:
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
//添加到日志队列中
ChannelBuffer buffer = (ChannelBuffer)e.getMessage();
String log = buffer.toString(Charset.forName(ConstantSet.CHAR_DECODER));
}
注:上述的字符串与字节数组转换时,采用的字符集编码请保持一致。