首先说一下需要注意的问题
1:发送端的javabean 一定要有注解 @Message。这个注解要加在类上。使用@Message 可以标记被序列化的类。类中所有成员都会被序列化。 否则javabean不会被序列化,也就接收不到了。接收端的javabean可以不加这个注解。习惯性的两个端都会加上。
2、因为有 @Message 所以javabean就不需要实现Serializable接口,当然实现了也没有问题(已测);
3、发送的javabean要在Client和Server端两个端都存在,而且名称要完全一致,全类名一致。或者直接打成单独的jar包放在两个端;
4、发送端编码,服务解码。也就是说,编码和和解码的类不一定要两个端都有。
5、网上有许多关于messagepack拆包的问题,我发现我没有发生粘包。。。所以,没有处理这一块。有需要的朋友网上找找,很多的。
netty权威指南里也有相关的介绍。
遇到的坑:(1)一开始没有加上@Message注解(2)解码的一段代码应该是msg.getBytes(msg.readerIndex(), array, 0, length);但是写成 了msg.getBytes(msg.readableBytes(), array, 0, length); 导致解码出的msg长度0,没有内容;
其他的问题暂无。
下面看具体代码,client端和server端是两个不同的工程。
javabean 和编码解码的代码两个端是一样的,这里提供一份。
handler 写的比较简单,可以根据需要改改;
NettyClient.java
package com.aowin.netty.serial.messagepack; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; public class NettyClient { public void connet(){ EventLoopGroup bosLoup=new NioEventLoopGroup(); Bootstrap bootstrap=new Bootstrap(); bootstrap.group(bosLoup) .channel(NioSocketChannel.class) .handler(new NettyClientInitializer()); try { ChannelFuture future= bootstrap.connect("127.0.0.1",8765).sync(); UserInfo userInfoArray[]=new UserInfo[3]; for(int i=0;i<3;i++){ UserInfo userInfo=new UserInfo(); userInfo.setName("netty"); userInfo.setAge(i); userInfoArray[i]=userInfo; } // future.channel().writeAndFlush(Unpooled.copiedBuffer("hello".getBytes())); future.channel().writeAndFlush(userInfoArray); future.channel().closeFuture().sync(); bosLoup.shutdownGracefully(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { NettyClient client=new NettyClient(); client.connet(); } }
NettyClientHandler.java
package com.aowin.netty.serial.messagepack; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; public class NettyClientHandler extends ChannelHandlerAdapter{ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { } }
NettyClientInitializer.java
package com.aowin.netty.serial.messagepack; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.handler.codec.string.StringDecoder; public class NettyClientInitializer extends ChannelInitializer{ @Override protected void initChannel(Channel ch) throws Exception { //ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new MsgPackEncode()); ch.pipeline().addLast(new MsgPackDecode()); ch.pipeline().addLast(new NettyClientHandler()); } }
Server端的代码:
NettyServer.java
package com.aowin.netty.serial.messagepack; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; public class NettyServer { public void bind() { EventLoopGroup bosGroup = new NioEventLoopGroup(); EventLoopGroup workGroup = new NioEventLoopGroup(); ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bosGroup, workGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 1024) .option(ChannelOption.SO_SNDBUF, 32 * 1024) .option(ChannelOption.SO_RCVBUF, 32 * 1024) .option(ChannelOption.SO_KEEPALIVE, true) .handler(new LoggingHandler(LogLevel.DEBUG)) .childHandler(new NettyServerInitializer()); try { ChannelFuture future = bootstrap.bind("127.0.0.1", 8765).sync(); future.channel().closeFuture().sync(); bosGroup.shutdownGracefully(); workGroup.shutdownGracefully(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { NettyServer server=new NettyServer(); server.bind(); } }
NettyServerHandler.java
package com.aowin.netty.serial.messagepack; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.List; import java.util.logging.Logger; public class NettyServerHandler extends ChannelHandlerAdapter { Log logger= LogFactory.getLog(NettyServerHandler.class); @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Listlist= (List ) msg; logger.info(list); logger.info(list.get(0)); logger.info(list.get(1)); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { } }
NettyServerInitializer.java
package com.aowin.netty.serial.messagepack; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.handler.codec.string.StringDecoder; public class NettyServerInitializer extends ChannelInitializer { protected void initChannel(Channel ch) throws Exception { ch.pipeline().addLast(new MsgPackEncode()); ch.pipeline().addLast(new MsgPackDecode()); ch.pipeline().addLast(new NettyServerHandler()); } }
下面是两个端都要有的代码:
解码:
MsgPackDecode.java
package com.aowin.netty.serial.messagepack; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageDecoder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.msgpack.MessagePack; import java.util.List; public class MsgPackDecode extends MessageToMessageDecoder{ private Log logger= LogFactory.getLog(MsgPackDecode.class); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List
编码:
package com.aowin.netty.serial.messagepack; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.msgpack.MessagePack; public class MsgPackEncode extends MessageToByteEncoder
javaBean:
package com.aowin.netty.serial.messagepack; import org.msgpack.annotation.Message; import java.io.Serializable;
//这个注解是加在类上的 @Message public class UserInfo{ String name; int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
运行结果:
客户端:
服务端: