手把手带你撸zookeeper源码-zookeeper通信序列化协议

上篇文章分析到了zookeeper集群之间通信时用到了jute序列化协议,本篇文章来简单了解jute如何序列化和反序列化以及如何解决粘包拆包的问题的

今天上网看了一下查了一下zookeeper jute,其实网上也有很多这方面的资料,我就简单的写了一个demo先来展示一下,最后给大家一点自己如何自定义传输协议,如何解决粘包拆包的问题

public class City implements Record{
    private String cityNo;//城市编号
    private String cityName;//城市名称

    public City() {
    }

    public City(String cityNo, String cityName) {
        this.cityNo = cityNo;
        this.cityName = cityName;
    }

    @Override
    public void serialize(OutputArchive archive, String tag) throws IOException {
        archive.startRecord(this, tag);
        archive.writeString(cityNo, "cityNo");
        archive.writeString(cityName, "cityName");
        archive.endRecord(this, tag);
    }

    @Override
    public void deserialize(InputArchive archive, String tag) throws IOException {
        archive.startRecord(tag);
        this.cityNo = archive.readString("cityNo");
        this.cityName = archive.readString("cityName");
        archive.endRecord(tag);
    }

    public String getCityNo() {
        return cityNo;
    }

    public void setCityNo(String cityNo) {
        this.cityNo = cityNo;
    }

    public String getCityName() {
        return cityName;
    }

    public void setCityName(String cityName) {
        this.cityName = cityName;
    }

    @Override
    public String toString() {
        return "City{" +
                "cityNo='" + cityNo + '\'' +
                ", cityName='" + cityName + '\'' +
                '}';
    }
}

自定义一个对象,必须实现Record接口,我们看一下Record接口的代码

public interface Record {
    public void serialize(OutputArchive archive, String tag)
        throws IOException;
    public void deserialize(InputArchive archive, String tag)
        throws IOException;
}

它只有两个方法,serialize方法是对数据进行序列化, deserialize对数据进行反序列化

然后OutputArchive就是对各种类型的数据进行write,相反InputArchive对各种数据进行读取,tag就是可以指定一下读取到哪个标记算是一个整体,然后对数据进行反序列化,底层主要就是根据tag来解决粘包问题的

看一下测试类

public class MainTest {
    public static void main(String[] args) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);
        City city = new City("bj", "北京");
        city.serialize(boa, "city");


        ByteBuffer array = ByteBuffer.wrap(baos.toByteArray());
        ByteArrayInputStream bais = new ByteArrayInputStream(array.array());
        BinaryInputArchive bia = BinaryInputArchive.getArchive(bais);
        City newCity = new City();
        newCity.deserialize(bia, "city");

        System.out.println(newCity);

        bais.close();
        baos.close();
    }
}

上面进行输出内容

City{cityNo='bj', cityName='北京'}

其实对对象进行序列化的协议有很多,比如protobuf、thrift、dubbo自定义的协议、hessian协议等等

看过dubbo源码的小伙伴应该对dubbo协议知道,它是如何自定义协议的?

粘贴一张官网的图

/dev-guide/images/dubbo_protocol_header.jpg

也粘贴个官网链接吧 http://dubbo.apache.org/zh-cn/docs/dev/implementation.html,大家感兴趣的可以深入去看看

说一下我的简单理解,其实就是写一堆的数据,一个int有4个字节,long有8个字节,然后每个字节中的每一位代表什么意思,比如上图中第16位的地方,然后用0代表请求,用1代表响应,然后去解析这个地方的值,你就知道当前是请求还是响应了,自定义序列化协议需要客户端和服务端上方协商好一致性,该如何解析等等

那我们该如何自定义序列化协议呢,我这里就简单的抛砖引玉一下,有兴趣的可以深入思考一下

比如,客户端发送 “张三” 这个字符串给服务端,该怎么发送呢?

先把“张三”这个字符串转成字节数组 byte array

可以这样,比如我先写一个int 4个字节长度的 请求类型writeInt(0)   0表示请求, 1表示响应 然后我再写一个int 4个字节的要发送数据的长度(字节数组长度), 比如writeInt(100), 接着写要发送的数据 writeBytes(“张三”.toByteArray()) 这是模拟的。然后发送个服务端

 

那服务端如何解析呢?它首先读取int,比如readInt(),把0 读取出来,知道了当前是一个请求, 然后在读取一个int,readInt()把数据的长度读取出来,此时是100,然后接着读取,比如readBytes,此时要指定读取的长度为100,如果超过100,只能读取100长度,如果不够100,则等待下次请求继续读取,直到两次加起来达到100之后,再去反序列化,此时就能得到"张三"了

 

大家有没有明白?仔细细品一下

通过上面的方式就可以解决我们在传输过程当中的粘包拆包问题。只要涉及到网络传输,必然涉及到粘包拆包的问题,比如netty有几种解决粘包拆包的问题,我们可以指定长度、或者指定结尾符号来等等,其实底层也是上面的实现原理,只是深度包装了一下

 

好了,本篇文章就说这么多吧,上篇文章分析到了leader启动之后做了什么事,到监听其他follower来连接发送数据。下一篇我们分析一下follower启动的时候都做了什么,如何和leader建立连接的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值