为了账号安全,请及时绑定邮箱和手机立即绑定
3.2 电话和短信

Phone 设置项中可以模拟来电和短信:From:选择或输入电话号码;CALL DEVICE:点击来电;HOLD CALL:点击保持通话;END CALL:点击结束通话;SMS message:输入模拟消息的正文内容;SEND MESSAGE:点击发送短信。

3.1 模拟电话

模拟10086来电;gsm call 10086模拟接听来电;gsm accept 10086模拟挂断来电;gsm cancel 10086下面是完整会话示例。pt@Win10-Panda:~$ telnet localhost 5554Trying 127.0.0.1...Connected to localhost.Escape character is '^]'.Android Console: Authentication requiredAndroid Console: type 'auth <auth_token>' to authenticateAndroid Console: you can find your <auth_token> in'C:\Users\panda\.emulator_console_auth_token'OKauth KeGgPVHDN7YifXfZAndroid Console: type 'help' for a list of commandsOKgsm call 10086OKgsm accept 10086OKgsm cancel 10086OK

2.5 电话模拟命令

命令说明gsm {call\accept\cancel\busy} phonenumber模拟电话的呼入、接听、挂断、繁忙。gsm {data\voice} statedata state 命令用于更改 GPRS 数据连接的状态,data voice state 则用于更改 GPRS 语音连接的状态。gsm hold将通话状态更改为 hold。只有在当前状态为 active 或 waiting 时,才能将通话状态更改为 hold。gsm list列出所有呼入电话和外拨电话及其通话状态。gsm status报告当前的 GSM 语音/数据连接状态。相关的值就是前述 voice 和 data 命令的值。

3. Zookeeper 的会话

Zookeeper 是一个 C/S 架构的服务,也就是 Client — Server 的形式。在我们使用 Zookeeper 时,都是使用 Zookeeper 的客户端向服务端发送请求,然后由服务端做出响应返回到客户端。在这个过程中,Zookeeper 的客户端需要与 Zookeeper 服务端建立连接,建立一个连接就是新建一个会话,那么会话的状态也就是 Zookeeper 客户端与 Zookeeper 服务端的连接状态。接下来我们从会话的结构开始进行讲解:

3.1 微信小程序 API

uni-app 的 API 与微信小程序 API 基本一致。掌握微信小程序 API 对后面的开发很有帮助。微信小程序 API 文档:https://developers.weixin.qq.com/miniprogram/dev/api/

新浪微博

咱们打开新浪微博,然后随便找个带皇冠的,按下F12键(Mac用户按command+option+i)然后选中控制台的箭头,再点击皇冠:再点开这个图片可以发现:可以看到那些大 V 图标皇冠图标以及各种微博认证等图标,都是放在了一张雪碧图里(即使再牛的大 V,身份标志也是放在雪碧图中的)。

6.2 新增联系人

function addUser(button){ var children = $(button).parent().children(); var name = children.eq(0).val(); var phone = children.eq(1).val(); var data = JSON.stringify({'name': name, 'phone': phone}); $.ajax({ 'url': '/users', 'type': 'POST', 'contentType': 'application/json', 'data': data, 'dataType': 'json', 'error': ajaxError, 'success': ajaxSuccess });}点击 “新增” 按钮后,执行函数 addUser(button),button 指向的是 “新增” 按钮。在 templates/index.html 中,按钮、联系人姓名、联系人电话于相同的 DIV 中,如下所示:<div class="row"> <input type="text" placeholder='姓名'> <input type="text" placeholder='电话'> <span class="button" onclick="addUser(this);">增加</span></div>在第 3 行到第 5 行,表达式的含义如下所示:表达式含义$(button).parent()指向按钮的父节点$(button).parent().children()表示 div 的 3 个子节点children.eq(0)指向联系人姓名children.eq(1)指向联系人电话children.eq(2)指向新增按钮在第 4 行,根据联系人的姓名和电话创建一个新联系人,将它作为参数、调用后端新增联系人的服务。在第 8 行,通过 jquery 的 ajax 函数调用后端服务,设置 url 为 ‘/users/’、type 为 ‘POST’ ,表示 RESTful 架构下的新增联系人。

