首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >JAVAEE分布式技术之Zookeeper技术

JAVAEE分布式技术之Zookeeper技术

作者头像
张哥编程
发布2024-12-13 14:01:24
发布2024-12-13 14:01:24
2780
举报
文章被收录于专栏:云计算linux云计算linux

1,课程回顾 2,本章重点 zk节点类型 zk的常用命令及ACL权限管理 java操作zk(java代码模拟集群管理) 3,具体内容 3.1 zk节点和节点类型 znode数据存储图的讲解 图片: https://uploader.shimo.im/f/udQnNfpVuIeiEluU.png

节点类型: 1、PERSISTENT–持久化目录节点 客户端与zookeeper断开连接后,该节点依旧存在 2、PERSISTENT_SEQUENTIAL-目持久化顺序编号录节点 客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号 3、EPHEMERAL-临时目录节点 客户端与zookeeper断开连接后,该节点被删除,临时节点不可以创建子节点 4、EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点 客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号 3.2 常用命令: 3.2.1 客户端链接: 保证集群启动 使用zkCli.sh默认链接本机 zkCli.sh close 关闭会话 quit 退出 或者直接使用quit 或者使用 zkCli -server ip或者主机名:端口号 链接相应服务器 zkCli.sh -server 192.168.23.11:2181 zkCli.sh -server cluster3:2181 或者是在zk命令行: connect ip地址或者主机名称:端口号, 链接相应服务器 [zk: 192.168.23.12:2181(CONNECTED) 0] connect 192.168.170.42:2181 connect cluster3:2181 quit 退出 3.2.2 常用命令: help 帮助命令,会显示所有zk的命令

ls 存储路径 查看路径下的信息(路径必须是绝对路径) ls [-s] [-w] [-R] path 列出子节点 -s状态( State) -R 递归查看所有子节点(Recursive) -w 添加监听(watch) ls / 查看根目录下的内容 ls -R / 递归查看根节点所有子节点 ls -w / 查看并监听根目录,如果根下子节点发生变化都会被监听到,但是只监听一次(提高zk效率) 在另外一个会话中执行: create /frame1 ‘frame1’ create /frame2 ‘frame2’ 发现只有一次有监控信息 在原会话中执行 ls -w / 在另外一个会话中执行: delete /frame2 delete /frame1 发现只有一次有监控信息

close 关闭与服务端的链接 close quit 退出

create [-s] [-e] path [data] [acl] -s 创建有序节点 -e 创建临时节点 data 节点内容 acl(access control list) 访问控制权限 创建持久节点 create /frame ‘frame’ create /frame/spring ‘spring’ ls /frame close quit zkCli.sh 再次连接,发现会话ID发生变化,说明不上一次会话 ls / ls /frame 断开会话后持久化节点依然存在

创建持久有序节点 create -s /frame/spring/ioc ‘ioc1’ create -s /frame/spring/ioc ‘ioc2’ create -s /frame/spring/ioc ‘ioc3’ ls /frame/spring 发现3个持久有序节点 quit 退出 zkCli.sh 再次连接,发现会话ID发生变化,说明不上一次会话 ls /frame/spring 发现3个持久有序节点依然存在 create /frame/spring/ioc0000000000/ioccontainer ‘iocc’ 在持久有序节点下还可以创建子节点 ls /frame/spring/ioc0000000000 总结: 只要持久节点,都可以有子节点 创建临时节点:create -e 路径 “字符串信息” (-e是创建短暂节点) create -e /frame/spring/aop ‘aop’ ls -s /frame/spring/aop 发现 ephemeralOwner 就是依赖当前会话ID ls -s / ls -s /frame 发现持久节点 ephemeralOwner 都是0x0 create /frame/spring/aop/cglibproxy ‘cglibproxy’ create -e /frame/spring/aop/cglibproxy ‘cglibproxy’ 都错误 临时节点不能有子节点

