Netty应用基础篇

本篇主要介绍Netty解决TCP粘包和拆包问题。

概念介绍

TCP是个”流"协议,所谓流,就是没有界限的一串数据。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。

产生原因:

1,应用程序write写入的字节大小大于套接口发送缓冲区大小;

2,进行MSS大小的TCP分段;

3,以太网帧的payload大于MTU进行IP分片。

实例如下

服务端代码:

package com.huawei.netty.test;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * Created by liuzhengqiu on 2017/10/15.
 */
public class NettyServer
{
    public void bind(int port) throws Exception
    {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try
        {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,1024)
                    .childHandler(new ChildChannelHandler());
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            channelFuture.channel().closeFuture().sync();
        }
        finally
        {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private class ChildChannelHandler extends ChannelInitializer<SocketChannel>
    {

        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception
        {
            socketChannel.pipeline().addLast(new NettyServerHandler());
        }
    }

    public static void main(String[] args) throws Exception {
        new NettyServer().bind(8080);
    }
}

 

package com.huawei.netty.test;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.Date;

/**
 * Created by liuzhengqiu on 2017/10/15.
 */
public class NettyServerHandler extends ChannelInboundHandlerAdapter
{
    private int counter;

    @Override
    public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception
    {
        ByteBuf byteBuf = (ByteBuf) msg;
        byte[] req = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(req);
        String body = new String(req,"UTF-8");
        System.out.println("The time server receive order :" + body
            + ";the counter is :"+ ++counter);

        String currentTime = "hello world".equalsIgnoreCase(body)?new Date().toString():"bad order";
        currentTime += System.getProperty("line.separator");
        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
        ctx.write(resp);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception
    {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause)
    {
        ctx.close();
    }
}

 

客户端代码如下:

package com.huawei.netty.test;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * Created by liuzhengqiu on 2017/10/15.
 */
public class NettyClient
{
    public void connect(int port,String host) throws Exception
    {
        EventLoopGroup group = new NioEventLoopGroup();
        try
        {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY,true)
                    .handler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new NettyClientHandler());
                        }
                    });
            ChannelFuture f = bootstrap.connect(host,port).sync();
            f.channel().closeFuture().sync();
        }
        finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        new NettyClient().connect(8080,"127.0.0.1");
    }
}

 

package com.huawei.netty.test;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/**
 * Created by liuzhengqiu on 2017/10/15.
 */
public class NettyClientHandler extends ChannelInboundHandlerAdapter
{
    private int counter;

    private final ByteBuf msg;

    public NettyClientHandler()
    {
        byte[] req = ("hello world"+System.getProperty("line.separator")).getBytes();
        msg = Unpooled.buffer(req.length);
        msg.writeBytes(req);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx)
    {
        ByteBuf message = null;
        byte[] req = ("hello world"+System.getProperty("line.separator")).getBytes();
        for (int i=0;i<100;i++)
        {
            message = Unpooled.buffer(req.length);
            message.writeBytes(req);
            ctx.writeAndFlush(message);
        }
        ctx.writeAndFlush(msg);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception
    {
        ByteBuf buf = (ByteBuf) msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);

        String body = new String(req,"UTF-8");
        System.out.println("Now is :"+body);
    }
}

 

服务端运行结果:

The time server receive order :hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello worl;the counter is :1
The time server receive order :d
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
;the counter is :2

客户端运行结果如下:

Now is :bad order
bad order

Netty的解决方法

利用LineBasedFrameDecoder和StringDecoder解决TCP粘包问题。

LineBasedFrameDecoder原理:依次遍历ByteBuf中的可读字节,判断看是否有”\n"或者“\r\n",如果有,就以此位置为结束位置,从可读索引到结束位置区间的字节就组成了一行。它是以换行符为结束标志的解码器,支持携带结束符或者不携带结束符两种解码方式,同时支持配置单行的最大长度。如果连续读取到最大长度后仍然没有发现换行符,就会抛出异常。

StringDecoder:就是将收到的对象转换成字符串。

Netty还支持DelimiterBasedFrameDecoder和FixedLengthFrameDecoder。

DelimiterBasedFrameDecoder:用于对使用分隔符结尾的消息进行自动解码。

