导入依赖
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>msgpack</artifactId>
<version>0.6.12</version>
</dependency>
客户端
/**
* 类说明:客户端
*/
public class ClientMsgPackEcho {
private final String host;
public ClientMsgPackEcho(String host) {
this.host = host;
}
public void start() throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();/*线程组*/
try {
final Bootstrap b = new Bootstrap();
;/*客户端启动必须*/
b.group(group)/*将线程组传入*/
.channel(NioSocketChannel.class)/*指定使用NIO进行网络传输*/
/*配置要连接服务器的ip地址和端口*/
.remoteAddress(
new InetSocketAddress(host, ServerMsgPackEcho.PORT))
.handler(new ChannelInitializerImp());
ChannelFuture f = b.connect().sync();
System.out.println("已连接到服务器.....");
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
private static class ChannelInitializerImp extends ChannelInitializer<Channel> {
@Override
protected void initChannel(Channel ch) throws Exception {
//这里设置报文的包头长度来避免粘包,设置为最大2个字节长度,即是最大长度65536
ch.pipeline().addLast("frameEncoder",
new LengthFieldPrepender(2));
//对发送的数据进行序列化
ch.pipeline().addLast(new MsgPackEncoder());
//处理服务器的应答,因为服务器传来的是一个字符串,所以可以使用LineBasedFrameDecoder
ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
ch.pipeline().addLast(new MsgPackClientHandler(5));
}
}
public static void main(String[] args) throws InterruptedException {
new ClientMsgPackEcho("127.0.0.1").start();
}
}
自定义序列化处理器
/**
* 类说明:服务端反序列化处理器
*/
public class MsgPackDecoder extends MessageToMessageDecoder<ByteBuf> {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg,
List<Object> out) throws Exception {
int length = msg.readableBytes();
byte[] array = new byte[length];
msg.getBytes(msg.readerIndex(), array, 0, length);
MessagePack messagePack = new MessagePack();
//反序列化后将数据给下一个处理器处理
out.add(messagePack.read(array, User.class));
}
}
客户端处理器
/**
* 类说明:客户端处理器
*/
public class MsgPackClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
private final int sendNumber;
public MsgPackClientHandler(int sendNumber) {
this.sendNumber = sendNumber;
}
private AtomicInteger counter = new AtomicInteger(0);
/*** 客户端读取到网络数据后的处理*/
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
System.out.println("client Accept["+msg.toString(CharsetUtil.UTF_8)
+"] and the counter is:"+counter.incrementAndGet());
}
/*** 客户端被通知channel活跃后,做事*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
User[] users = makeUsers();
//发送数据
for(User user:users){
System.out.println("Send user:"+user);
ctx.write(user);
}
ctx.flush();
}
/*** 发生异常后的处理*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
/*生成用户实体类的数组,以供发送*/
private User[] makeUsers(){
User[] users=new User[sendNumber];
User user =null;
for(int i=0;i<sendNumber;i++){
user=new User();
user.setAge(i);
String userName = "ABCDEFG --->"+i;
user.setUserName(userName);
user.setId("No:"+(sendNumber-i));
user.setUserContact(
new UserContact(userName+"@xiangxue.com","133"));
users[i]=user;
}
return users;
}
}
服务端
/**
* 类说明:服务端
*/
public class ServerMsgPackEcho {
public static final int PORT = 9995;
public static void main(String[] args) throws InterruptedException {
ServerMsgPackEcho serverMsgPackEcho = new ServerMsgPackEcho();
System.out.println("服务器即将启动");
serverMsgPackEcho.start();
}
public void start() throws InterruptedException {
final MsgPackServerHandler serverHandler = new MsgPackServerHandler();
EventLoopGroup group = new NioEventLoopGroup();/*线程组*/
try {
ServerBootstrap b = new ServerBootstrap();/*服务端启动必须*/
b.group(group)/*将线程组传入*/
.channel(NioServerSocketChannel.class)/*指定使用NIO进行网络传输*/
.localAddress(new InetSocketAddress(PORT))/*指定服务器监听端口*/
/*服务端每接收到一个连接请求,就会新启一个socket通信,也就是channel,
所以下面这段代码的作用就是为这个子channel增加handle*/
.childHandler(new ChannelInitializerImp());
ChannelFuture f = b.bind().sync();/*异步绑定到服务器,sync()会阻塞直到完成*/
System.out.println("服务器启动完成,等待客户端的连接和数据.....");
f.channel().closeFuture().sync();/*阻塞直到服务器的channel关闭*/
} finally {
group.shutdownGracefully().sync();/*优雅关闭线程组*/
}
}
private static class ChannelInitializerImp extends ChannelInitializer<Channel> {
@Override
protected void initChannel(Channel ch) throws Exception {
//根据消息长度,从中剥离出完整的实际数据
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(65535,
0, 2, 0, 2));
//反序列化
ch.pipeline().addLast(new MsgPackDecoder());
//将反序列化后的实体类交给业务处理
ch.pipeline().addLast(new MsgPackServerHandler());
}
}
}
自定义反序列化处理器
/**
* 类说明:客户端序列化处理器
*/
public class MsgPackEncoder extends MessageToByteEncoder<Object> {
@Override
protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out)
throws Exception {
MessagePack messagePack = new MessagePack();
byte[] raw = messagePack.write(msg);
out.writeBytes(raw);
}
}
服务端处理器
/**
* 类说明:自己的业务处理
*/
@ChannelHandler.Sharable
public class MsgPackServerHandler extends ChannelInboundHandlerAdapter {
private AtomicInteger counter = new AtomicInteger(0);
/*** 服务端读取到网络数据后的处理*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//将上一个handler生成的数据强制转型
User user = (User)msg;
System.out.println("Server Accept["+user
+"] and the counter is:"+counter.incrementAndGet());
//服务器的应答
String resp = "I process user :"+user.getUserName()
+ System.getProperty("line.separator");
ctx.writeAndFlush(Unpooled.copiedBuffer(resp.getBytes()));
}
/*** 发生异常后的处理*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}