3.1 打包为微信小程序

注册微信小程序账号,获取到 AppID,我们后面配置的时候会用到。在 HBuilderX 工具栏,点击发行,选择小程序-微信。输入小程序名称和 AppID,单击发行就可以了。这样我们就会获得一个微信小程序的打包文件,接下来我们来发布微信小程序项目,打开微信小程序开发者工具,导入刚刚生成的微信小程序项目的打包文件,在微信小程序开发者工具中先测试一下,项目运行是否正常,项目测试没有问题后,点击右上角>>按钮,上传代码就可以发布微信小程序了,最后等待微信团队审核通过,别人就可以在线上访问到你的项目了。

2.1 微框架

Flask 是一个 Python 实现的 Web 开发微框架,但是这个“微”并不代表着 Flask 功能比较简陋、有所欠缺。微框架中的 “微” 意味着:Flask 旨在保持核心简单而易于扩展;Flask 不会替用户做出太多决策,比如使用何种数据库;Flask 的选项(比如使用何种模板引擎) 通常有多个,用户很容易替换。默认情况下,Flask 不包含数据库抽象层、模板引擎、身份认证或其它任何已有多种库可以胜任的功能,如下图所示。然而,Flask 支持用扩展来给应用添加这些功能,应用程序可以很方便的集成这些扩展。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。

1. 数据转成电信号

数据转换成电信号还是比较简单的,将字符根据指定的编码转换成唯一的二进制编码,然后将二进制的 01 映射成高低电平就可以传输出去了。

3.3 会话层

通过传输层,建立了数据的传输通道。不同应用有自己不同的会话标识,所以传输过来的数据根据会话标识能够知道跟电脑的哪个应用在通信的。

2. 几种常用的客户端-服务器消息传递方式

http 最常用的协议,用于客户端主动向服务器发送请求,单向传递;ajax HTTP 的扩展版,底层还是 HTTP 协议,只不过客户端是无刷新的;comet 也是基于 HTTP 封装的,使用 HTTP 长连接的方式,原理大致是将 HTTP 的timeout 设置较长,服务器有数据变化时返回数据给客户端,同时断开连接,客户端处理完数据之后重新创建一个 HTTP 长连接,循环上述操作(这只是其中一种实现方式);websocket 这是 HTML5 中的新标准,基于 socket 的方式实现客户端与服务端双向通信,需要浏览器支持 HTML5;Adobe Flash Socket 这个也是使用 socket 的方式,需要浏览器支持 flash 才行,为了兼容老版本的浏览器;ActiveX object 只适用于 IE 浏览器;目前尚没有一种方式能兼容所有的浏览器,只能针对软件的目标客户人群做一定的兼容。sse 服务端单向推送。

2. 服务快速失败之服务熔断机制

服务熔断机制的服务快速失败所实现的目标,和我们在上述小节中所介绍的普通的服务快速失败所实现的目标相同,都是为了保证,在某一微服务发生故障时,不影响后续微服务的正常运行。雪崩效应产生原理在上述小节中,各位同学已经对什么是雪崩效应有所了解,如上图所示,我们所讲的服务熔断也是为了避免和解决雪崩现象的发生,只不过所采用的手段不同而已,那么接下来,就让我们来看一下基于服务熔断机制的服务快速失败的概念是什么吧。针对服务熔断机制,我们先来介绍什么是熔断?熔断这一名词,其实不是来源于计算机相关专业,而是来源于电子工程相关专业。熔断的核心是断路器,对于断路器来说,我们可以将断路器理解为一根保险丝,在日常生活中,当我们家庭用电超过负载时,保险丝就会迅速烧断,阻止由于电流过大而烧毁整个家庭电路。同样地,熔断我们也可以像保险丝那样理解,即在计算机相关领域中,由于中断上游的故障服务,而保全整体的服务的措施就被称为熔断,而实现中断上游的故障服务所采取的核心措施就是我们的断路器。服务熔断机制就是把这些概念都统一起来,然后封装到 Hystrix 中,且最终应用于我们的微服务项目中间,通过配置断路器,来保全我们整体的微服务项目,这就是 Hystrix 所提供的服务熔断机制。Tips: 1. 在实际工作中,我们需要灵活的去配置微服务项目中,各个领域的微服务所对应的断路器配置,包括间隔时间、持续时间等关键属性,切记不要凭感觉去配置; 2. Hystrix 本身所提供的服务熔断机制并不是很好用,往往需要我们在项目中集成其他的微服务服务中间件来一起集成使用,单独使用 Hystrix 服务熔断机制的项目很少见。

