【网络编程】ZeroMQ的网络通信

news2025/1/24 18:02:41

文章目录

  • 1、概述
  • 2、通信效果
    • 2.1、Request-Reply(请求-响应模式)
    • 2.2、Publish-Subscribe(订阅-发布模式)
  • 3、方式选择
    • 3.1、准备用 Visual Studio-C++ 方式
      • 3.1.1、找到 Builds 文件夹
      • 3.1.2、查看 deprecated-msvc 下的 libzmq.sln 文件
      • 3.1.3、使用 Visual Studio 打开 libzmq.sln 解决方案
      • 3.1.4、修改 libzmq.import.props 文件
      • 3.1.5、编译生成
    • 3.2、准备用 PyCharm-Python 方式
      • 3.2.1、安装
        • 3.2.1.1、命令安装
        • 3.2.1.2、IDE安装
      • 3.2.2、查看是否安装成功
  • 4、Request-Reply(请求响应模式)
    • 4.1、Request-Reply模式概述
    • 4.2、Client 源代码
    • 4.3、Server 源代码
  • 5、Publish/Subscribe(订阅-发布模式)
    • 5.1、Pub-Subs模式概述
    • 5.2、发布者 源代码
    • 5.3、订阅者 源代码

1、概述

在前一篇文章中提到了 ØMQ (ZeroMQ) ,是一个基于消息队列的多线程网络库,它封装了网络通信、消息队列、线程调度等功能,向上层提供简洁的API,应用程序通过加载库文件,调用API函数来实现高性能网络通信。

本篇文章重点讲述下,在客户端上如何使用 ZeroMQ 与 服务端的 ZeroMQ 进行通信,主要讲述两种常用模式:
1.Request-Reply(请求响应模式)
2.Publish-Subscribe(订阅-发布模式)

相关文章:

  • 【Qt 学习之路】在 Qt 使用 ZeroMQ:https://shazhenyu.blog.csdn.net/article/details/136051050?spm=1001.2014.3001.5502

2、通信效果

2.1、Request-Reply(请求-响应模式)

Client:
在这里插入图片描述
Server:
在这里插入图片描述

2.2、Publish-Subscribe(订阅-发布模式)

发布者:
在这里插入图片描述
订阅者:
在这里插入图片描述
在这里插入图片描述

3、方式选择

3.1、准备用 Visual Studio-C++ 方式

3.1.1、找到 Builds 文件夹

在 ZeroMQ 的 builds 文件夹下,有很多种编译方法,为了方便演示,本文选择msvc进行演示。
在这里插入图片描述

3.1.2、查看 deprecated-msvc 下的 libzmq.sln 文件

在这里插入图片描述

3.1.3、使用 Visual Studio 打开 libzmq.sln 解决方案

在这里插入图片描述

3.1.4、修改 libzmq.import.props 文件

