Nacos源码学习系列第10篇服务端消息接收类PushReceiver

前面的文章中我们着重讲了服务的注册和主动查询服务列表的功能。实际上在客户端发起服务查询(订阅)后,服务端会定时推送服务的结果给客户端,在1.1.4版本中是通过udp的方式推动的

初始化

public PushReceiver(HostReactor hostReactor) {
        try {
            this.hostReactor = hostReactor;
            udpSocket = new DatagramSocket();

            executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
                @Override
                public Thread newThread(Runnable r) {
                    Thread thread = new Thread(r);
                    thread.setDaemon(true);
                    thread.setName("com.alibaba.nacos.naming.push.receiver");
                    return thread;
                }
            });

            executorService.execute(this);
        } catch (Exception e) {
            NAMING_LOGGER.error("[NA] init udp socket failed", e);
        }
    }

PushServer 初始化一个udpSocket server ,创建单线程的线程池用于监听和处理服务端发来的消息。hostReactor 服务处理服务相关的逻辑

监听任务

public void run() {
        while (true) {
            try {
                // byte[] is initialized with 0 full filled by default
                byte[] buffer = new byte[UDP_MSS];
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                udpSocket.receive(packet);
                String json = new String(IoUtils.tryDecompress(packet.getData()), "UTF- 
                   8").trim();
                NAMING_LOGGER.info("received push data: " + json + " from " + 
                packet.getAddress().toString());

                PushPacket pushPacket = JSON.parseObject(json, PushPacket.class);
                String ack;
                if ("dom".equals(pushPacket.type) || "service".equals(pushPacket.type)) 
                    {
                    hostReactor.processServiceJSON(pushPacket.data);

                    // send ack to server
                    ack = "{\"type\": \"push-ack\""
                        + ", \"lastRefTime\":\"" + pushPacket.lastRefTime
                        + "\", \"data\":" + "\"\"}";
                } else if ("dump".equals(pushPacket.type)) {
                    // dump data to server
                    ack = "{\"type\": \"dump-ack\""
                        + ", \"lastRefTime\": \"" + pushPacket.lastRefTime
                        + "\", \"data\":" + "\""
                        +  
        StringUtils.escapeJavaScript(JSON.toJSONString(hostReactor.getServiceInfoMap()))
                        + "\"}";
                } else {
                    // do nothing send ack only
                    ack = "{\"type\": \"unknown-ack\""
                        + ", \"lastRefTime\":\"" + pushPacket.lastRefTime
                        + "\", \"data\":" + "\"\"}";
                }

                udpSocket.send(new DatagramPacket(ack.getBytes(Charset.forName("UTF- 
                8")),
                ack.getBytes(Charset.forName("UTF-8")).length, 
                packet.getSocketAddress()));
            } catch (Exception e) {
                NAMING_LOGGER.error("[NA] error while receiving push data", e);
            }
        }
    }

    public static class PushPacket {
        public String type;
        public long lastRefTime;
        public String data;
    }

如果接收到报文类型是dom 或者 service ,调用hostReactor的processServiceJSON方法处理json. 

如果收到报文类型是dump,发送本地的所有service列表到服务端

其他是未知消息

其他的就是udp socket相关的内容,读者可以参考udp socket的相关知识学习

有2个疑问

1、消息类型dom 代表哪一类消息?

2、为什么还要从客户端dump服务到服务端

3、lastRefTime 又是代表什么含义呢

这些问题等我们以后讲到服务端代码的时候再回过头来解答。

出个小问题考大家一下, 服务端是怎么知道客户端的端口的?

 

你可能感兴趣的:(#,Nacos注册与发现客户端篇,spring,cloud)