鸿蒙HarmonyOS编程开发:TLS单向认证通讯示例

1.TLS简介

TLS(Transport Layer Security)协议的前身是SSL(Secure Socket Layer)安全套接层协议,由Netscape公司于1994年提出,是一套网络通信安全协议。IETF(The Internet Engineering Task Force)后期负责SSL协议,并且重新命名为TLS协议。IETF于1999年发布了TLS 1.0版本,该版本基于SSL 3.0;2006年4月,发布了TLS 1.1版本,2008年8月,发布了TLS 1.2版本,2018年3月,TLS 1.3版本发布,是目前最新的TLS版本。

2. TLS的常用方法

鸿蒙封装的TLS操作类位于模块socket中,使用如下的方式导入:

import socket from '@ohos.net.socket';

        socket模块包括了众多的TCP操作方法,就本文而言,重点需要掌握的是如下五个:

1)constructTLSSocketInstance(): TLSSocket

创建并返回一个TLSSocket对象,,在使用TLSSocket的方法以前需要创建该对象。

2)bind(address: NetAddress): Promise<void>

绑定IP地址和端口,端口可以指定或由系统随机分配,可以使用0.0.0.0表示本机IP地址;使用Promise方式作为异步方法。

3)connect(options: TLSConnectOptions): Promise<void>

连接到指定的TLS服务端,参数options包含了连接的地址address、TLS安全配置secureOptions以及ALPN协议列表ALPNProtocols,其中address和secureOptions是必选的,ALPN是可选的,使用promise方法作为异步方法。

4)send(data: string): Promise<void>

通过TLSSocket连接向服务端发送消息data,使用Promise方式作为异步方法。

5)on(type: 'message', callback: Callback<{message: ArrayBuffer, remoteInfo: SocketRemoteInfo}>): void

订阅TLSSocket连接的接收消息事件,当套接字接收到消息时触发该事件,其中message表示接收到的消息,remoteInfo是发送方信息;使用callback方式作为异步方法。

3. TLS单向认证通讯示例

为演示TLS安全通讯单向认证的方式(即客户端认证服务端,客户端本身不提供证书),本示例实现了使用TLS协议发送、接收消息的功能,运行后的初始界面如下所示:

cke_115807.jpeg

本示例中,可以配置TLS服务端的地址,可以直接输入服务端证书的CA信息,或者从文件加载,在配置好CA后,就可以连接服务端了,连接握手成功后,就可以发送信息给对方。

下面详细介绍创建该应用的步骤。

步骤1:创建Empty Ability项目。

步骤2:在module.json5配置文件加上对权限的声明:

"requestPermissions": [

      {

        "name": "ohos.permission.INTERNET"

      },

      {

        "name": "ohos.permission.GET_WIFI_INFO"

      }

    ]

这里分别添加了访问互联网和访问WIFI信息的权限。

步骤3:在Index.ets文件里添加如下的代码:

