socket 通信且看j d k是如何做出迭代优化的

「这是我参与2022首次更文挑战的第35天,活动详情查看:2022首次更文挑战」

 ​
 public class SocketFactory implements ProtocolCodecFactory {
    private MessageDecoder decoder;
    private MessageEncoder encoder;
 ​
    public SocketFactory() {
        decoder = new MessageDecoder();
        encoder = new MessageEncoder();
    }
 ​
    public ProtocolDecoder getDecoder(IoSession session) throws Exception {
        return this.decoder;
    }
 ​
    public ProtocolEncoder getEncoder(IoSession session) throws Exception {
        return this.encoder;
    }
 }
 ​
复制代码

服务端和客户端不同的就是我们创建的监听对象不同而已,客户端发送消息到服务端,服务端需要经历过滤器的处理才能到达消息中心,但是在过滤器中我们就需要将消息进行解码,然后才会到消息接收的地方处理我们的业务。正常情况下我们处理完消息需要对客户端进行回应。回应的时候也会经历过滤器中的编码逻辑,进行数据编码然后发送。信息发送到客户端我们可以看成服务端的方向。也是需要进行编解码的。下面看看服务端的创建代码

解码器

  • 上面的工厂就是提供编解码的。和我们生活中一样工厂提供功能,但是实际并不是工厂做的,工厂可能只代理功能,仅仅是个加工厂而已。mina通信也是如此。真正编解码的并不是工厂执行的,本节将揭露解码者CumulativeProtocolDecoder

  • 解码器写好之后只需要在上面自定义工厂中创建就好了。至于自定义编码器只需要继承CumulativeProtocolDecoder这个类就好了。而且复写doDecode方法就好了。这个方法的返回值是boolean类型。返回值不同代表意义不一。这里需要重点理清楚

    • true: 返回true表示你已经从CumulativeProtocolDecoder的消息中消费了信息,在编码器中返回true之前也应该调用ProtocolDecoderOutput 的wirte将消息发布到IoHandAdaptor中进行业务处理。但是这里会出现其他情况,应为我们服务端客户端是长连接所以在我们消息中消息是不断发过来的,我们缓存中的消息可能是完整一条消息,也可能不够一整条消息,也可能是一整条多了一点,

      • 1、如果不是一条完整(半包)的那么我们返回falsed等待客户端继续发送
      • 2、如果正好是一整条,那么我们接受到之后返回true的时候我们缓存中就没有数据了,在CumulativeProtocolDecoder会停止对解码中doDecode的调用了,这种情况不会出现意外
      • 3、数据比一条完整信息(粘包)多,那么我们处理到一条信息后也需要返回true,但是CumulativeProtocolDecoder会将剩余的缓存继续拼装,剩余消息就相当于内部进行了第二次解码。如果不过那么相当于上面第一种情况

      记住三种情况 半包 、 正常 、 粘包

    • false: 返回false就是缓存中的数据不够我们一整条消息,需要继续等待客户端的消息。CumulativeProtocolDecoder中的缓存机制会不断的将客户端发过来的数据拼接到缓存中

编码器

  • 编码器相对解码器简单很多,编码器就是加入我们的协议,正常情况就是我们业务代码中消息是一个Java实体,我们需要做的是将Java实体按照协议转换成IoBuffer进行发送。但是我们mina中发送消息是通过IoSession中write方法发送的。我们查看源码发现在IoSession.write(Object o),发送的如果是IoBuffer那么就不经过我们的编码器,否则会经过我们编码器进行编码最终将转换后的IoBuffer发送出去。

 ​
 public class MessageEncoder extends ProtocolEncoderAdapter {
    @Override
    public void encode(IoSession ioSession, Object o, ProtocolEncoderOutput protocolEncoderOutput) throws Exception {
        //TODO 根据协议编码
        //组装好之后 ioSession.write(IoBuffer)写出
        System.out.println(o);
    }
 }
 ​
复制代码

总结

Guess you like

Origin juejin.im/post/7067352251706114055