用 Notepad++ 打开 libzmq.import.props 文件,修改 5处 路径,全部改成…\bin【注意:去掉“…\libzmq\”】

  • 原:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup Label="Globals">
    <_PropertySheetDisplayName>ZMQ Import Settings</_PropertySheetDisplayName>
  </PropertyGroup>

  <!-- User Interface -->

  <ItemGroup Label="BuildOptionsExtension">
    <PropertyPageSchema Include="$(MSBuildThisFileDirectory)libzmq.import.xml" />
  </ItemGroup>

  <!-- Configuration -->

  <ItemDefinitionGroup>
    <ClCompile>
      <PreprocessorDefinitions Condition="'$(Option-sodium)' == 'true'">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <PreprocessorDefinitions Condition="'$(Option-openpgm)' == 'true'">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <PreprocessorDefinitions Condition="'$(Option-gssapi)' == 'true'">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <PreprocessorDefinitions Condition="'$(Option-draftapi)' == 'true'">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
  </ItemDefinitionGroup>

  <!-- Linkage -->

  <ItemDefinitionGroup>
    <ClCompile>
      <AdditionalIncludeDirectories>$(ProjectDir)..\..\..\..\..\libzmq\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <PreprocessorDefinitions Condition="'$(Linkage-libzmq)' == 'static' Or '$(Linkage-libzmq)' == 'ltcg'">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
    <Link>
      <AdditionalDependencies Condition="'$(Linkage-libzmq)' != ''">libzmq.lib;%(AdditionalDependencies)</AdditionalDependencies>
      <AdditionalLibraryDirectories Condition="$(Configuration.IndexOf('Debug')) != -1">$(ProjectDir)..\..\..\..\..\libzmq\bin\$(PlatformName)\Debug\$(PlatformToolset)\$(Linkage-libzmq)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
      <AdditionalLibraryDirectories Condition="$(Configuration.IndexOf('Release')) != -1">$(ProjectDir)..\..\..\..\..\libzmq\bin\$(PlatformName)\Release\$(PlatformToolset)\$(Linkage-libzmq)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
    </Link>
  </ItemDefinitionGroup>

  <!-- Copy -->

  <Target Name="Linkage-libzmq-dynamic" AfterTargets="AfterBuild" Condition="'$(Linkage-libzmq)' == 'dynamic'">
    <Copy Condition="$(Configuration.IndexOf('Debug')) != -1"
          SourceFiles="$(ProjectDir)..\..\..\..\..\libzmq\bin\$(PlatformName)\Debug\$(PlatformToolset)\dynamic\libzmq.dll"
          DestinationFiles="$(TargetDir)libzmq.dll"
          SkipUnchangedFiles="true" />
    <Copy Condition="$(Configuration.IndexOf('Debug')) != -1"
          SourceFiles="$(ProjectDir)..\..\..\..\..\libzmq\bin\$(PlatformName)\Debug\$(PlatformToolset)\dynamic\libzmq.pdb"
          DestinationFiles="$(TargetDir)libzmq.pdb"
          SkipUnchangedFiles="true" />
    <Copy Condition="$(Configuration.IndexOf('Release')) != -1"
          SourceFiles="$(ProjectDir)..\..\..\..\..\libzmq\bin\$(PlatformName)\Release\$(PlatformToolset)\dynamic\libzmq.dll"
          DestinationFiles="$(TargetDir)libzmq.dll"
          SkipUnchangedFiles="true" />
  </Target>

  <!-- Messages -->

  <Target Name="libzmq-info" BeforeTargets="AfterBuild" Condition="'$(Linkage-libzmq)' == 'dynamic'">
    <Message Text="Copying libzmq.dll -&gt; $(TargetDir)libzmq.dll" Importance="high"/>
    <Message Text="Copying libzmq.pdb -&gt; $(TargetDir)libzmq.pdb" Importance="high" Condition="$(Configuration.IndexOf('Debug')) != -1" />
  </Target>

</Project>
  • 改:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup Label="Globals">
    <_PropertySheetDisplayName>ZMQ Import Settings</_PropertySheetDisplayName>
  </PropertyGroup>

  <!-- User Interface -->

  <ItemGroup Label="BuildOptionsExtension">
    <PropertyPageSchema Include="$(MSBuildThisFileDirectory)libzmq.import.xml" />
  </ItemGroup>

  <!-- Configuration -->

  <ItemDefinitionGroup>
    <ClCompile>
      <PreprocessorDefinitions Condition="'$(Option-sodium)' == 'true'">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <PreprocessorDefinitions Condition="'$(Option-openpgm)' == 'true'">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <PreprocessorDefinitions Condition="'$(Option-gssapi)' == 'true'">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <PreprocessorDefinitions Condition="'$(Option-draftapi)' == 'true'">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
  </ItemDefinitionGroup>

  <!-- Linkage -->

  <ItemDefinitionGroup>
    <ClCompile>
      <AdditionalIncludeDirectories>$(ProjectDir)..\..\..\..\..\libzmq\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <PreprocessorDefinitions Condition="'$(Linkage-libzmq)' == 'static' Or '$(Linkage-libzmq)' == 'ltcg'">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
    <Link>
      <AdditionalDependencies Condition="'$(Linkage-libzmq)' != ''">libzmq.lib;%(AdditionalDependencies)</AdditionalDependencies>
      <AdditionalLibraryDirectories Condition="$(Configuration.IndexOf('Debug')) != -1">$(ProjectDir)..\..\..\..\bin\$(PlatformName)\Debug\$(PlatformToolset)\$(Linkage-libzmq)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
      <AdditionalLibraryDirectories Condition="$(Configuration.IndexOf('Release')) != -1">$(ProjectDir)..\..\..\..\bin\$(PlatformName)\Release\$(PlatformToolset)\$(Linkage-libzmq)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
    </Link>
  </ItemDefinitionGroup>

  <!-- Copy -->

  <Target Name="Linkage-libzmq-dynamic" AfterTargets="AfterBuild" Condition="'$(Linkage-libzmq)' == 'dynamic'">
    <Copy Condition="$(Configuration.IndexOf('Debug')) != -1"
          SourceFiles="$(ProjectDir)..\..\..\..\bin\$(PlatformName)\Debug\$(PlatformToolset)\dynamic\libzmq.dll"
          DestinationFiles="$(TargetDir)libzmq.dll"
          SkipUnchangedFiles="true" />
    <Copy Condition="$(Configuration.IndexOf('Debug')) != -1"
          SourceFiles="$(ProjectDir)..\..\..\..\bin\$(PlatformName)\Debug\$(PlatformToolset)\dynamic\libzmq.pdb"
          DestinationFiles="$(TargetDir)libzmq.pdb"
          SkipUnchangedFiles="true" />
    <Copy Condition="$(Configuration.IndexOf('Release')) != -1"
          SourceFiles="$(ProjectDir)..\..\..\..\bin\$(PlatformName)\Release\$(PlatformToolset)\dynamic\libzmq.dll"
          DestinationFiles="$(TargetDir)libzmq.dll"
          SkipUnchangedFiles="true" />
  </Target>

  <!-- Messages -->

  <Target Name="libzmq-info" BeforeTargets="AfterBuild" Condition="'$(Linkage-libzmq)' == 'dynamic'">
    <Message Text="Copying libzmq.dll -&gt; $(TargetDir)libzmq.dll" Importance="high"/>
    <Message Text="Copying libzmq.pdb -&gt; $(TargetDir)libzmq.pdb" Importance="high" Condition="$(Configuration.IndexOf('Debug')) != -1" />
  </Target>

