文章目录
一、UDP

User Datagram Protocol 用户数据协议,属于传输层的一种协议。无需建立连接就可以发送封装的 IP 数据包,不对传送数据包进行可靠性保证,即无法得知报文是否安全完整到达。
优势:
具有较好的实时性,工作效率较高;
网络开销小。
劣势:
无法保证可靠性、顺序性等
二、Java实现UDP
public class Send {
public static void main(String[] args) {
byte[] data="hello world".getBytes();
try {
DatagramPacket datagramPacket=new DatagramPacket(data,data.length,
InetAddress.getByName("127.0.0.1"),6000);
DatagramSocket socket=new DatagramSocket();
socket.send(datagramPacket);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Receive {
public static void main(String[] args) throws IOException {
DatagramSocket socket=new DatagramSocket(6000);
byte[] data=new byte[1024];
DatagramPacket datagramPacket=new DatagramPacket(data,data.length);
socket.receive(datagramPacket);
System.out.println(new String(data,0,datagramPacket.getLength())+" ip:"
+datagramPacket.getAddress().getHostAddress()+" port:"+datagramPacket.getPort());
socket.close();
}
}
测试:
注意:先执行receive,然后等待send消息发送。
三、nacos中的主要UDP通信
在Nacos Naming中,使用http/udp的推送模型。由于UDP无ack,所以client要轮询查询保证数据一致性。

Nacos Naming的UDP通知可以分为以下几个主要流程。

1、Client上报ip+port(http)
Nacos Client在服务发现时,会通过NamingHttpClientProxy调用Nacos Naming的/instance/list接口,传入ip、udpPort。该接口有v1、v2版本。这里以v1为例。位置:com.alibaba.nacos.naming.controllers.InstanceController。
//InstanceController
@GetMapping("/list")
@Secured(parser = NamingResourceParser.class, action = ActionTypes.READ)
public Object list(HttpServletRequest request) throws Exception {
...
String clientIP = WebUtils.optional(request, "clientIP", StringUtils.EMPTY);
int udpPort = Integer.parseInt(WebUtils.optional(request, "udpPort", "0"));
...
Subscriber subscriber = new Subscriber(clientIP + ":" + udpPort, agent, app, clientIP, namespaceId, serviceName,
udpPort, clusters);
return getInstanceOperator().listInstance(namespaceId, serviceName, subscriber, clusters, healthyOnly);
}
public ServiceInfo listInstance(String namespaceId, String serviceName, Subscriber subscriber, String cluster,
boolean healthOnly) throws Exception {
...
if (subscriber.getPort() > 0 && pushService.canEnablePush(subscriber.getAgent())) {
subscriberServiceV1.addClient(namespaceId, serviceName, cluster, subscriber.getAgent(),
new InetSocketAddress(clientIP, subscriber.getPort()), pushDataSource, StringUtils.EMPTY,
StringUtils.EMPTY);
cacheMillis = switchDomain.getPushCacheMillis(serviceName);
}
...
}
public void addClient(String namespaceId, String serviceName, String clusters, String agent,
InetSocketAddress socketAddr, DataSource dataSource, String tenant, String app) {
PushClient client = new PushClient(namespaceId, serviceName, clusters, agent, socketAddr, dataSource, tenant,
app);
addClient(client);
}
private final ConcurrentMap<String, ConcurrentMap<String, PushClient>> clientMap = new ConcurrentHashMap<>();
public void addClient(PushClient client) {
// client is stored by key 'serviceName' because notify event is driven by serviceName change
String serviceKey = UtilsAndCommons.assembleFullServiceName(client.getNamespaceId(), client.getServiceName());
ConcurrentMap<String, PushClient> clients = clientMap.get(serviceKey);
if (clients == null) {
clientMap.putIfAbsent(serviceKey, new ConcurrentHashMap<>(1024));
clients = clientMap.get(serviceKey);
}
PushClient oldClient = clients.get(client.toString

最低0.47元/天 解锁文章
2222