import socket from '@ohos.net.socket';
import wifiManager from '@ohos.wifiManager';
import systemDateTime from '@ohos.systemDateTime';
import util from '@ohos.util';
import picker from '@ohos.file.picker';
import fs from '@ohos.file.fs';
import common from '@ohos.app.ability.common';//执行TLS通讯的对象
let tlsSocket = socket.constructTLSSocketInstance()//说明:本地的IP地址不是必须知道的,绑定时绑定到IP:0.0.0.0即可,显示本地IP地址的目的是方便对方发送信息过来
//本地IP的数值形式
let ipNum = wifiManager.getIpInfo().ipAddress
//本地IP的字符串形式
let localIp = (ipNum >>> 24) + '.' + (ipNum >> 16 & 0xFF) + '.' + (ipNum >> 8 & 0xFF) + '.' + (ipNum & 0xFF);let caFileUri = ''@Entry
@Component
struct Index {//连接、通讯历史记录@State msgHistory: string = ''//要发送的信息@State sendMsg: string = ''//服务端IP地址@State serverIp: string = "0.0.0.0"//服务端端口@State serverPort: number = 9999//是否可以加载@State canLoad: boolean = false//是否可以连接@State canConnect: boolean = false//是否可以发送消息@State canSend: boolean = false@State ca: string = ``scroller: Scroller = new Scroller()build() {Row() {Column() {Text("TLS通讯示例").fontSize(14).fontWeight(FontWeight.Bold).width('100%').textAlign(TextAlign.Center).padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text("本地IP地址:").width(100).fontSize(14).flexGrow(0)Text(localIp).width(110).fontSize(12).flexGrow(1)}.width('100%').padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text("服务端地址:").fontSize(14).width(90).flexGrow(1)TextInput({ text: this.serverIp }).onChange((value) => {this.serverIp = value}).width(110).fontSize(12).flexGrow(4)Text(":").width(5).flexGrow(0)TextInput({ text: this.serverPort.toString() }).type(InputType.Number).onChange((value) => {this.serverPort = parseInt(value)}).fontSize(12).flexGrow(2).width(50)}.width('100%').padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text("CA(输入或者加载)").fontSize(14).width(90).flexGrow(1)Button("选择").onClick(() => {this.selectCA()}).width(70).fontSize(14).flexGrow(0)Button("加载").onClick(() => {this.loadCA()}).enabled(this.canLoad).width(70).fontSize(14).flexGrow(0)Button("连接").onClick(() => {this.connect2Server()}).enabled(this.canConnect).width(70).fontSize(14).flexGrow(0)}.width('100%').padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {TextArea({ text: this.ca }).onChange((value) => {this.ca = value}).flexGrow(1).height(200)}.width('100%').padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {TextInput({ placeholder: "输入要发送的消息" }).onChange((value) => {this.sendMsg = value}).width(200).flexGrow(1)Button("发送").enabled(this.canSend).width(70).fontSize(14).flexGrow(0).onClick(() => {this.sendMsg2Server()})}.width('100%').padding(10)Scroll(this.scroller) {Text(this.msgHistory).textAlign(TextAlign.Start).padding(10).width('100%').backgroundColor(0xeeeeee)}.align(Alignment.Top).backgroundColor(0xeeeeee).height(300).flexGrow(1).scrollable(ScrollDirection.Vertical).scrollBar(BarState.On).scrollBarWidth(20)}.width('100%').justifyContent(FlexAlign.Start).height('100%')}.height('100%')}//发送消息到服务端sendMsg2Server() {tlsSocket.send(this.sendMsg + "\r\n").then(async () => {this.msgHistory += "我:" + this.sendMsg + await getCurrentTimeString() + "\r\n"}).catch((e) => {this.msgHistory += '发送失败' + e.message + "\r\n";})}//绑定本地地址async bind2LocalAddress() {//本地地址let localAddress = { address: "0.0.0.0", family: 1 }await tlsSocket.bind(localAddress).then(() => {this.msgHistory = 'bind success' + "\r\n";}).catch((e) => {this.msgHistory = 'bind fail ' + e.message + "\r\n";})//收到消息时的处理tlsSocket.off("message")tlsSocket.on("message", async (value) => {let msg = buf2String(value.message)let time = await getCurrentTimeString()this.msgHistory += "服务端:" + msg + time + "\r\n"this.scroller.scrollEdge(Edge.Bottom)})}//选择CA证书文件selectCA() {let documentPicker = new picker.DocumentViewPicker();documentPicker.select().then((result) => {if (result.length > 0) {caFileUri = result[0]this.msgHistory += "select file: " + caFileUri + "\r\n";this.canLoad = true}}).catch((e) => {this.msgHistory += 'DocumentViewPicker.select failed ' + e.message + "\r\n";});}//加载CA文件内容loadCA() {try {let buf = new ArrayBuffer(1024 * 4);let file = fs.openSync(caFileUri, fs.OpenMode.READ_ONLY);let readLen = fs.readSync(file.fd, buf, { offset: 0 });this.ca = buf2String(buf.slice(0, readLen))this.canConnect = truefs.closeSync(file);}catch (e) {this.msgHistory += 'readText failed ' + e.message + "\r\n";}}//连接服务端connect2Server() {//绑定本地地址this.bind2LocalAddress()//服务端地址let serverAddress = { address: this.serverIp, port: this.serverPort, family: 1 }let opt: socket.TLSSecureOptions = {ca: [this.ca]}tlsSocket.connect({ address: serverAddress, secureOptions: opt }).then(() => {this.msgHistory = 'connect success ' + "\r\n";this.canSend = true}).catch((e) => {this.msgHistory = 'connect fail ' + e.message + "\r\n";})}
}//同步获取当前时间的字符串形式
async function getCurrentTimeString() {let time = ""await systemDateTime.getDate().then((date) => {time = date.getHours().toString() + ":" + date.getMinutes().toString()+ ":" + date.getSeconds().toString()})return "[" + time + "]"
}//ArrayBuffer转utf8字符串
function buf2String(buf: ArrayBuffer) {let msgArray = new Uint8Array(buf);let textDecoder = util.TextDecoder.create("utf-8");return textDecoder.decodeWithStream(msgArray)
}复制

步骤4:编译运行,可以使用模拟器或者真机。

步骤5:配置CA信息,单击“选择”按钮选择CA证书,如图所示:

cke_654546.jpeg

步骤6:单击“加载”按钮加载CA证书,如图所示:

cke_679681.jpeg

步骤7:配置服务端地址,当前,前提是要运行一个TLS服务端,具体的服务端可以使用别的语言编写,或者使用更高版本的鸿蒙API编写,本例假定使用一个基于TLS的回声服务器,配置好后,单击“连接”按钮即可开始连接服务端。连接成功后,如果在服务端监听,可以看到如下的连接过程信息:

cke_1097373.jpg

步骤8:输入要发送的信息,单击“发送”按钮即可发送信息到服务端,如下图所示:

cke_1338959.jpeg

如果监听发送接收消息,可以看到Application Data的发送过程:

cke_1424014.jpg

通过上面的过程可知,在经过成功的握手后,消息发送接收都是基于密文的,达到了保密的目的。

这样就完成了一个简单的TLS单向认证消息发送应用。

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为资料太多,太杂,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

为了确保高效学习,建议规划清晰的学习路线,涵盖以下关键阶段:

  →【纯血版鸿蒙全套最新学习资料】希望这一份鸿蒙学习资料能够给大家带来帮助~


 鸿蒙(HarmonyOS NEXT)最新学习路线

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.视频学习资料+学习PDF文档

HarmonyOS Next 最新全套视频教程

  纯血版鸿蒙全套学习资料(面试、文档、全套视频等)              

​​

总结

参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端开发中的大屏布局方案:使用 rem 单位与动态设置 html 的 font-size

使用 rem 单位与动态设置 html 的 font-size 前言 随着设备尺寸的多样化&#xff0c;网页需要能够在不同大小的屏幕上提供良好的用户体验。传统的布局方式&#xff08;如使用 px&#xff09;在不同分辨率下可能会导致布局失真。为了解决这个问题&#xff0c;我们可以通过动态…

【UE5】基于摄像机距离逐渐剔除角色

效果 步骤 1. 新建一个工程&#xff0c;在内容浏览器中添加第三人称游戏内容包 2. 找到第三人称角色的材质实例“MI_Quinn_01”并打开 找到材质实例的父项材质“M_Mannequin” 打开材质“M_Mannequin” 在材质图表中添加如下节点 此时运行效果如文章开头所示。 参考视频&#…

flutter 中 ssl 双向证书校验

SSL 证书&#xff1a; 在处理 https 请求的时候&#xff0c;通常可以使用 中间人攻击的方式 获取 https 请求以及响应参数。应为通常我们是 SSL 单向认证&#xff0c;服务器并没有验证我们的客户端的证书。为了防止这种中间人攻击的情况。我么可以通过 ssl 双向认证的方式。即…

创意无限,尽在掌握:热门视频剪辑软件一览

我们记录生活、分享故事、传播信息用视频的频率越来越高了。而这些视频往往都是通过剪辑之后才能展示出当前的效果。那这次我们就来探索剪辑视频的时候都会用到什么工具吧。 1.福昕视频剪辑 连接直达>>https://www.pdf365.cn/foxit-clip/ 这是一款专为追求高效与创意…

【React】为什么Hooks不能出现在判断中

前言 在 React 中&#xff0c;Hooks 不能写在条件语句中&#xff0c;如下面这段代码点击button后则会报错。 import { useEffect, useState } from "react"export default () > {const [count, setCount] useState(0)if (count > 0) {useEffect(() > {co…

2-74 基于matlab的图像k-means聚类GUI

基于matlab的图像k-means聚类GUI&#xff0c;可对彩色图像进行Kmeans和meanshift进行聚类分析&#xff0c;生成最后的聚类图像以及聚类中心的迭代轨迹。程序已调通&#xff0c;可直接运行。 2-74 matlab GUI - 小红书 (xiaohongshu.com)

iOS 通知

iOS 通知分为本地推送和远程推送两类 一. 本地推送使用流程 1. 注册通知 //请求通知权限 UNUserNotificationCenter *center [UNUserNotificationCenter currentNotificationCenter];[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizati…

Java方法的使用

目录 一&#xff1a;方法概念及使用 1.1什么是方法 1.2 方法定义 1.3 方法调用的执行过程 1.4 实参和形参的关系(重要) 1.5 没有返回值的方法 二&#xff1a;方法重载 2.1 为什么需要方法重载 2.2 方法重载概念 2.3 方法签名 三. 递归 3.1递归的概念 3.2 递归执行过…

Unity 资源 之 Photon Inventory 2 (Game Creator 2)

免费获取资源&#xff1a; 有2种方式可免费获取资源&#xff1a; 在后台回复**“UnityAssetStore**“ 或 ”Unity资源”。在Unity官方地址&#xff1a;https://assetstore.unity.com/publisher-sale &#xff0c;兑换码&#xff1a;NINJUTSUGAMES 【本周限定】 关注我每周&a…