</Project>

3.1.5、编译生成

按照官网的方式,这一步应该是成功了,但是目前是失败,还少文件,可能是包有问题
在这里插入图片描述

3.2、准备用 PyCharm-Python 方式

3.2.1、安装

3.2.1.1、命令安装
pip install pyzmq
3.2.1.2、IDE安装

安装图种方法安装 pyzmq25.1.2 版本
在这里插入图片描述

3.2.2、查看是否安装成功

直接打印 zmq 版本号 试试

import zmq
print(zmq.__version__)

在这里插入图片描述
由于 Python 相对快捷,本文后续以 Python 进行讲述

4、Request-Reply(请求响应模式)

4.1、Request-Reply模式概述

消息双向的,有来有往。
Client请求的消息,Server必须答复给Client。
Client在请求后,Server必须回响应,注意:Server不返回响应会报错。
Server和Client都可以是1:N的模型。通常把1认为是Server,N认为是Client。
更底层的端点地址是对上层隐藏的,每个请求都隐含回应地址,而应用则不关心它。
ZMQ 可以很好的支持路由功能(实现路由功能的组件叫做 Device),把 1:N 扩展为 N:M(只需要加入若干路由节点)。

4.2、Client 源代码

# client.py

import zmq

context = zmq.Context()

#  Socket to talk to server
print("Connecting to 5555 server…")
socket = context.socket(zmq.REQ)
socket.connect("tcp://localhost:5555")
socket.send(b"Hello, I'm Mr.Sha Client.")
#  Get the reply.
message = socket.recv()
print(f"Received reply [ {message} ]")

4.3、Server 源代码

# server.py
import time
import zmq

context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5555")

while True:
    #  Wait for next request from client
    message = socket.recv()
    print("Received request: %s" % message)

    #  Do some 'work'
    time.sleep(1)

    #  Send reply back to client
    socket.send(b"Hello, I'm server.")

5、Publish/Subscribe(订阅-发布模式)

5.1、Pub-Subs模式概述

消息单向,有去无回
一个发布端,多个订阅端;发布端只管产生数据,发布端发布一条消息,可被多个订阅端同时收到。
发布者不必关心订阅者的加入和离开,消息会以 1:N 的方式扩散到每个订阅者。
广播所有client,没有队列缓存,断开连接数据将永远丢失。
如果Publish端开始发布信息时,Subscribe端尚未连接进来,则这些信息会被直接丢弃。
PUB和SUB谁bind谁connect并无严格要求(虽本质并无区别),但仍建议PUB使用bind,SUB使用connect
使用SUB设置一个订阅时,必须使用zmq_setsockopt()对消息进行过滤

这里直接引用官方文档的例子,订阅者再稍作改装!

5.2、发布者 源代码

类似于一个天气更新服务器,向订阅者发送天气更新,内容包括邮政编码、温度、湿度等信息

# Publisher.py
import zmq
from random import randrange

context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:5556")