创建 临时有序节点 create -e -s /frame/spring/mvc ‘mvc1’ create -e -s /frame/spring/mvc ‘mvc2’ create -e -s /frame/spring/mvc ‘mvc3’ ls /frame/spring create -e -s /frame/spring/mvc0000000005/ds ‘DespatcherServlet’ ls -s /frame/spring/mvc0000000005 发现 ephemeralOwner 就是依赖当前会话ID quit zkCli.sh ls /frame/spring/ 退出quit当前节点,再次链接zkCli.sh查看,发现临时节点不存在

代码语言:javascript
复制
   总结:   只要是临时节点,都不可以有孩子

在zk1查看节点 get 路径 [watch] 获取数据时,启动监听,监听数据(只生效一次) [zk: localhost:2181(CONNECTED) 18] get /aaa watch 在zk2在另一链接上: [zk: localhost:2181(CONNECTED) 0] set /aaa 11 zk1截图:

get [-s] [-w] path 查看节点数据 -s 包含节点状态 -w 添加监听 get /frame/spring get -s /frame/spring set /frame/spring ‘spirng1’ get -s /frame/spring set /frame/spring ‘spirng111’ get -s /frame/spring create /frame/spring/boot ‘boot’ get -s /frame/spring delete /frame/spring/boot get -s /frame/spring get -w /frame/spring 查看节点内容并监控 但是也是只监控一次 在另外一个会话中,改变/frame/spring的内容 set /frame/spring ‘spirng4’ set /frame/spring ‘spirng5’ 发现只有一次可以触发监控

zxid:节点创建时的zxid ctime:节点创建时间 mZxid:节点最近一次更新时的zxid mtime:节点最近一次更新的时间 pZxid: 表示该节点的子节点列表最后一次修改的事务ID,添加子节点或删除子节点就会影响子节点列表,但是修改子节点的数据内容则不影响该ID cversion:子节点更新次数 dataVersion:本节点数据更新次数 aclVersion:节点ACL(授权信息)的更新次数 ephemeralOwner:如果该节点为临时节点,ephemeralOwner值表示与该节点绑定的session id. 如果该节点不是临时节点,ephemeralOwner值为0 dataLength:节点数据长度,本例中为hello world的长度 numChildren:子节点个数 set 更新节点内容: set /frame/spring ‘spring1’ 更新节点内容

delete [-v version] path 删除单个节点 删除节点,(不能存在子节点) delete /frame/spring/mvc0000000008 create /frame/spring/boot ‘boot’ create /frame/spring/boot/sarun ‘SpringApplicationrun’ delete /frame/spring/boot 错误 deleteall path 删除路径及所有子节点 deleteall /frame/spring/boot stat查看节点的状态 stat /frame/spring setquota增加配额 setquota -n|-b val path -n 设置子节点的配额数量 -b 设置节点内容的长度 setquota -n 3 /frame 为/frame路径设置子节点数量限制 包含自己在内,最多3个子节点 listquota /frame 查看配额 ls /frame 查看子节点 在另外一个会话中打开日志: tail -f /usr/zookeeper/logs/zookeeper-root-server-cluster1.out create /frame/mybatis ‘ORM’ create /frame/hibernate ‘ORM’ 第二次创建目录时就会提示 listquota查询配额 listquota path -1 表示无限, 即没有限制 listquota /frame delquota删除配额 delquota [-n|-b] path delquota /frame 删除所有配额 3.2.3 ACL权限控制: ACL:Access Control List 访问控制列表 相关命令: getAcl 获取某个节点的acl权限信息 setAcl 设置某个节点的acl权限信息 addauth 输入认证授权信息,注册时输入明文密码(登录),但是在zk的系统里,密码是以加密后的形式存在的 特性: ZooKeeper的权限控制是基于每个znode节点的,需要对每个节点设置权限   每个znode支持设置多种权限控制方案和多个权限   子节点不会继承父节点的权限,客户端无权访问某节点,但可能可以访问它的子节点