3.1 关于微服务监控平台

技巧 1如果我们的微服务监控平台没有任何数据,或者说,在打开微服务平台之后,各参数一直处于 loading 状态,这个时候,我们只需要在服务端调用任意一个服务接口即可,这样在微服务监控平台,我们就能看到被监控实例的参数了。技巧 2如果我们在访问 /actuator/hystrix.stream 路径时,系统找不到对应的路径,即报 404 异常,那么我们需要在对应项目的启动类中添加一个 Bean :@Beanpublic ServletRegistrationBean hystrixMetricsStreamServlet() { ServletRegistrationBean registration = new ServletRegistrationBean(new HystrixMetricsStreamServlet()); registration.addUrlMappings("/hystrix.stream"); return registration;}这样我们就能正常访问 /actuator/hystrix.stream 下的路径了。

4.3 DDOS攻击

DDOS(Distributed Denial of Service)也是一种经典的攻击模式,它不是利用服务器存在什么漏洞,而是直接粗狂的用大流量来访问你的网站,使你的网站承受不了这么多流量而崩溃。这种模式有时候还挺难处理的,因为流量的来源可能是一种变化的,都没有固定 IP 防不胜防。而这些攻击你的电脑可能是来自各地的私人电脑,只是被黑客利用了的傀儡机。

4.1 主要泄漏信息

IP 地址,物理地址网站后台访问地址,密码信息家庭成员信息,电话信息生日(很多人的秘密是生日日期)公司信息,同事信息

1.2 没有验证通信方身份

通信双方无法确认对方的身份是否正确。案例1:本地电脑有木马,路由表被踹改,www.baidu.com 的域名被解析到另一台虚假的服务器,此时你在浏览器访问的百度就是黑客的另一个钓鱼网站,然后给你推送了很多虚假消息,此时客户端很难知情。案例2:路由表没问题,但是目标服务器被人黑了,处理不了请求,此时有其它服务冒充提供服务。案例3:某个资源只有特定用户有查询的权限,黑客通过伪造该客户端一样的请求来查询,服务端只是简单的根据入参判断,并无法知道对应客户端的真实性,于是消息很容易泄漏。

1. 为什么需要Cookie和Session?

在 Web 程序中,对会话的跟踪是很一件非常重要的事情。通常,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能互不干扰。然而大部分的 Web 应用程序都是使用HTTP 协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。如果 Web 服务上没有这种的会话追踪功能,那么大部分网站都会陷入一片混乱。特别是对于电商网站而言,如果我添加一次购物车就需要登录一次确认身份,那对于用户体验而言是糟糕透的。会话(Session)跟踪是 Web 程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。正是有了 Cookie 和 Session 这样的会话跟踪技术,弥补了 HTTP 协议无状态的不足,才使得我们可以无差别的访问网站,即只需要一次登录,后续所有的操作通过 Cookie 或者 Session 便能自动识别为该用户,并维持在一个会话中。

2.3 服务消费者

