Netty处理TCP拆包、粘包

Netty实践(二):TCP拆包、粘包问题-学海无涯 心境无限-51CTO博客 http://blog.51cto.com/zhangfengzhe/1890577网络

 2017-01-09 21:56:06框架

什么是TCP拆包、粘包?
ide

在网络通讯中,数据在底层都是以字节流形式在流动,那么发送方和接受方理应有一个约定(协议),只有这样接受方才知道须要接受多少数据,哪些数据须要在一块儿处理;若是没有这个约定,就会出现本应该一块儿处理的数据,被TCP划分为多个包发给接收方进行处理,以下图:this

 

 

 

 

看一个TCP拆包、粘包的实例编码

客户端Handler:3d

 

服务端Handler:code

 

运行结果:orm

 

上面的程序本意是CLIENT发送3次消息给SERVER,SERVER端理应处理3次,但是结果SERVER却将3条消息一次处理了。blog

 

那么如何解决TCP拆包、粘包问题呢?其实思路不外乎有3种:get

第一种:发定长数据

接收方拿固定长度的数据,发送方发送固定长度的数据便可。可是这样的缺点也是显而易见的:若是发送方的数据长度不足,须要补位,浪费空间。

第二种:在包尾部增长特殊字符进行分割

发送方发送数据时,增长特殊字符;在接收方以特殊字符为准进行分割

第三种:自定义协议

相似于HTTP协议中的HEAD信息,好比咱们也能够在HEAD中,告诉接收方数据的元信息(数据类型、数据长度等)

 

 

Netty如何解决TCP拆包、粘包问题?

《Java通讯实战:编写自定义通讯协议实现FTP服务》中,涉及到了JAVA SOCKET这方面的处理,你们能够参考。接下来,咱们来看Netty这个框架是如何帮助咱们解决这个问题的。本篇博客的代码在《Netty实践(一):轻松入门》基础上进行。

 

方式一:定长消息

Server启动类:

 

 

Client Handler:

 

 

运行结果:

 

 

 

 

利用FixedLengthFrameDecoder,加入到管道流处理中,长度够了接收方才能收到。

 

 

方式二:自定义分隔符

Server启动类:

 

 

Client Handler:

 

 

运行结果:

 

 

 

方式三:自定义协议

下面咱们将简单实现一个自定义协议:

HEAD信息中包含:数据长度、数据版本

数据内容

MyHead

public class MyHead {

    //数据长度
    private int length;

    //数据版本
    private int version;


    public MyHead(int length, int version) {
        this.length = length;
        this.version = version;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }


}


MyMessage

public class MyMessage {
    //消息head
    private MyHead head;
    //消息body
    private String content;

    public MyMessage(MyHead head, String content) {
        this.head = head;
        this.content = content;
    }

    public MyHead getHead() {
        return head;
    }

    public void setHead(MyHead head) {
        this.head = head;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return String.format("[length=%d,version=%d,content=%s]",head.getLength(),head.getVersion(),content);
    }
}


编码器

/**
 * Created by Administrator on 17-1-9.
 * 编码器 将自定义消息转化成ByteBuff
 */
public class MyEncoder extends MessageToByteEncoder {

    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, MyMessage myMessage, ByteBuf byteBuf) throws Exception {

        int length = myMessage.getHead().getLength();
        int version = myMessage.getHead().getVersion();
        String content = myMessage.getContent();

        byteBuf.writeInt(length);
        byteBuf.writeInt(version);
        byteBuf.writeBytes(content.getBytes(Charset.forName("UTF-8")));

    }
}


解码器

/**
 * Created by Administrator on 17-1-9.
 * 解码器  将ByteBuf数据转化成自定义消息
 */
public class MyDecoder extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List

 

 

 

运行结果

 

 

到这里,你会发现Netty处理TCP拆包、粘包问题很简单,经过编解码技术支持,让咱们编写自定义协议也很方便,在后续的Netty博客中,我将继续为你们介绍Netty在实际中的一些应用(好比实现心跳检测),See You~

相关文章
相关标签/搜索