MessagePack 序列化框架在netty中的簡單實現。
MessagePack 序列化框架的簡單實現。
1.匯入相關jar包
如果使用maven的話,直接新增依賴即可:
<properties>
<msgpack.version>0.6.12</msgpack.version>
</properties>
<!-- MessagePack dependency -->
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>msgpack</artifactId>
<version>${msgpack.version}</version>
</dependency>
如果是普通java專案,去[maven中央倉庫](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22ch.dissem.msgpack%22)下載即可
2.編寫Encoder(編碼器)
繼承MessageToByteEncoder
public class MsgpackEncoder extends MessageToByteEncoder {
@Override
protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
// TODO Auto-generated method stub
MessagePack msgpack = new MessagePack();
out.writeBytes(msgpack.write(msg));
}
}
3.編寫Decoder(編碼器)
繼承MessageToMessageDecoder,設定型別為ByteBuf
public class MsgpackDecoder extends MessageToMessageDecoder<ByteBuf> {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
// TODO Auto-generated method stub
final int length = msg.readableBytes();
byte[] b = new byte[length];
msg.getBytes(msg.readerIndex(), b,0,length);
MessagePack msgpack = new MessagePack();
out.add(msgpack.read(b));
}
}
4.在Client端和Server端增加編碼器和解碼器,順便增加粘包/拆包支援:
客戶端程式碼:
public class NettyClient {
private void bind(int port,String host){
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true).handler(new ClientHandlerInit());
try {
ChannelFuture f = b.connect(host, port).sync();
f.channel().closeFuture().sync();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
group.shutdownGracefully();
}
}
/*
*這裡是增加相應的解碼編碼器。
*/
private class ClientHandlerInit extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// TODO Auto-generated method stub
//這裡設定通過增加包頭表示報文長度來避免粘包
ch.pipeline().addLast("frameDecoder",new LengthFieldBasedFrameDecoder(1024, 0, 2,0,2));
//增加解碼器
ch.pipeline().addLast("msgpack decoder",new MsgpackDecoder());
//這裡設定讀取報文的包頭長度來避免粘包
ch.pipeline().addLast("frameEncoder",new LengthFieldPrepender(2));
//增加編碼器
ch.pipeline().addLast("msgpack encoder",new MsgpackEncoder());
ch.pipeline().addLast(new ClientHandler());
}
}
public static void main(String[] args) throws UnknownHostException {
// TODO Auto-generated method stub
NettyClient client = new NettyClient();
client.bind(12580,"localhost");
}
}
Server端程式碼,和client端大同小異,不再贅述
public class TimeServer {
public void bind(int port) throws Exception {
EventLoopGroup bossGruop = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGruop, workGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024).childHandler(new ChildChannelHandler());
try {
ChannelFuture future = bootstrap.bind(port).sync();
future.channel().closeFuture().sync();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
bossGruop.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// TODO Auto-generated method stub
ch.pipeline().addLast("frameDecoder",new LengthFieldBasedFrameDecoder(1024, 0, 2,0,2));
ch.pipeline().addLast("msgpack decoder",new MsgpackDecoder());
ch.pipeline().addLast("frameEncoder",new LengthFieldPrepender(2));
ch.pipeline().addLast("msgpack encoder",new MsgpackEncoder());
ch.pipeline().addLast(new TimeServerHandler());
}
}
public static void main(String[] args) {
int port = 12580;
try {
new TimeServer().bind(port);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
5.接下來自定義一個model類來實作為訊息類:
/*
*這裡出現了兩個坑,一個是需要在訊息類上加上註解Message,另一個就是必須要有預設的無參構造器,不然就會報如下的錯誤:
*org.msgpack.template.builder.BuildContext build
*SEVERE: builder: 這個問題在github上有個issue解釋了
*/
@Message
public class UserInfo {
private String username;
private String age;
public String getUsername() {
return username;
}
public String getAge() {
return age;
}
public void setUsername(String username) {
this.username = username;
}
public void setAge(String age) {
this.age = age;
}
public UserInfo(String username, String age) {
super();
this.username = username;
this.age = age;
}
public UserInfo(){
}
}
6.對應的ServerHandler和ClientHandler程式碼:
serverhandler:
public class TimeServerHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// TODO Auto-generated method stub
try {
//直接輸出msg
System.out.println(msg.toString());
String remsg = new String("has receive");
//回覆has receive 給客戶端
ctx.write(remsg);
} catch (Exception e) {
e.printStackTrace();
}finally {
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
ctx.flush();
}
}
clientHanlder:
public class ClientHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// TODO Auto-generated method stub
System.out.println(msg);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
//傳送50個UserInfo給伺服器,由於啟用了粘包/拆包支援,所以這裡連續傳送多個也不會出現粘包的現象。
for (int i = 0; i < 50; i++) {
UserInfo userInfo = new UserInfo();
userInfo.setAge(i + "year");
userInfo.setUsername("senninha");
ctx.write(userInfo);
}
ctx.flush();
System.out.println("-----------------send over-----------------");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// TODO Auto-generated method stub
System.out.println("error");
}
}
客戶端控制檯:
-----------------send over-----------------
"has receive"
"has receive"
"has receive"
"has receive"
"has receive"
"has receive"
........
伺服器控制檯:
["senninha","0year"]
["senninha","1year"]
["senninha","2year"]
["senninha","3year"]
["senninha","4year"]
["senninha","5year"]
["senninha","6year"]
至此,一個MessagePack序列化框架的入門就搭建好了,參考了《Netty權威指南》。
相關文章
- netty 實現簡單的rpc呼叫NettyRPC
- Java使用Netty實現簡單的RPCJavaNettyRPC
- 簡單的Java實現Netty進行通訊JavaNetty
- Go語言實現簡單的反序列化Go
- Netty(二) 實現簡單Http伺服器NettyHTTP伺服器
- 自己用 Netty 實現一個簡單的 RPCNettyRPC
- JS實現簡單的判斷文字框長度JS
- Java:對一個物件序列化和反序列化的簡單實現Java物件
- 探險新型序列化工具MessagePack
- 用java實現一個簡單的序列化的例子(轉)Java
- 用java實現一個簡單的序列化的例子 (轉)Java
- 基於Netty的Android系統IM簡單實現原理NettyAndroid
- 使用Netty和動態代理實現一個簡單的RPCNettyRPC
- netty系列之:EventExecutor,EventExecutorGroup和netty中的實現Netty
- netty系列之:Bootstrap,ServerBootstrap和netty中的實現NettybootServer
- netty系列之:channel,ServerChannel和netty中的實現NettyServer
- Android中SharePreferences的簡單實現Android
- js中trim函式的簡單實現JS函式
- easyui利用combobox實現下拉框簡單介紹UI
- JS原生實現表單序列化JS
- netty系列之:netty實現http2中的流控制NettyHTTP
- Node中EventEmitter理解與簡單實現MIT
- 實現簡單的BitMap
- ArrayList的簡單實現
- AOP的簡單實現
- 簡單的 HashMap 實現HashMap
- 簡單的Filter實現Filter
- Promise的簡單實現Promise
- Flutter | 超實用簡單選單彈出框 PopupMenuButtonFlutter
- 計算機程式的思維邏輯 (63) – 實用序列化: JSON/XML/MessagePack計算機JSONXML
- 計算機程式的思維邏輯 (63) - 實用序列化: JSON/XML/MessagePack計算機JSONXML
- 原生JS實現表單序列化serialize()JS
- Struts2中攔截器的簡單實現
- 簡單的實現vue原理Vue
- 簡單的實現React原理React
- java實現簡單的JDBCJavaJDBC
- php實現簡單的SQLBuilderPHPSQLUI
- kd樹的簡單實現