我们在服务提供者的同级新建项目服务消费者,使用 Spring Initializr 来初始化,以下是服务消费者的项目信息:pom.xml初始化完成,我们在 pom.xml 文件中加入需要的依赖。<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>cn.cdd</groupId> <artifactId>zookeeper-consumer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>zookeeper-consumer</name> <description>zookeeper-consumer Demo project for Spring Boot</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- curator 客户端 --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>5.1.0</version> </dependency> <!-- curator 客户端 --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>5.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>application.properties依赖导入后,我们在 application.properties 配置端口信息server.port=9090接下来我们编写使用 Curator 客户端连接 Zookeeper 服务的代码。CuratorService在项目主类的同级新建目录 service 目录,在 service 目录下新建 CuratorService 类:@Componentpublic class CuratorService implements ApplicationRunner { private static CuratorFramework client; private static final String PROVIDER_NODE = "/imooc/provider"; private static List<String> PROVIDER_SERVER_LIST; private static int NUMBER_OF_REQUESTS = 0; @Override public void run(ApplicationArguments args) throws Exception { // 构建 CuratorFramework 客户端,并开启会话 buildCuratorClient(); // 获取服务列表 getAListOfServiceAddresses(); // 开启对 PROVIDER_NODE 子节点变化事件的监听 startMonitoring(); } /** * 构建 CuratorFramework 客户端,并开启会话 */ private void buildCuratorClient() { // 使用 CuratorFrameworkFactory 构建 CuratorFramework client = CuratorFrameworkFactory.builder() .sessionTimeoutMs(10000) // Zookeeper 地址 .connectString("127.0.0.1:2181") // 重连策略 .retryPolicy(new RetryForever(10000)) .build(); // 开启会话 client.start(); System.out.println(">>> 服务消费者连接 Zookeeper "); } /** * 获取服务列表 * * @throws Exception Exception */ private void getAListOfServiceAddresses() throws Exception { Stat stat = client.checkExists().forPath(PROVIDER_NODE); if (stat == null) { throw new RuntimeException("服务地址未注册到 Zookeeper"); } else { PROVIDER_SERVER_LIST = client.getChildren().forPath(PROVIDER_NODE); } } /** * 开启对 PROVIDER_NODE 子节点变化事件的监听 */ public void startMonitoring() { // 构建 CuratorCache 实例 CuratorCache cache = CuratorCache.build(client, PROVIDER_NODE); // 使用 Fluent 风格和 lambda 表达式来构建 CuratorCacheListener 的事件监听 CuratorCacheListener listener = CuratorCacheListener.builder() // 开启对 PROVIDER_NODE 节点的子节点变化事件的监听 .forPathChildrenCache(PROVIDER_NODE, client, (curator, event) -> // 重新获取服务列表 PROVIDER_SERVER_LIST = curator.getChildren().forPath(PROVIDER_NODE)) // 初始化 .forInitialized(() -> System.out.println(">>> CuratorCacheListener 初始化")) // 构建 .build(); // 注册 CuratorCacheListener 到 CuratorCache cache.listenable().addListener(listener); // CuratorCache 开启缓存 cache.start(); } /** * 轮询策略,按顺序获取服务地址 * * @return 服务地址 */ public String roundRobin() { if (PROVIDER_SERVER_LIST.isEmpty()){ throw new RuntimeException(">>> 服务提供者地址列表为空"); } int i = NUMBER_OF_REQUESTS % PROVIDER_SERVER_LIST.size(); NUMBER_OF_REQUESTS++; return PROVIDER_SERVER_LIST.get(i); }}在 CuratorService 中,我们提供了创建 Curator 客户端的方法,获取服务地址列表的方法,对父节点的子节点变化事件开启监听的方法,以及对服务的负载均衡策略的方法轮询策略。在服务消费者启动时,连接 Zookeeper 服务,获取已注册的服务地址列表,并对服务地址临时节点的父节点开启监听。监听到子节点的变化事件时,则重新获取服务地址列表。ConsumerController这里我们使用 RESTful 的风格来调用服务消费者的方法,在 service 同级创建目录 controller ,在 controller 中创建 ConsumerController 类:@RestController@RequestMapping("/consumer")public class ConsumerController { @Autowired private CuratorService curatorService; @Autowired private RestTemplate restTemplate; /** * 调用方法 * http://localhost:9090/consumer/callMethod * * @return String */ @GetMapping("/callMethod") public String callMethod() { // 轮询策略获取服务地址 String s = curatorService.roundRobin(); // 使用 RestTemplate 远程调用服务的 /provider/callMethod 方法,String.class 为返回值类型 return restTemplate.getForObject("http://" + s + "/provider/callMethod", String.class); }}我们使用了 RestTemplate 来远程调用 RESTful 风格的接口,所以我们需要把 RestTemplate 注入到 Spring IOC 容器中。RestTemplate我们在服务消费者项目的主类中注入Bean RestTemplate :package cn.cdd.zookeeper.consumer;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;import org.springframework.web.client.RestTemplate;@SpringBootApplicationpublic class ZookeeperConsumerApplication { public static void main(String[] args) { SpringApplication.run(ZookeeperConsumerApplication.class, args); } @Bean public RestTemplate restTemplate(){ return new RestTemplate(); }}controller 编写完毕后,我们就可以对我们的服务消费者进行测试了。

1.1 客户端-服务端模型:

客户端,是指发起请求的一方。也就是浏览器,或者指爬虫程序。通过发起请求,来获取想要的网页。服务端,请求的响应端,是 web 服务端。web 服务,是一个虚拟意思上的机器的概念。可以是一个计算机集群,也可以是一个软件或者程序。客户端,通过发送一个请求给服务端,然后进行等待。服务端按照客户端的请求,返回客户端需要的数据。这个过程,我们称之为经典的客户端——服务端模型。

2. 什么是服务监控平台

Hystrix 中的服务监控平台,就是对微服务项目进行监控的平台,包括服务运行的状态、服务有无宕机、服务异常信息监控等内容,为开发者和运维者提供了比较友好地界面支持,开发者和运维者可以直接通过观察服务平台界面,来判断具体微服务的状态信息,从而更好地对微服务进行控制。默认的 Hystrix 中间件已经为我们封装好了微服务监控平台,但是需要通过引入依赖的方式来使用它,接下来就让我们来看一下如何搭建该服务监控平台吧。

3.4 新增联系人

@app.route('/users', methods=['POST'])def addUser(): name = request.json['name'] phone = request.json['phone'] user = User(name, phone) users.append(user) return jsonify({'error': None});通过 POST 方法访问页面路径 /users 的处理函数是 addUser,在 RESTful 架构中,POST /users 表示新增一个联系人。在第 3 行和第 4 行,request.json 是一个字典,记录了客户端发送的 JSON 格式的参数:联系人的姓名和电话;在第 6 行和第 7 行,将新建的联系人加入到全局变量 users;最后,使用 jsonify 将 JSON 格式的数据转换为字符串,{‘error’: None} 表示操作成功。

2.1 微前端

微前端 尚处在发展时期,其核心概念和 微服务 相似。现阶段较为常用的微前端框架为 single-spa 和 qiankun,后者是基于前者实现的。该技术能做到 技术栈无关,即一个应用,能由多个不同技术的子应用构成,同时做到子应用的相互隔离,这里的隔离就可以选择采用 Web Components 实现。

3.2 Session 的状态

在 Zookeeper 的运行过程中,会话 Session 会经历各种状态的变化,从 Zookeeper 客户端与 Zookeeper 服务端开始建立连接到连接被关闭,会话的状态会经历以下几种:CONNECTING:正在连接状态,Zookeeper 客户端与 Zookeeper 服务端建立连接时的状态;CONNECTIED:已连接状态,Zookeeper 客户端与 Zookeeper 服务端完成连接的状态;RECONNECTING:正在重新连接状态,当 Zookeeper 客户端与 Zookeeper 服务端断开连接,Session 重连策略发起重新连接时的状态;RECONNECTED:已经重新连接状态,在 RECONNECTING 的基础上,完成了 Zookeeper 客户端与 Zookeeper 服务端的重新连接;CLOSE:连接关闭状态,Zookeeper 客户端与 Zookeeper 服务端断开连接的状态。

3. Zookeeper 客户端

使用 Zookeeper 客户端连接 Zookeeper 服务,我们需要使用 ./zkCli.sh 命令:# 进入 bin 文件夹cd /usr/local/zookeeper/apache-zookeeper-3.6.1-bin/bin/# 连接命令./zkCli.sh # 连接时输出信息Connecting to localhost:2181...# 出现下面这一行时,表示我们连接成功[zk: localhost:2181(CONNECTED) 0] 这里我们就可以使用上一节学习过的命令来操作节点了,我们来测试一下:# 获取根节点的子节点ls /# 输出默认的子节点 zookeeper[zookeeper]# 创建根节点的子节点 imooccreate /imooc# 输出创建成功信息Created /imooc# 创建后再次获取根节点的子节点ls /# 输出两个子节点[imooc, zookeeper]# 我们可以给节点设置数据set /imooc wiki# 然后我们再获取 imooc 节点的数据get /imooc# 输出我们设置的信息wiki# 最后我们测试一下删除命令delete /imooc# 删除后再次获取根节点的子节点ls /# 输出子节点 zookeeper,imooc 节点被删除[zookeeper]# 退出 Zookeeper 客户端命令quit通过上面的学习,我们知道了如何部署单机模式的 Zookeeper 服务,以及如何通过 Zookeeper 客户端连接 Zookeeper 服务端,来对 Znode 节点进行操作。那么 Zookeeper 是如何为我们提供服务的呢,接下来我们就来了解单机模式下的 Zookeeper 的工作流程。

6.3 更新联系人

function updateUser(button, userId){ var children = $(button).parent().children(); var name = children.eq(0).val(); var phone = children.eq(1).val(); var data = JSON.stringify({'name': name, 'phone': phone}); $.ajax({ 'url': '/users/' + userId, 'type': 'PUT', 'contentType': 'application/json', 'data': data, 'dataType': 'json', 'error': ajaxError, 'success': ajaxSuccess });}点击 “更新” 按钮后,执行函数 updateUser(button, userId),button 指向的是 “新增” 按钮,userId 是需要更新的联系人 id。在第 3 行到第 5 行,获取需要联系人的姓名和电话,使用了和 6.2 小节相同的方法,请参考 6.2 小节。在第 8 行,通过 jquery 的 ajax 函数调用后端服务,设置 url 为 ‘/users/userId’、type 为 ‘PUT’ ,表示 RESTful 架构下的更新联系人。

2.1 服务提供者

首先我们新建服务提供者项目,我们选择 Spring Initializr 来初始化 Spring Boot 项目,这是服务提供者的项目信息。pom.xml初始化完成,在 pom.xml 中加入项目所需的依赖。<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>cn.cdd</groupId> <artifactId>zookeeper-provider</artifactId> <version>0.0.1-SNAPSHOT</version> <name>zookeeper-provider</name> <description>zookeeper-providerDemo project for Spring Boot</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- curator 客户端 --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>5.1.0</version> </dependency> <!-- curator 客户端 --> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>5.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>依赖导入完成后,我们在 application.properties 配置文件中加入端口的配置。application.propertiesserver.port=8090接下来开始编写服务提供者的接口。ProviderService我们在 Spring Boot 主类的同级新建 service 目录,在 service 目录中新建 ProviderService 类。package cn.cdd.zookeeper.provider.service;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service;import java.net.InetAddress;import java.net.UnknownHostException;@Servicepublic class ProviderService { @Value("${server.port}") private String port; public String callMethod(){ try { return "调用了服务提供者 " + InetAddress.getLocalHost().getHostAddress() + ":" + port + " 的方法"; } catch (UnknownHostException e) { e.printStackTrace(); } return null; }}接下来编写使用 Curator 连接 Zookeeper 服务的代码。CuratorService在 service 目录下新建 CuratorService 类:@Componentpublic class CuratorService implements ApplicationRunner { @Value("${server.port}") private String port; // CuratorFramework 客户端 private static CuratorFramework client; // 服务地址临时节点的父节点 private static final String PROVIDER_NODE = "/imooc/provider"; // 服务地址临时节点的全路径 private static String PROVIDER_ADDRESS; // 服务 ip private static String PROVIDER_IP; @Override public void run(ApplicationArguments args) throws Exception { // 获取客户端,连接 Zookeeper 服务 buildCuratorClient(); // 获取本机 IP PROVIDER_IP = InetAddress.getLocalHost().getHostAddress(); // 注册本机地址到 Zookeeper registeredAddress(); } /** * 构建 CuratorFramework 客户端,并开启会话 */ private void buildCuratorClient() { // 使用 CuratorFrameworkFactory 构建 CuratorFramework client = CuratorFrameworkFactory.builder() .sessionTimeoutMs(10000) // Zookeeper 地址 .connectString("127.0.0.1:2181") // 重连策略 .retryPolicy(new RetryForever(10000)) .build(); // 开启会话 client.start(); System.out.println(">>> 服务提供者连接 Zookeeper "); } /** * 注册服务地址 */ public String registeredAddress() { String address = null; try { Stat stat = client.checkExists().forPath(PROVIDER_NODE); if (stat == null) { client.create().creatingParentsIfNeeded().forPath(PROVIDER_NODE); } // 获取本机地址 address = PROVIDER_IP + ":" + port; // 创建临时节点 /imooc/provider/192.168.0.106:8090 PROVIDER_ADDRESS = client.create() .withMode(CreateMode.EPHEMERAL) .forPath(PROVIDER_NODE + "/" + address); } catch (Exception e) { e.printStackTrace(); } System.out.println(">>> 本服务已上线"); return ">>> 服务提供者 " + address + " 已上线"; } /** * 注销服务地址 */ public String deregistrationAddress() { String address = null; try { Stat stat = client.checkExists().forPath(PROVIDER_ADDRESS); if (stat != null) { client.delete().forPath(PROVIDER_ADDRESS); } // 获取本机地址 address = PROVIDER_IP + ":" + port; } catch (Exception e) { e.printStackTrace(); } System.out.println(">>> 本服务已下线"); return ">>> 服务提供者 " + address + " 已下线"; }}在 CuratorService 类中,我们提供了创建 Curator 客户端的方法,注册服务地址的方法以及注销服务地址的方法。在该服务启动时,就会自动连接 Zookeeper 服务,并且把自身的地址信息注册到 Zookeeper 的临时节点上。ProviderController这里我们使用 RESTful 的风格编写服务提供者对外的接口,在 service 目录同级创建 controller 目录,在 controller 中创建 ProviderController 。@RestController@RequestMapping("/provider")public class ProviderController { @Value("${server.port}") private String port; @Autowired private CuratorService curatorService; @Autowired private ProviderService providerService; /** * 调用方法 * http://localhost:8090/provider/callMethod * * @return String */ @GetMapping("/callMethod") public String callMethod() { return providerService.callMethod(); } /** * 上线服务 * http://localhost:8090/provider/online * * @return String */ @GetMapping("/online") public String registeredAddress() { return curatorService.registeredAddress(); } /** * 下线服务 * http://localhost:8090/provider/offline * * @return String */ @GetMapping("/offline") public String deregistrationAddress() { return curatorService.deregistrationAddress(); }}controller 编写完毕后,我们就可以对我们的服务提供者进行测试了。

2. 需求分析

业务场景: 模拟微信聊天,每个客户端和服务端建立连接,并且可以实现点对点通信(单聊),点对多点通信(群聊)。设计思路: 我们要实现的是点(客户端)对点(客户端)的通讯,但是我们大部分情况下接触的业务都是客户端和服务端之间的通讯,客户端只需要知道服务端的 IP 地址和端口号即可发起通讯了,那么客户端和客户端应该怎么去设计呢?思考:难道是手机和手机之间建立通讯连接,互相发送消息吗?这种方案显然不是很好的方案,第一: 客户端和客户端之间通讯,首先需要确定对方的 IP 地址和端口号,显然不是很现实。第二: 即使有办法拿到对方的 IP 地址和端口号,那么每个点(客户端)既作为服务端还得作为客户端,无形之中增加了客户端的压力。其实,我们可以使用服务端作为中转站,由服务端主动往指定客户端推送消息,如果是这种模式的话,那么 Http 协议是无法支持的,Http 是无状态的,只能一请求一响应的模式,只能使用 TCP 协议去实现了。

4.2 新增联系人

<body><h1>通讯录</h1><div class="row"> <input type="text" placeholder='姓名'> <input type="text" placeholder='电话'> <span class="button" onclick="addUser(this);">增加</span></div>新增联系人的界面包含 3 个部分:一个文本字段用于填写姓名;一个文本字段用于填写电话;一个按钮,用于增加联系人,设置按钮的 onclick 函数,点击按钮时执行函数 addUser(this),其中 this 指向按钮对应的 DOM 元素。

3.1 四字命令介绍

这里我们列出常用的四字命令进行介绍:conf: 查询 Zookeeper 服务的配置信息。# 对客户端开放的端口,默认 2181clientPort=2181# 安全的客户端的端口secureClientPort=-1# 数据文件目录dataDir=/usr/local/zookeeper/apache-zookeeper-3.6.1-bin/data/version-2# 数据文件大小dataDirSize=67108880# 日志文件目录dataLogDir=/usr/local/zookeeper/apache-zookeeper-3.6.1-bin/data/log/version-2# 日志文件大小dataLogSize=914# 心跳检测间隔毫秒tickTime=2000# 最大客户端连接数maxClientCnxns=60# 最小的会话超时时间minSessionTimeout=4000# 最大的会话超时时间maxSessionTimeout=40000# 客户端端口列表备份日志clientPortListenBacklog=-1# 服务idserverId=0cons: 列出连接到 Zookeeper 服务的所有客户端的完整连接和会话详细信息。包括接收和发送的数据包数量、会话id、操作延迟、最后执行的操作等信息。/127.0.0.1:44244[0](queued=0,recved=1,sent=0)crst: 重置服务端的连接和会话统计信息。Connection stats reset.dump: 适用于 Leader 节点,列出未完成的请求和临时节点。envi: 列出服务器的环境信息。Environment:zookeeper.version=3.6.1--104dcb3e3fb464b30c5186d229e00af9f332524b, built on 04/21/2020 15:01 GMThost.name=fbbc740a6217java.version=1.8.0_261java.vendor=Oracle Corporationjava.home=/usr/local/java/jdk1.8.0_261/jrejava.class.path=/usr/local/java/jdk1.8.0_261/jre/libjava.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/libjava.io.tmpdir=/tmpjava.compiler=<NA>os.name=Linuxos.arch=amd64os.version=4.19.128-microsoft-standarduser.name=rootuser.home=/rootuser.dir=/usr/local/zookeeper/apache-zookeeper-3.6.1-binos.memory.free=142MBos.memory.max=889MBos.memory.total=192MBruok: 测试服务是否处于正确运行状态,如果正常返回 imok,否则返回空。srst: 重置服务的统计信息。srvr: 列出服务的详细信息。Zookeeper version: 3.6.1--104dcb3e3fb464b30c5186d229e00af9f332524b, built on 04/21/2020 15:01 GMTLatency min/avg/max: 0/0.0/0Received: 9Sent: 8Connections: 1Outstanding: 0Zxid: 0x2Mode: standaloneNode count: 5wchs: 列出服务的 Watcher 的简要信息。wchc: 按会话列出服务的 Watcher 的详细信息。wchp: 按路径列出服务带有 znode 列表的 Watcher 的详细信息。如果 Watcher 的数量多,会影响服务器性能,请谨慎使用。dirs: 以字节为单位显示快照和日志文件的总大小。datadir_size: 67108880logdir_size: 914

首页上一页1234567下一页尾页
直播
查看课程详情
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号