FixedLengthFrameDecoder:用于对固定长度的消息进行自动解码。

Netty解决方法实例

服务端:

package com.huawei.netty.test;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

/**
 * Created by liuzhengqiu on 2017/10/15.
 */
public class NettyServer
{
    public void bind(int port) throws Exception
    {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try
        {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,1024)
                    .childHandler(new ChildChannelHandler());
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            channelFuture.channel().closeFuture().sync();
        }
        finally
        {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private class ChildChannelHandler extends ChannelInitializer<SocketChannel>
    {

        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception
        {
            socketChannel.pipeline()
                    .addLast(new LineBasedFrameDecoder(1024))
                    .addLast(new StringDecoder())
                    .addLast(new NettyServerHandler());
        }
    }

    public static void main(String[] args) throws Exception {
        new NettyServer().bind(8080);
    }
}
package com.huawei.netty.test;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.Date;

/**
 * Created by liuzhengqiu on 2017/10/15.
 */
public class NettyServerHandler extends ChannelInboundHandlerAdapter
{
    private int counter;

    @Override
    public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception
    {
//        ByteBuf byteBuf = (ByteBuf) msg;
//        byte[] req = new byte[byteBuf.readableBytes()];
//        byteBuf.readBytes(req);
//        String body = new String(req,"UTF-8");
        String body = (String) msg;
        System.out.println("The time server receive order :" + body
            + ";the counter is :"+ ++counter);

        String currentTime = "hello world".equalsIgnoreCase(body)?new Date().toString():"bad order";
        currentTime += System.getProperty("line.separator");
        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
        ctx.write(resp);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception
    {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause)
    {
        ctx.close();
    }
}

客户端:

package com.huawei.netty.test;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

/**
 * Created by liuzhengqiu on 2017/10/15.
 */
public class NettyClient
{
    public void connect(int port,String host) throws Exception
    {
        EventLoopGroup group = new NioEventLoopGroup();
        try
        {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY,true)
                    .handler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline()
                                    .addLast(new LineBasedFrameDecoder(1024))
                                    .addLast(new StringDecoder())
                                    .addLast(new NettyClientHandler());
                        }
                    });
            ChannelFuture f = bootstrap.connect(host,port).sync();
            f.channel().closeFuture().sync();
        }
        finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        new NettyClient().connect(8080,"127.0.0.1");
    }
}
package com.huawei.netty.test;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/**
 * Created by liuzhengqiu on 2017/10/15.
 */
public class NettyClientHandler extends ChannelInboundHandlerAdapter
{
    private int counter;

    private final ByteBuf msg;

