
ZXID:当发生写请求的时候,在 ZK 内会发起一个事务,每个事务会分配一个 zxid 作为标识符。zxid 是64位的 long 类型,高32位代表时间戳,低32位可以认为是事务ID,用来标识服务器状态的变更次数
SID:服务器ID。用来标识一台在 ZooKeeper 集群中的机器,每台机器不能重复。注意:这里和启动时指定的myid一致
Epoch:每个 Leader 任期的代号。每次新选举一个 Leader 就会递增1
Observer:不参与投票和选举换句话说,不参与 Leader 的选举,也不会投票给某个节点
节点状态:
好了,前置知识大概这么多,接下来咱们看一下,上面这些东西和选举有什么关系。
选举目的是为了从一堆 ZK 的服务节点中找一个大佬(Leader),然后所有非 Observer 节点都会成为小弟(Follower)。Leader负责读写数据,而 Follower 会分担大佬的负担,分担部分的读请求。
那么问题来了,根据什么条件判断,认为某一台 ZK 服务能成为 Leader 呢?
实际上,选举的规则是按照 Epoch > 事务Id > SID 依次由大到小排序,值最大作为 Leader。
简单来说,选举的时候会比较 epoch 的大小,如果所有 ZK 节点的 Leader 任期大小一样,则继续比较 ZXID 的低32位,也就是事务Id大小,如果事务ID大小都一样的话,就会比较服务器ID(SID)
ps 由于我是基于 Docker 部署 ZK 集群,进入其中的ZK节点,执行 cat /data/version-2/currentEpoch 既可以看到epoch的大小
接下来,看下 ZK 集群是怎样选举 Leader 的,但值得注意的是,选举区分了第一次启动和非第一次启动。第一次选举流程比较简单,但非第一次选举的时候,会涉及到 Leader 宕机或假死的情况,这样的话细节就会多一些。
背景:ZK集群是由5台ZK节点组成,只要集群中过半的节点投票就可选出 Leader
在集群节点启动之初,所有的epoch都是一样的,此时 Leader 还没选举出来,此时不会有写请求进来,所以事务Id也是没有的,所以最终的判断条件是根据SID,也就是节点的 ZOO_MY_ID 决定,理论上来说,ZOO_MY_ID 值最大的就会成为Leader,但为什么说是理论上呢?咱们来看下实际的效果。
基于docker-compose一次性部署5台ZK节点,参考我另外一篇博客 Zookeeper系列基于docker-compose快速搭建Zookeeper集群
最终结果是例子中的zoo5成为Leader,符合上面 ZOO_MY_ID 值最大的就会成为 Leader 的说法。
先把5台节点都关掉执行docker-compose stop,模拟集群的节点准备启动的状态,然后依次执行
集群中有5台节点,先启动3台,符合过半投票的情况,这时候已经可以选举出 Leader,盲猜一下,应该是 zoo3 这台机器成为Leader 了吧?进入 zoo3 容器,执行 zkServersh status 查看节点角色。果然,此时的 zoo3 是 Leader
此时,再依次执行 docker start zoo4 和 docker start zoo5,可以发现,Leader依旧是 zoo3。这是因为,当成功选举出 Leader 后,后续启动的 zk 节点都会成为 Follower(现在先不讨论Observer的情况)。
但这种结果并不与选举规则冲突,当 zk 集群内的机器不是同一时刻启动的时候,其大致选举流程是:
但为什么在场景1的时候,不是 zoo3 成为 Leader 而是 zoo5 成为 Leader 呢?这是因为在近乎同一时刻,zk 集群所有的服务都启动了,此时所有节点都是先投票给自己,然后再与其他节点交换信息,发现 zoo5 的 Sid 最大,接着所有的节点都投票给了 zoo5 ,其余节点就都处于 FOLLOWING 状态,而 zoo5 是 LEADING 状态。
假设 zoo3 是 Leader,其余都是 Follower。当 zoo3 宕机,其余节点都变为 FOLLOWING 状态,重新参与选举。
为降低复杂度,将真实的 zxid 简化为只有事务Id。假设 zoo1、zoo2、zoo4、zoo5 的 (epoch,zxid,sid) 分别是 (1,13,1),(1,10,2),(1,13,4),(1,12,5)
此时选举流程是怎样呢?
zoo3 为 LEADING 状态,此时 zoo3 假死。如果 zoo3 忽然网络出问题,断开与其他 follower 节点的连接。其他节点以为 zoo3 宕机,则重新选举新 Leader,假设此时 zoo1 成为大佬,此时 zoo3 忽然正常了,那么剩下的 follower 节点会不会蒙圈?怎么会有两个大佬,正所谓一山不能容二虎,我应该听谁?
实际上,zk 有考虑到这种情况,还记得上面说的 epoch 的定义吗?这是每个 Leader 的代号,每更新一次 Leader,epoch 就会递增1。假如 zoo3 假死前,所有的节点的 epoch 都是2。zoo3 假死,zoo3 的 epoch 不会变,因为没想到有其他节点想替代自己的位置嘛。但其他节点选举 zoo1 为 Leader 后,除了 zoo3 ,其他的节点的 epoch 都是3了。此时 zoo3 恢复正常,即使向其他节点同步事务消息,但其余节点发现 zoo3 的 epoch 和自己不一样,就不会认这个大佬,而是认准 zoo1 才是自己的老大。
实际上,zk 集群的选举并不简单,底层选举算法使用到的 ZAB 协议保证分布式消息一致性,本篇文章并没过多描述。对于初学者来说,了解其选举的规则和某些场景下是如何选举,大概了解流程足矣。当实际开发中,为了保证高可用,需要注意的是 ZK 集群节点为奇数。另外,感兴趣的读者可以再去关注 ZAB 协议的细节。
参考资料:
《从Paxos到Zookeeper分布式一致性原理与实践》
如果觉得文章不错的话,麻烦点个赞哈,你的鼓励就是我的动力!对于文章有哪里不清楚或者有误的地方,欢迎在评论区留言~按照 docker搭建zookeeper集群 中步骤,安装完docker,配置好三台容器后,启动zookeeper环境。发现两台正常,一台报Notification timeout的日志。
而异常的原因是cannot assign requested address。该问题要么ip、port不通要么就是开启监听的server地址和发送消息的地址不对。
查看源码位置,发现在QuorumCnxManagerjava文件中抛的异常
找到异常,去上下看看是否有迹可循
然后,去日志看下绑定的ip、port是什么。发现Slave1的日志里打印出了信息
2018-06-15 01:28:53,612 [myid:3] - INFO [Slave2/1721704:3890:QuorumCnxManager$Listener@534] - My election bind port: Slave2/1721704:3890
我的zoocfg server配置如下
server1=Master:2888:3888
server2=Slave1:2889:3889
server3=Slave2:2890:3890
参考“艾伦蓝”的博客介绍了
serverA=B:C:D: 其中 A 是一个数字,表示这个是第几号服务器; B 是这个服务器的 ip 地址;C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。 如果是伪集群的配置方式,由于 B 都是一样,所以不同的 Zookeeper 实例通信端口号不能一样,所以要给它们分配不同的端口号。
也就是说我本地绑定的端口是server3的端口。(看日志感觉应该起的server2的3889才对!)
剩下的工作就是看看zookeeper配置文件如何加载,为什么解析的不正确!
回到刚才的源码,获取addr的地方:
addr = selfquorumPeersget(selfgetId())electionAddr;
查看QuorumPeerConfigjava发现quorumPeers存的是server1,2,3的信息。那id是哪来的?
public long getId() {
return myid;
}
myid又是从哪里来的?
这个myid是解析myid的文件来的。
莫非是这个myid还要和server#的值必须匹配起来?
server2的myid必须是2。
查看Slave1和Slave2的myid文件,果然Slave1 写的3,Slave2写的2。
以上!得出结论修改Slave1和Slave2的myid文件为2,3。
问题解决!!
Zookeeper 的视图结构是一个树形结构,树上的每个节点称之为数据节点(即 ZNode),每个ZNode 上都可以保存数据,同时还可以挂载子节点。并且Zookeeper的根节点为 "/"。
在 Zookeeper 中,每个数据节点都是有生命周期的,其生命周期的长短取决于数据节点的节点类型。在 Zookeeper 中有如下几类节点:
每个数据节点中除了存储了数据内容之外,还存储了数据节点本身的一些状态信息(State)。
在Zookeeper 中,事务是指能够改变 Zookeeper 服务器状态的 *** 作,我们也称之为事务 *** 作或更新 *** 作,一般包括数据节点创建与删除、数据节点内容更新和客户端会话创建与失效等 *** 作。对于每一个事务请求,Zookeeper 都会为其分配一个全局唯一的事务ID,用 ZXID 来表示,通常是一个 64 位的数字。每一个 ZXID 对应一次更新 *** 作,从这些 ZXID 中可以间接地识别出 Zookeeper 处理这些更新 *** 作请求的全局顺序。
ZXID 是一个 64 位的数字,其中低 32 位可以看作是一个简单的单调递增的计数器,针对客户端的每一个事务请求,Leader 服务器在产生一个新的事务 Proposal 的时候,都会对该计数器进行加 1 *** 作;而高 32 位则代表了 Leader 周期 epoch 的编号,每当选举产生一个新的 Leader 服务器,就会从这个 Leader 服务器上取出其本地日志中最大事务 Proposal 的 ZXID,并从该 ZXID 中解析出对应的 epoch 值,然后再对其进行加 1 *** 作,之后就会以此编号作为新的 epoch,并将低 32 位置 0 来开始生成新的 ZXID。
Zookeeper 中为数据节点引入了版本的概念,每个数据节点都具有三种类型的版本信息(在上面的状态信息中已经介绍了三种版本信息代表的意思),对数据节点的任何更新 *** 作都会引起版本号的变化。其中我们以 dataVersion 为例来说明。在一个数据节点被创建完毕之后,节点的dataVersion 值是 0,表示的含义是 ”当前节点自从创建之后,被更新过 0 次“。如果现在对该节点的数据内容进行更新 *** 作,那么随后,dataVersion 的值就会变成 1。即表示的是对数据节点的数据内容的变更次数。
版本的作用是用来实现乐观锁机制中的 “写入校验” 的。例如,当要修改数据节点的数据内容时,带上版本号,如果数据节点的版本号与传入的版本号相等,就进行修改,否则修改失败。
Zookeeper 提供了分布式数据的发布/订阅功能。一个典型的发布/订阅模型系统定义了一种一对多的订阅关系,能够让多个订阅者同时监听某一个主题对象,当这个主题对象自身状态变化时,会通知所有订阅者,使它们能够做出相应的处理。在 Zookeeper 中,引入了 Watcher 机制来实现这种分布式的通知功能。Zookeeper 允许客户端向服务端注册一个 Watcher 监听,当服务端的一些指定事件触发了这个 Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能。
从上图可以看出 Zookeeper 的 Watcher 机制主要包括客户端线程、客户端WatchMananger 和 Zookeeper 服务器三部分。在具体工作流程上,简单地讲,客户端在向 Zookeeper 服务器注册 Watcher 的同时,会将 Watcher 对象存储在客户端的 WatchMananger 中。当 Zookeeper 服务器端触发 Watcher 事件后,会向客户端发送通知,客户端线程从 WatchManager 中取出对应的 Watcher 对象来执行回调逻辑。
Watcher是一个接口,任何实现了Watcher接口的类就是一个新的Watcher。Watcher内部包含了两个枚举类:KeeperState、EventType
注 :客户端接收到的相关事件通知中只包含状态及类型等信息,不包括节点变化前后的具体内容,变化前的数据需业务自身存储,变化后的数据需调用get等方法重新获取;
上面讲到zookeeper客户端连接的状态和zookeeper对znode节点监听的事件类型,下面我们来讲解如何建立zookeeper的watcher监听。在zookeeper中采用zkgetChildren(path, watch)、zkexists(path, watch)、zkgetData(path, watcher, stat)这样的方式为某个znode注册监听。
下表以node-x节点为例,说明调用的注册方法和可监听事件间的关系:
Zookeeper 中提供了一套完善的 ACL(Access Control List)权限控制机制来保障数据的安全。
ACL 由三部分组成,分别是:权限模式(Scheme)、授权对象(ID)和权限(Permission),通常使用“scheme: id:permission”来标识一个有效的ACL 信息。下面分别介绍:
174、ACL 超级管理员
zookeeper的权限管理模式有一种叫做super,该模式提供一个超管可以方便的访问任何权限的节点
假设这个超管是:super:admin,需要先为超管生成密码的密文
那么打开zookeeper目录下的/bin/zkServersh服务器脚本文件,找到如下一行:
这就是脚本中启动zookeeper的命令,默认只有以上两个配置项,我们需要加一个超管的配置项
那么修改以后这条完整命令变成了
之后启动zookeeper,输入如下命令添加权限
在服务器集群初始化阶段,我们以 3 台机器组成的服务器集群为例,当有一台服务器server1 启动的时候,它是无法进行 Leader 选举的,当第二台机器 server2 也启动时,此时这两台服务器已经能够进行互相通信,每台机器都试图找到一个 Leader,于是便进入了 Leader 选举流程。
在zookeeper运行期间,leader与非leader服务器各司其职,即便当有非leader服务器宕机或新加入,此时也不会影响leader,但是一旦leader服务器挂了,那么整个集群将暂停对外服务,进入新一轮leader选举,其过程和启动时期的Leader选举过程基本一致。
假设正在运行的有server1、server2、server3三台服务器,当前leader是server2,若某一时刻leader挂了,此时便开始Leader选举。选举过程如下:
observer角色特点:
为了使用observer角色,在任何想变成observer角色的配置文件中加入如下配置:
并在所有server的配置文件中,配置成observer模式的server的那行配置追加:observer,例如:
选举计票方法专利名称:高速后台选举计票系统的制作方法技术领域:
本实用新型涉及一种高速后台选举计票系统。
背景技术:
很多国家机关和企事业单位为了便于管理和发展都会定期或者不定期的举办各种会议,其中有部分会议可能涉及到表决事项,为了提高会议表决的效率和计票准确性,电子表决计票系统的应用也越来越广泛。传统的电子表决计票系统大多采用光学标记阅读器(OMR)读取选票信息,光学标记阅读机能识别信息卡上的涂写内容,并传入计算机中处理,其基本原理是发光器件发出的光照射在信息卡的信息位上,如该信息位被涂黑则部分光被吸收,反射光变弱,否则反射光变强,由对应的接收器件将强弱不同的光信息转移成电信号,再经A/D转换、数字滤波、 模式识别后完成对信息卡中字符的识别。但光学标记阅读机识别选票时,对选票格式要求高,识别速度不甚理想。还有一部分传统的选举计票系统,虽然使用扫描仪读取选票信息,但是传统的扫描仪不具有自动进纸的功能,在扫描选票信息时需要一张一张的送纸到扫描仪内, *** 作十分麻烦;此外,传统的扫描仪也不可以将扫描的模拟信号转化为数字信号然后通过接口传输到外接设备上。
实用新型内容本实用新型的目的在于克服现有选举计票系统的不足,提供一种扫描速度快、误码率低且识别范围广的高速后台选举机票系统,同时该选票系统还具有自动进纸的功能, 且可以将扫描的结果通过USB接口传输到外接设备上。本实用新型的目的是通过以下技术方案实现的高速后台选举计票系统,它包括服务器、交换机和至少一个最小系统配置单元,最小系统配置单元通过交换机与服务器连接,所述的最小系统配置单元包括计算机及与之连接的高速扫描仪。高速扫描仪包括设有送纸板的送纸机构和设有搓纸轮、搓纸垫的搓纸机构,送纸板的下部设置有送纸板调节装置,送纸板调节装置包括送纸板调节d簧、送纸板调节顶块、 送纸板调节机构固定架和送纸板调节螺钉,送纸板调节d簧的一端固定在送纸板末端的上方,另一端固定在送纸板调节顶块上,送纸板调节顶块通过送纸板调节螺钉与送纸板调节机构固定架连接;搓纸垫的下部设置有搓纸调节装置,搓纸调节装置包括搓纸垫固定架、搓纸机构安装架、搓纸调节d簧、搓纸调节d簧顶板和搓纸调节螺钉,搓纸垫固定架置于搓纸垫的下方,搓纸调节d簧的一端固定在搓纸垫固定架内,另一端固定在搓纸调节d簧顶板上,搓纸调节d簧顶板通过搓纸调节螺钉与搓纸机构安装架连接。高速扫描仪还设置有电机、扫描条、电路板和USB接口,电机与搓纸轮传动连接, 扫描条的输出接电路板的输入,电路板的输出接USB接口的输入。本实用新型的有益效果是扫描速度快、误码率低、识别范围广,可以将扫描的结果通过USB接口传输到外接设备上。
图1为高速后台选举计票系统结构示意图图2高速扫描仪进纸机构结构示意图图中,1-送纸板,2"送纸板调节d簧,3"送纸板调节顶块,4"送纸板调节机构固定架,5-送纸板调节螺钉,6-搓纸轮,7-搓纸垫,8-搓纸垫固定架,9-搓纸机构安装架,10-搓纸调节d簧,11-搓纸调节d簧顶板,12-搓纸调节螺钉,13-电机,14-扫描条,15-电路板, 16-USB 接口。
具体实施方式
以下结合附图进一步详细说明本实用新型的技术方案如图1所示,高速后台选举计票系统,它包括一台服务器和两个最小系统配置单元,所述的最小系统配置单元包括计算机及与之连接的高速扫描仪,服务器和最小系统配置单元通过网络互连设备互联,其中网络互连设备为交换机。如图2所示,所述高速扫描仪由送纸机构和搓纸机构组成。其中送纸板1的下部设有送纸调节装置,搓纸垫7的下部设有搓纸调节装置。由送纸调节装置和搓纸调节装置配合完成扫描仪的自动进纸和整个工作过程。送纸调节装置由送纸板调节d簧2,送纸板调节顶块3,送纸板调节机构固定架4 和送纸板调节螺钉5组成。送纸板调节d簧2的一端固定在送纸板1末端的下方,另一端固定在送纸板调节顶块3上,调节顶块3通过送纸板调节螺钉5与送纸板调节机构固定架 4连接。搓纸调节装置由搓纸垫固定架8,搓纸机构安装架9,搓纸调节d簧10,搓纸调节d簧顶板11和搓纸调节螺钉12组成。搓纸垫固定架8置于搓纸垫7的下方,搓纸调节d簧10的一端固定在搓纸垫固定架8内,另一端固定在搓纸调节d簧顶板11上,搓纸调节d簧顶板11通过搓纸调节螺钉12与搓纸机构安装架9连接。根据需要扫描的纸张的厚度和数量要求,灵活调节送纸板调节螺钉5以改变送纸板调节d簧给送纸板施加的压力,同时调节搓纸调节螺钉12可以改变搓纸调节d簧对搓纸垫施加的压力,使纸张能够保持相同速度通过仪器,从而达到控制扫描图像的稳定性的目的。在高速扫描仪工作时,根据待扫描纸张情况,将送纸装置和搓纸装置调到合适位置, 电机13转动带动搓纸轮转动,实现自动进纸。纸张进入扫描仪后,由电路板15上的硬件电路和控制程序驱动扫描条14对纸张进行实时的图像采集,并将采样到的模拟信号转化成相应的二进制数据存储在电路板15 上,再由电路板15上的USB接口芯片通过USB接口 16实时地将图像数据传输给主机,最后由主机形成一张完整的灰度图像。所述的高速扫描仪的扫描速度为双面60张/分钟,一次可放入100张选票,可以
自动进纸,不需人工一张一张送纸。一个320人的中等会议选举计票,其处理时间(包括投票、读票、显示结果、打印结果)约为5 10分钟。[0022]如果选举规模超过320人,则可以采用多个最小系统配置单元并行处理,为此,可设置一台服务器,服务器和最小系统配置单元通过网络互连设备互联。本实用新型的工作过程大致为与会代表在会议现场将选票投入到普通票箱中, 工作人员将选票收集起来,放入高速扫描仪的送纸盒,高速扫描仪自动一张一张地扫描每张选票,并将选票正反面图像信息传输到计算机或服务器中,再经高速后台选举计票软件进行识别、处理和统计得到选举结果。本实用新型所述的高速后台选举计票系统具有以下主要功能(1)可提前准备多次会议的选票和模式,正式选举时只需简单的切换;(2) —次选举允许同时使用1至64种不同类型的选票,系统按类自动进行数据处理,统计分析;(3)具备党章和我国宪法规定的党和国家最高人事决策支持所需的完善功能,适用于等额选票、差额选举及等额、差额混合型选举。适用于选举票、表决票等信息处理;(4)系统具有对任一候选人的“弃权”功能对任何候选人,与会者可投“赞成票” 、“反对票”或“弃权票”,一次选举使用的1至64种选票中,任一类既可以含弃权功能,也可以不含弃权功能;(5)校正功能系统可对非正常的误判废选票进行校正,提高数据处理精度,确保选举者权利,这种校正功能在选举办法规定后,监票人监督下进行,代表或委员投票方向及正反面不受限制,票箱自动识别、处理、控制;(6)选票用纸适应范围宽,印刷方便,填写选票简单,填写选票用笔没有限制,代表使用方便;(7)实现“另提人”得票数据的实时计算机处理和有效性判别与控制,实现废票的实时判定与校正处理,另提人和废票的处理不占用额外时间。本实用新型所述的高速后台选举计票系统的主要性能包括(1)选票① 选票用纸120 250克双白卡片纸;②选票尺寸A4QlOmm χ 297mm);③选票候选人最大容量(同时使用赞成、反对和弃权三个信息块)350人。(2)选举系统①选票信息识别误码率彡IO"10;②一次选举中能同时对广64种选票进行分类处理;③系统能满足从2人到10000人不同规模会议选举的需要;④系统可靠性指标达误判选票率λ ^ IO^张;⑤选举结果处理时间(打印文档和显示文档):5^10分钟。(3)高速扫描仪①选票扫描分辨率200DPI ;②选票识别精度1/8毫米;③选票扫描速度双面60张/分钟;④送纸盒容量100张。本实用新型采用高速扫描仪作为选票扫描工具,扫描速度双面60张/分钟,选票信息识别误码率d(Tw,可同时对广64种选票进行分类处理,具有结构简单、可扩展性强、 处理方法灵活、可以将扫描的结果通过USB接口传输到外接设备上等优点。
权利要求1高速后台选举计票系统,其特征在于它包括服务器、交换机和至少一个最小系统配置单元,最小系统配置单元通过交换机与服务器连接,所述的最小系统配置单元包括计算机及与之连接的高速扫描仪;高速扫描仪包括设有送纸板(1)的送纸机构和设有搓纸轮(6)、搓纸垫(7)的搓纸机构,送纸板(1)的下部设置有送纸板调节装置,送纸板调节装置包括送纸板调节d簧(2)、 送纸板调节顶块(3)、送纸板调节机构固定架(4)和送纸板调节螺钉(5),送纸板调节d簧 (2)的一端固定在送纸板(1)末端的上方,另一端固定在送纸板调节顶块(3)上,送纸板调节顶块(3)通过送纸板调节螺钉(5)与送纸板调节机构固定架(4)连接;搓纸垫(7)的下部设置有搓纸调节装置,搓纸调节装置包括搓纸垫固定架(8)、搓纸机构安装架(9)、搓纸调节d簧(10)、搓纸调节d簧顶板(11)和搓纸调节螺钉(12),搓纸垫固定架(8)置于搓纸垫 (7)的下方,搓纸调节d簧(10)的一端固定在搓纸垫固定架(8)内,另一端固定在搓纸调节d簧顶板(11)上,搓纸调节d簧顶板(11)通过搓纸调节螺钉(12)与搓纸机构安装架(9) 连接;高速扫描仪还设置有电机(13)、扫描条(14)、电路板(15)和USB接口( 16),电机(13) 与搓纸轮(6)传动连接,扫描条(14)的输出接电路板(15)的输入,电路板(15)的输出接 USB接口(16)的输入。
专利摘要本实用新型公开了一种高速后台选举计票系统,它包括服务器、交换机和至少一个最小系统配置单元,最小系统配置单元包括计算机及与之连接的高速扫描仪,高速扫描仪包括设有送纸板(1)的送纸机构和设有搓纸轮(6)、搓纸垫(7)的搓纸机构,送纸板(1)和搓纸垫(7)的下部都设置有调节装置,高速扫描仪还设置有电机(13)、扫描条(14)、电路板(15)和USB接口(16),扫描条(14)的输出接电路板(15)的输入,电路板(15)的输出接USB接口(16)的输入。本实用新型的有益效果是扫描速度快、误码率低、识别范围广,可以将扫描的结果通过USB接口传输到外接设备上。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)