while True:
    zipcode = randrange(1, 100000)
    temperature = randrange(-80, 135)
    relhumidity = randrange(10, 60)

    socket.send_string("%i %i %i" % (zipcode, temperature, relhumidity))

5.3、订阅者 源代码

它监听发布者更新的数据流,过滤只接收与特定邮政编码相关的天气信息,默认接收接收10条数据

# Subscribe.py
import sys
import zmq


#  Socket to talk to server
context = zmq.Context()
socket = context.socket(zmq.SUB)

print("Collecting updates from weather server...")
socket.connect("tcp://localhost:5556")

# Subscribe to zipcode, default is NYC, 10001
zip_filter = sys.argv[1] if len(sys.argv) > 1 else "10001"

# Python 2 - ascii bytes to unicode str
if isinstance(zip_filter, bytes):
    zip_filter = zip_filter.decode('ascii')
socket.setsockopt_string(zmq.SUBSCRIBE, zip_filter)

# Process 5 updates
total_temp = 0
for update_nbr in range(5):
    string = socket.recv_string()
    zipcode, temperature, relhumidity = string.split()
    total_temp += int(temperature)

print("zipcode, temperature, relhumidity:" + string)

print(
    "Average temperature for zipcode '%s' was %dF"
    % (zip_filter, total_temp / (update_nbr + 1))
)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1454322.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图像像素读写image.at、image.ptr、指针

image.at 在OpenCV中&#xff0c;使用Mat对象表示图像数据&#xff0c;在使用at方法时&#xff0c;需要确保使用正确的数据类型&#xff08;如uchar或Vec3b&#xff09;&#xff0c;这取决于图像的通道数和数据深度。 单通道图像 对于单通道图像&#xff08;如灰度图像&…

正信晟锦:借钱后不还算诈骗吗

在探讨“借钱后不还”这一行为是否构成诈骗时&#xff0c;我们应首先明确诈骗的法律定义。根据《中华人民共和国刑法》&#xff0c;诈骗是指以非法占有为目的&#xff0c;采用虚构事实或隐瞒真相的手段&#xff0c;骗取他人财物的行为。关键在于是否存在欺诈行为和非法占有的主…

12.QT文件对话框 文件的弹窗选择-QFileDialog

目录 前言&#xff1a; 技能&#xff1a; 内容&#xff1a; 1. 界面 2.信号槽 3.其他函数 参考&#xff1a; 前言&#xff1a; 通过按钮实现文件弹窗选择以及关联的操作 效果图就和平时用电脑弹出的选文件对话框一样 技能&#xff1a; QString filename QFileDialog::ge…

消毒柜行业分析:市场渗透率不足20%

目前消毒柜仍然属于“小众”品类&#xff0c;疫情前期市场渗透率也不足20%。有业内人士表示&#xff0c;多年来消毒柜零售量规模基本在400万台左右徘徊&#xff0c;这个角度看&#xff0c;消毒柜是具有自身的产品消费人群的&#xff0c;其市场相对稳定&#xff0c;而且消毒柜的…

【Java EE初阶十六】网络原理(一)

在网络原理中主要学习TCP/IP四层模型中的重点网络协议 1. 应用层 1.1 应用程序与协议 应用层是和程序员接触最密切的&#xff1b; 应用程序&#xff1a;在应用层这里&#xff0c;很多时候都是程序员自定义应用层协议&#xff08;步骤&#xff1a;1、根据需求&#xff0c;明确…

前端工程化面试题 | 14.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

2974. 最小数字游戏【简单】

2974. 最小数字游戏 题目描述&#xff1a; 你有一个下标从 0 开始、长度为 偶数 的整数数组 nums &#xff0c;同时还有一个空数组 arr 。Alice 和 Bob 决定玩一个游戏&#xff0c;游戏中每一轮 Alice 和 Bob 都会各自执行一次操作。游戏规则如下&#xff1a; 每一轮&#xf…

001kafka源码项目gradle报错UnsupportedClassVersionError-kafka-报错-大数据学习

1 报错提示 java.lang.UnsupportedClassVersionError: org/eclipse/jgit/lib/AnyObjectId has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0 如…

AI:131- 法律文件图像中的隐含信息挖掘与敲诈勒索检测

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的关键代码,详细讲解供…

2024最全的性能测试种类介绍,这6个种类特别重要!

系统的性能是一个很大的概念&#xff0c;覆盖面非常广泛&#xff0c;包括执行效率、资源占用、系统稳定性、安全性、兼容性、可靠性、可扩展性等&#xff0c;性能测试就是描述测试对象与性能相关的特征并对其进行评价而实施的一类测试。 性能测试是一个统称&#xff0c;它其实包…