    public NettyClientHandler()
    {
        byte[] req = ("hello world"+System.getProperty("line.separator")).getBytes();
        msg = Unpooled.buffer(req.length);
        msg.writeBytes(req);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx)
    {
        ByteBuf message = null;
        byte[] req = ("hello world"+System.getProperty("line.separator")).getBytes();
        for (int i=0;i<100;i++)
        {
            message = Unpooled.buffer(req.length);
            message.writeBytes(req);
            ctx.writeAndFlush(message);
        }
        ctx.writeAndFlush(msg);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception
    {
//        ByteBuf buf = (ByteBuf) msg;
//        byte[] req = new byte[buf.readableBytes()];
//        buf.readBytes(req);
//
//        String body = new String(req,"UTF-8");
        String body = (String) msg;
        System.out.println("Now is :"+body);
    }
}

服务端运行结果:

The time server receive order :hello world;the counter is :1
The time server receive order :hello world;the counter is :2
The time server receive order :hello world;the counter is :3
The time server receive order :hello world;the counter is :4
The time server receive order :hello world;the counter is :5
The time server receive order :hello world;the counter is :6
The time server receive order :hello world;the counter is :7
The time server receive order :hello world;the counter is :8
The time server receive order :hello world;the counter is :9
The time server receive order :hello world;the counter is :10
The time server receive order :hello world;the counter is :11
The time server receive order :hello world;the counter is :12
The time server receive order :hello world;the counter is :13
The time server receive order :hello world;the counter is :14
The time server receive order :hello world;the counter is :15
The time server receive order :hello world;the counter is :16
The time server receive order :hello world;the counter is :17
The time server receive order :hello world;the counter is :18
The time server receive order :hello world;the counter is :19
The time server receive order :hello world;the counter is :20
The time server receive order :hello world;the counter is :21
The time server receive order :hello world;the counter is :22
The time server receive order :hello world;the counter is :23
The time server receive order :hello world;the counter is :24
The time server receive order :hello world;the counter is :25
The time server receive order :hello world;the counter is :26
The time server receive order :hello world;the counter is :27
The time server receive order :hello world;the counter is :28
The time server receive order :hello world;the counter is :29
The time server receive order :hello world;the counter is :30
The time server receive order :hello world;the counter is :31
The time server receive order :hello world;the counter is :32
The time server receive order :hello world;the counter is :33
The time server receive order :hello world;the counter is :34
The time server receive order :hello world;the counter is :35
The time server receive order :hello world;the counter is :36
The time server receive order :hello world;the counter is :37
The time server receive order :hello world;the counter is :38
The time server receive order :hello world;the counter is :39
The time server receive order :hello world;the counter is :40
The time server receive order :hello world;the counter is :41
The time server receive order :hello world;the counter is :42
The time server receive order :hello world;the counter is :43
The time server receive order :hello world;the counter is :44
The time server receive order :hello world;the counter is :45
The time server receive order :hello world;the counter is :46
The time server receive order :hello world;the counter is :47
The time server receive order :hello world;the counter is :48
The time server receive order :hello world;the counter is :49
The time server receive order :hello world;the counter is :50
The time server receive order :hello world;the counter is :51
The time server receive order :hello world;the counter is :52
The time server receive order :hello world;the counter is :53
The time server receive order :hello world;the counter is :54
The time server receive order :hello world;the counter is :55
The time server receive order :hello world;the counter is :56
The time server receive order :hello world;the counter is :57
The time server receive order :hello world;the counter is :58
The time server receive order :hello world;the counter is :59
The time server receive order :hello world;the counter is :60
The time server receive order :hello world;the counter is :61
The time server receive order :hello world;the counter is :62
The time server receive order :hello world;the counter is :63
The time server receive order :hello world;the counter is :64
The time server receive order :hello world;the counter is :65
The time server receive order :hello world;the counter is :66
The time server receive order :hello world;the counter is :67
The time server receive order :hello world;the counter is :68
The time server receive order :hello world;the counter is :69
The time server receive order :hello world;the counter is :70
The time server receive order :hello world;the counter is :71
The time server receive order :hello world;the counter is :72
The time server receive order :hello world;the counter is :73
The time server receive order :hello world;the counter is :74
The time server receive order :hello world;the counter is :75
The time server receive order :hello world;the counter is :76
The time server receive order :hello world;the counter is :77
The time server receive order :hello world;the counter is :78
The time server receive order :hello world;the counter is :79
The time server receive order :hello world;the counter is :80
The time server receive order :hello world;the counter is :81
The time server receive order :hello world;the counter is :82
The time server receive order :hello world;the counter is :83
The time server receive order :hello world;the counter is :84
The time server receive order :hello world;the counter is :85
The time server receive order :hello world;the counter is :86
The time server receive order :hello world;the counter is :87
The time server receive order :hello world;the counter is :88
The time server receive order :hello world;the counter is :89
The time server receive order :hello world;the counter is :90
The time server receive order :hello world;the counter is :91
The time server receive order :hello world;the counter is :92
The time server receive order :hello world;the counter is :93
The time server receive order :hello world;the counter is :94
The time server receive order :hello world;the counter is :95
The time server receive order :hello world;the counter is :96
The time server receive order :hello world;the counter is :97
The time server receive order :hello world;the counter is :98
The time server receive order :hello world;the counter is :99
The time server receive order :hello world;the counter is :100
The time server receive order :hello world;the counter is :101

客户端运行结果:

Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017
Now is :Sat Oct 21 23:17:57 CST 2017

续集

了解编解码基础知识之后,后面继续讲解Netty内置编解码框架的使用,例如Java序列化,二进制编解码,谷歌的protobuf和JBoss的Marshalling序列化框架。

猜你喜欢

转载自liuzhengqiu0127.iteye.com/blog/2397209
今日推荐