授权格式: 授权策略:授权对象: 权限 scheme: id: Permission   Scheme:(计划)授权的策略 包含下面: world:默认方式,相当于全部都能访问 代表所有人  ip:使用客户端的主机IP作为ACL ID 。这个ACL表达式的格式为addr/bits ,此时addr中的有效位与客户端addr中的有效位进行比对。   auth:使用已添加认证的用户认证(cli中可以通过addauth digest user:pwd 来添加当前上下文中的授权用户)   digest:即用户名:密码这种方式认证,这也是业务系统中最常用的。用 username:password 字符串来产生一个MD5串,然后该串被用来作为ACL ID。认证是通过明文发送username:password 来进行的,当用在ACL时,表达式为username:base64 ,base64是password的SHA1摘要的编码。   ID:授权的对象 权限赋予的用户或者一个实体,例如:IP 地址 或者是用户(授权) 或者是 anyone   Permission:授予的权限 CRWDA zookeeper支持的权限 CREATE©: 创建权限,可以在在当前node下创建child node READ®: 读权限,可以获内容及子节点 WRITE(w): 写权限,可以向当前node写数据 DELETE(d): 删除权限,可以删除当前的child nodes ADMIN(a): 管理权限,可以设置当前node的permission

测试: world: getAcl /aaa //获取原来权限列表 setAcl /aaa world:anyone:cda //设置新的访问权限列表 getAcl /aaa //再次查看 get /aaa //没有r时,不可以查看节点内容 setAcl /aaa world:anyone:crwda //设置为原来的 get /aaa //又可以查看 ip: create /a1 ‘a1’ //创建新节点 setAcl /a1 ip:127.0.0.1:crwda getAcl /a1 get /a1 //获取不到数据 quit //退出 zkCli.sh -server 127.0.0.1:2181 //重新登录 get /a1 //获取到数据 setAcl /a1 ip:192.168.23.91:cdwra,ip:192.168.23.92:cdwra getAcl /a1 quit zkCli.sh -server 192.168.23.91:2181 //重新登录,限制只能是本机登录 get /a1 //可以获取 zkCli.sh -server 192.168.23.93:2181 //在93登录 get /a1 //不可以 auth: create /a2 ‘a2’ getAcl /a2 addauth digest scott:tiger #增加授权用户,明文用户名和密码 setAcl /a2 auth:scott:cdwra  #授予权限 getAcl /a2 //设置时为明码,查看时,加密过的 get /a2 可以查看 重新链接后,需要再次添加授权用户才可以查看: addauth digest admin:123 // 设置错误的认证信息 get /a2 // 不可以查看 addauth digest scott:tiger //设置正确的认证信息 get /a2 //可以 digest: create /a3 ‘a3’ getAcl /a3 setAcl /a3 digest:user:6DY5WhzOfGsWQ1XFuIyzxkpwdPo=:crwda #授权 getAcl /a3 rmr /a3 #直接删除没权限 addauth digest user:123456 #增加认证用户 rmr /a3 // 成功 3.3 zookeeper java api 使用下列地址查找依赖包: ​​​ https://mvnrepository.com/​​ 1,创建项目,引入jar包

代码语言:javascript
复制
<dependency>
  <groupId>org.apache.zookeeper</groupId>
  <artifactId>zookeeper</artifactId>
  <version>3.4.13</version>
</dependency>

   <!--日志 start-->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.25</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.25</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.7.25</version>
        <scope>test</scope>
    </dependency>
    <!--日志end-->

2,增删改查 config.properties #链接字符串 C:\Windows\System32\drivers\etc\hosts 和/etc/hosts connectString=zk1:2181,zk2:2181,zk3:2181,zk4:2181,zk5:2181 #链接超时时长 sessionTimeout=2000

代码语言:javascript
复制
  192.168.170.41 cluser1

192.168.170.42 cluser1 192.168.170.43 cluser1

ZookeeperUtil package com.aaa.util;

import org.apache.zookeeper.*; import org.apache.zookeeper.data.Stat;

import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.List; import java.util.Properties;

