前面的文章中我们着重讲了服务的注册和主动查询服务列表的功能。实际上在客户端发起服务查询(订阅)后,服务端会定时推送服务的结果给客户端,在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 又是代表什么含义呢
这些问题等我们以后讲到服务端代码的时候再回过头来解答。
出个小问题考大家一下, 服务端是怎么知道客户端的端口的?