Nginx高级课程扩容(四)

Brotli 安装 ● 官网 ● https://github.com/google/ngx_brotli ● https://codeload.github.com/google/brotli/tar.gz/refs/tags/v1.0.9 ● 下载 两个项目 ● 解压缩模块化编译 ./configure --with-compat --add-dynamic-module/root/ngx_brotli-1.0.0rc --prefix/usr/local…

[嵌入式系统-28]:开源的虚拟机监视器和仿真器:QEMU(Quick EMUlator)与VirtualBox、VMware Workstation的比较

目录 一、QEMU概述 1.1 QEMU架构 1.2 QEMU概述 1.3 什么时候需要QEMU 1.4 QEMU两种操作模式 1.5 QEMU模拟多种CPU架构 二、QEMU与其他虚拟机的比较 2.1 常见的虚拟化技术 2.1 Linux KVM 2.2 Windows VirtualBox 2.3 Windows VMware workstation 三、VirtualBox、VM…

【Java程序员面试专栏 Java领域】Java集合 核心面试指引

关于Java 集合部分的核心知识进行一网打尽,主要包括Java各类集合以及Java的HashMap底层原理,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 集合基本概念和比较 关于集合的基本分类和知识 Java集合有哪些种类 Java 集合, 也叫作容器…

leetcode hot100 打家劫舍

本题中&#xff0c;依旧可以发现&#xff0c;当前位置的金额受到前两个位置金额是否被偷的影响&#xff0c;所以这明显是动态规划的问题。 我们采用动态规划五部曲来进行做 首先我们确定dp数组的含义&#xff1a;考虑下标i&#xff08;包括i&#xff09;以内的房屋&#xff0…

3秒开服《幻兽帕鲁》!如何抓住游戏背后的云计算机遇?

导语 | 2024 年伊始&#xff0c;《幻兽帕鲁》的火热就为新一年的游戏市场带来了极高的热度&#xff0c;无论是超千万份的销量还是关于游戏“缝合”与“借鉴”的争议&#xff0c;都使得开年游戏市场的销售前景与话题度拉满。而在游戏市场之外&#xff0c;云服务市场尤其是其面向…

K8s服务发现组件之CoreDNS/NodeLocalDNS /kubeDNS

1 coredns 1.1 概述 1.1.1 什么是CoreDNS CoreDNS 是一个灵活可扩展的 DNS 服务器&#xff0c;可以作为 Kubernetes 集群 DNS&#xff0c;在Kubernetes1.12版本之后成为了默认的DNS服务。 与 Kubernetes 一样&#xff0c;CoreDNS 项目由 CNCF 托管。 coredns在K8S中的用途,…

大屏设计:公说公有理婆说婆有理!错,看这十个判定标准。

“公说公有理&#xff0c;婆说婆有理”这句话通常用来形容争论双方都认为自己是正确的&#xff0c;而且都有自己的理由和观点。在设计中&#xff0c;这种情况也是很常见的。 为什么会公说公有理婆说婆有理&#xff1f; 设计是一门艺术和技术相结合的学科&#xff0c;涉及到很多…

人机工程学和人机交互理论:智能座舱设计

hello家人们...本人熟悉PS、Xd、Ai、Sketch、Figma、墨刀、即时设计、mastergo、Pixso等行业设计软件以及前端开发等技能&#xff0c;拥有10年的UI经验&#xff0c;我们可以通过关注评论私信交流以帮助到您解决UI工作中的烦恼&#xff01;谢谢 人机工程学与人机交互理论&#x…

源聚达:抖音网店做多久可以做起来

在数字化浪潮中&#xff0c;抖音作为新兴的电商平台&#xff0c;吸引了无数创业者的目光。然而&#xff0c;“抖音网店做多久可以做起来”这一问题&#xff0c;却像一道复杂的数学题&#xff0c;需要细致的解析与推导。 成功的抖音网店并非一蹴而就。根据业内数据分析&#xff…

Find My资讯|苹果Vision Pro无法通过Find My进行远程定位和发声

苹果 Vision Pro 头显现在已经正式开售&#xff0c;不过根据该公司日前发布的支持文件&#xff0c;这款头显目前缺乏一系列关键查找功能&#xff0c;用户无法在 iCloud 网站或Find My应用中获悉头显的位置&#xff0c;也无法让这款头显远程播放声音。 不过支持文件同时提到 V…