/**

  • fileName:ZookeeperUtil
  • description:
  • author:zz
  • createTime:2020/5/16 9:34
  • version:1.0.0 */ public class ZookeeperUtil { private Properties properties; //各个方法共享 private ZooKeeper zooKeeper; /**
  • 空构造,初始化配置文件 */ public ZookeeperUtil(){ InputStream inputStream = null; try { // Properties 是Map子孙类 properties = new Properties(); //使用任意类的Class对象中提供的getResourceAsStream读取配置文件为 输入字节流 inputStream =ZookeeperUtil.class.getResourceAsStream(“/config.properties”); //加载内容 properties.load(inputStream); } catch (IOException e) { e.printStackTrace(); }finally { try { if(inputStream!=null){ inputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } }

/**

  • 初始化zk */ public void initZk(){ try { zooKeeper = new ZooKeeper(properties.getProperty(“connectString”), Integer.valueOf(properties.getProperty(“sessionTimeout”)), new Watcher() { @Override public void process(WatchedEvent watchedEvent) { System.out.println(“当查看子节点或者查看节点数据时,使用watch时,在这回调”); } }); } catch (IOException e) { e.printStackTrace(); } }

/**

  • 节点的创建
  • @param path 节点路径
  • @param nodeData 节点数据
  • @param type 节点类型 type=0 持久节点 type=1 临时节点 type=2 持久有序 type=3 临时有序
  • @return */ public boolean createZKNode(String path,String nodeData,int type){ //String path, byte[] data, List acl, CreateMode createMode try { // nodeData.getBytes(“utf-8”) 支持中文的 zooKeeper.create(path,nodeData.getBytes(“utf-8”), ZooDefs.Ids.OPEN_ACL_UNSAFE,// world:anyone:crwda CreateMode.fromFlag(type) //type=0 持久节点 type=1 临时节点 type=2 持久有序 type=3 临时有序 ); return true; } catch (Exception e) { e.printStackTrace(); } return false; }

/**

  • 根据节点路径查询子节点
  • @param path 节点路径
  • @param isWatch 是否监控
  • @return */ public List getChirdrenByPath(String path,boolean isWatch){ try { //查询并返回 return zooKeeper.getChildren(path, isWatch); } catch (Exception e) { e.printStackTrace(); } return null; }

/**

  • 根据节点路径删除节点
  • @param path
  • @return */ public boolean deleteNodeByPath(String path){ try { // version=-1 删除所有版本 zooKeeper.delete(path,-1); return true; } catch (Exception e) { e.printStackTrace(); } return false; }

/**

  • 获取节点数据
  • @param path
  • @param isWatch
  • @return / public String getNodeData(String path,boolean isWatch){ try { byte[] byteArray = zooKeeper.getData(path, isWatch, null); return new String(byteArray); } catch (KeeperException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } return null; } /*
  • 节点数据的更新
  • @param path
  • @return */ public boolean updateNodeData(String path,String nodeData){ try { zooKeeper.setData(path,nodeData.getBytes(“utf-8”),-1); return true; } catch (Exception e) { e.printStackTrace(); } return false; }

/**

  • 判断节点是否存在
  • @param path
  • @return */ public boolean isNodeExist(String path){ try { Stat exists = zooKeeper.exists(path, false); if(exists!=null) return true; } catch (Exception e) { e.printStackTrace(); } return false; } }

ZKUtilTest package com.aaa.test;

import com.aaa.util.ZookeeperUtil; import org.apache.zookeeper.ZooKeeper; import org.junit.After; import org.junit.Before; import org.junit.Test;

import java.util.List;

/**

  • fileName:ZKUtilTest
  • description:
  • author:zz
  • createTime:2020/5/16 11:13
  • version:1.0.0 */ public class ZKUtilTest { private ZookeeperUtil zookeeperUtil; /**
  • 执行Test之前执行的方法 */ @Before public void init(){ //加载配置读取配置 zookeeperUtil = new ZookeeperUtil(); //使用配置连接zk集群 zookeeperUtil.initZk(); }

/**

  • 测试创建节点方法 */ @Test public void testCreateZKNode(){ boolean result = zookeeperUtil.createZKNode(“/testCreateNode1/cnode”, “子节点3”, 2); if(result){ System.out.println(“操作成功”); }else { System.out.println(“操作失败”); } }

/**

  • 测试获取子节点 */ @Test public void testGetChirdrenByPath(){ List chirdren = zookeeperUtil.getChirdrenByPath(“/testCreateNode1”, false); System.out.println(“子节点有:”); for (String s : chirdren) { System.out.println(s); } }

/**

  • 测试获取接单数据 / @Test public void testGetNodeData(){ String nodeData = zookeeperUtil.getNodeData(“/testCreateNode1”, false); System.out.println(nodeData); } /*
  • 测试更新数据 */ @Test public void testUpdateNodeData(){ //测试节点是否存在 if(zookeeperUtil.isNodeExist(“/testCreateNode1”)){ boolean result = zookeeperUtil.updateNodeData(“/testCreateNode1”, “根节点。。。”); if(result){ System.out.println(“操作成功”); }else { System.out.println(“操作失败”); } }

}

/**

  • 测试删除节点 */ @Test public void testDeleteNodeByPath(){ List chirdren = zookeeperUtil.getChirdrenByPath(“/testCreateNode1”, false); //判断是否有子节点 if(chirdren!=null&&chirdren.size()>0){ //循环删除子节点 for (String c : chirdren) { zookeeperUtil.deleteNodeByPath(“/testCreateNode1/”+c); } } //在删除父节点 boolean result = zookeeperUtil.deleteNodeByPath(“/testCreateNode1”); if(result){ System.out.println(“操作成功”); }else { System.out.println(“操作失败”); } }

@After public void distory(){ System.out.println(“最终执行的方法。。。”); } }

代码语言:javascript
复制
 回顾:
        zk数据存储  树状,节点类型4中:
            持久节点,持久有序节点,临时节点,临时有序节点
        命令:
               help   帮助命令(查看所有命令)
               connect   ip(或者主机名称):端口(2181)
               close   关闭当前的会话
               quit    退出
               create  [-s]  [-e]  /路径   内容   创建节点,默认就是持久节点,根据参数不同,创建不同节点
               set   /路径    内容     修改节点内容
               get   /路径   [watch]    获取节点内容[是否监听(只监听一次)]
               getAcl   /路径       ACL (访问控制列表,对每个节点进行设置,不会级联子节点)
                                          默认: world:anyone:crwda
               setAcl   /路径     schema:id:permission 
                                         schema:    world   ip   auth   digest 
                                         id:       anyone   ip     自定义用户(scott,admin) 
                                         permission:   create  是否创建子节点   
                                                               read   获取当前节点内容
                                                               write  修改当前节点内容
                                                               delete   删除当前节点内容
                                                               admin   是否可以修改ACL访问控制列表  
            delete  /路径     只能删除没有子节点的节点
            rmr     /路径     可以删除所有节点(有字节点也可以)
             ls      /路径   [watch]   查看子节点   [可以使用监听,子节点发生变化(添加和删除),只监听一次]
            histroy   返回最近使用的10条命令
        java  对zk的操作(和命令操作类似,只不过换成了 java代码)

3.4 java模拟zk管理其他集群 (练习zookeeper java 方法操作) 1,分析原理

图片: https://uploader.shimo.im/f/wlFxW2mjESjUzbv9.png

2,开发代码 util类: package com.aaa.test;

import java.io.IOException; import java.io.InputStream; import java.util.Properties;

/**

  • fileName:LoadP
  • description:
  • author:zz
  • createTime:2020/7/14 21:11
  • version:1.0.0 */ public class LoadP { /**
  • 加载配置文件方法
  • @param path
  • @return */ public static Properties load(String path){ Properties properties = new Properties(); InputStream inputStream = LoadP.class.getResourceAsStream(“/”+path); try { properties.load(inputStream); } catch (IOException e) { e.printStackTrace(); } return properties; } }

服务注册: package com.aaa.test.file;

import com.aaa.test.LoadP; import org.apache.zookeeper.*; import org.apache.zookeeper.data.Stat;

import java.util.Properties;

/**

  • fileName:HdfsServer
  • description:
  • author:zz
  • version:1.0.0 */ public class HdfsServer { private ZooKeeper zooKeeper; // private static final String parentPath=“/servers”; private Properties load = LoadP.load(“zk.properties”); /**
  • 获取连接
  • @throws Exception */ public void getZKConnect() throws Exception{ zooKeeper = new ZooKeeper(load.getProperty(“cstr”), Integer.valueOf(load.getProperty(“to”)), new Watcher() { public void process(WatchedEvent watchedEvent) { } }); }

/**

  • 注册
  • @param serverName
  • @throws KeeperException
  • @throws InterruptedException */ public void registerToZkCluster(String serverName) throws KeeperException, InterruptedException { Stat stat = zooKeeper.exists(load.getProperty(“parentPath”), false); if(stat==null) { String parentPath = zooKeeper.create(load.getProperty(“parentPath”), serverName.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.println(“无父节点,创建:”+parentPath); } String s = zooKeeper.create(load.getProperty(“parentPath”) + “/hdfs”, serverName.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); System.out.println(serverName+“主机上线了,注册节点为”+s); }

/**

  • 处理业务
  • @param serverName
  • @throws InterruptedException */ public void handleService(String serverName) throws InterruptedException { System.out.println(serverName+“开始工作,准备存储或者下载文件。。。”); Thread.sleep(Integer.MAX_VALUE); }

public static void main(String[] args) throws Exception { HdfsServer hdfsServer =new HdfsServer(); hdfsServer.getZKConnect(); //args[0]=“cs1”; hdfsServer.registerToZkCluster(args[0]); hdfsServer.handleService(args[0]); }

}

web服务感知: package com.aaa.test.file;

import com.aaa.test.LoadP; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper;

import java.util.ArrayList; import java.util.List; import java.util.Properties;

/**

  • fileName:WebServer
  • description:
  • author:zz
  • version:1.0.0 */ public class WebServer { private ZooKeeper zooKeeper; private Properties load = LoadP.load(“zk.properties”); /**
  • 获取连接
  • @throws Exception */ public void getZKConnect() throws Exception{ zooKeeper = new ZooKeeper(load.getProperty(“cstr”), Integer.valueOf(load.getProperty(“to”)), new Watcher() { public void process(WatchedEvent watchedEvent) { try { watchServerList(); } catch (KeeperException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }); }

/**

  • 监控集群中服务器状态
  • @throws KeeperException
  • @throws InterruptedException */ public void watchServerList() throws KeeperException, InterruptedException { List children = zooKeeper.getChildren(load.getProperty(“parentPath”), true); List hdfsList =new ArrayList(); for (String child : children) { byte[] data = zooKeeper.getData(load.getProperty(“parentPath”) + “/” + child, false, null); hdfsList.add(new String(data)); } System.out.println(“工作的HDFS有:”+hdfsList); }

/**

  • 运行web业务
  • @throws InterruptedException */ public void handleWebService() throws InterruptedException { System.out.println(“web 服务器在正常工作。。。”); Thread.sleep(Integer.MAX_VALUE); }

public static void main(String[] args) throws Exception { WebServer webServer=new WebServer(); webServer.getZKConnect(); webServer.watchServerList(); webServer.handleWebService(); } }

jar包运行: 图片: https://uploader.shimo.im/f/3Zf4efYpDpC3PQul.png 图片: https://uploader.shimo.im/f/ws7APmZ1oIc9LYLy.png

代码语言:javascript
复制
    java -cp  *.jar  含有main的类  参数

具体操作, cmd ->进入jar的存放目录,执行如下命令:

java -cp .\ZooKeeperDemo.jar com.aaa.zk.dp.FtpServers ftpa java -cp .\ZooKeeperDemo.jar com.aaa.zk.dp.FtpServers ftpb java -cp .\ZooKeeperDemo.jar com.aaa.zk.dp.FtpServers ftpc java -cp .\ZooKeeperDemo.jar com.aaa.zk.dp.FtpServers ftpd

java -cp .\ZooKeeperDemo.jar com.aaa.zk.dp.FtpClients

4,知识点总结 5,本章面试题

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-10-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档