配置PXE预启动执行环境:Kickstart自动化无人值守安装

文章目录 实现 Kickstart 无人值守安装1. 安装Kickstart和配置应答文件&#xff08;图形化界面&#xff09;2. 配置 PXE 菜单支持 Kickstart 无人值守安装3. 验证 Kickstart 无人值守安装4. 拓展&#xff1a;命令行配置应答文件&#xff08;命令行界面&#xff09; 实现 Kickst…

校友会系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;校友管理&#xff0c;生活模块管理&#xff0c;兼职信息管理&#xff0c;表白墙管理&#xff0c;我的收藏管理&#xff0c;校友论坛&#xff0c;系统管理 微信端账号功能包括&…

如何用3个月零基础入门网络安全?_网络安全零基础怎么学习

前 言 写这篇教程的初衷是很多朋友都想了解如何入门/转行网络安全&#xff0c;实现自己的“黑客梦”。文章的宗旨是&#xff1a; 1.指出一些自学的误区 2.提供客观可行的学习表 3.推荐我认为适合小白学习的资源.大佬绕道哈&#xff01; →点击获取网络安全资料攻略← 一、自学…

【图形学】TA之路-基于Unity Shader编程之初体验

学习shader之前你必须知道的事情&#xff1a; Unity开发引擎、Direct3D、Shader他们之间的关系 Direct3D 是一个底层图形 API&#xff0c;它直接与 GPU &#xff08;显卡&#xff09;交互&#xff0c;提供了访问硬件加速功能的接口。Unity 开发引擎&#xff0c;它封装了很多底…

Python酷库之旅-第三方库Pandas(094)

目录 一、用法精讲 401、pandas.Series.to_string方法 401-1、语法 401-2、参数 401-3、功能 401-4、返回值 401-5、说明 401-6、用法 401-6-1、数据准备 401-6-2、代码示例 401-6-3、结果输出 402、pandas.Series.to_clipboard方法 402-1、语法 402-2、参数 40…

⼆⼿⻋交易系统架构分析

二手车交易系统架构分析涉及多个层面&#xff0c;包括技术选型、系统模块、数据库设计、用户界面及安全性等。以下是对二手车交易系统架构的综合分析&#xff1a; 技术选型&#xff1a;系统通常采用B/S架构模式&#xff0c;前后端分离&#xff0c;前端使用微信小程序开发工具&…

搭建自己的金融数据源和量化分析平台(七):定时更新上市公司所属行业门类及大类

0x00 前言 由于此前从深交所下载的股票信息中只有行业门类信息&#xff0c;没有行业大类信息&#xff0c;导致后续解析三大报表和量化选股的时候无法进行&#xff1a; 可以看到深交所的股票是没有大类信息的。 再看看上交所的保险股&#xff1a; 因此需要将深交所股票的所属…

Spring + Boot + Cloud + JDK8 + Elasticsearch 单节点 模式下实现全文检索高亮-分页显示 快速入门案例

1. 安装elasticsearchik分词器插件 sudo wget https://release.infinilabs.com/analysis-ik/stable/elasticsearch-analysis-ik-8.13.4.zip sudo mkdir -p ./es_plugins/analysis-ik sudo mkdir ./es_data sudo unzip elasticsearch-analysis-ik-8.13.4.zip -d ./es_plugins/a…

市盈率的概念

写篇有关市盈率的【不务正业】的内容。 重要公式 市盈率 官方的定义 平均市盈率&#xff1d;∑(收盘价发行数量)/∑(每股收益发行数量)&#xff0c;统计时剔除亏损及暂停上市的上市公司。 静态市盈率 滚动市盈率&#xff08;TTM&#xff09; 股票市盈率的意义 如果某股票有较…

海运整箱成本与拼箱成本对比 | 国际贸易服务平台 | 箱讯科技

整箱和拼箱 在集装箱运输业务中&#xff0c;我们把一个集装箱、一个出口人、一个收货人、一个目的港&#xff0c;满足这“四个一”条件的货物叫做整箱货&#xff0c;而把一个集装箱、出口人、收货人和目的港这三项之中只要有一项是在两个或两个以上的出口运输货物&#xff0c;就…

Linux网络环境搭建,开发板网线直连电脑网口,电脑WIFI上网

开发板网线直连电脑网口&#xff08;电脑自带&#xff0c;一般有PCI&#xff0c;不是USB网卡&#xff09;&#xff0c;电脑WIFI上网 因为电脑是 WiFi 上网&#xff0c;所以需要添加一个网络适配器并设置成 NAT 模式&#xff0c;供虚拟机上网。 设置双网卡&#xff0c;注意双网卡…