【鸿蒙开发】第二十三章 Network 网络服务

server/2024/12/5 2:58:45/

目录​​​​​​​

1 简介

1.1 约束与限制

2 HTTP数据请求

2.1 request 接口开发步骤 

2.2 requestInStream接口开发步骤

3 WebSocket连接

3.1 开发步骤

4 Socket 连接

4.1 Socket 连接主要场景

4.1.1 TCP/UDP Socket进行数据传输 

4.1.2 TCP Socket Server 进行数据传输

4.1.3 Multicast Socket 进行数据传输

4.1.4 Local Socket进行数据传输

4.1.5 Local Socket Server 进行数据传输

4.1.6 TLS Socket 进行加密数据传输

4.1.7 TCP Socket 升级为 TLS Socket 进行加密数据传输

4.1.8 TCP Socket 升级为 TLS Socket 进行加密数据传输

5 MDNS管理

5.1 管理本地服务 

5.2 发现本地服务


1 简介

Network Kit(网络服务)主要提供以下功能:

  • HTTP数据请求:通过HTTP发起一个数据请求。
  • WebSocket连接:使用WebSocket建立服务器与客户端的双向连接。
  • Socket连接:通过Socket进行数据传输。
  • 网络连接管理:网络连接管理提供管理网络一些基础能力,包括WiFi/蜂窝/Ethernet等多网络连接优先级管理、网络质量评估、订阅默认/指定网络连接状态变化、查询网络连接信息、DNS解析等功能。
  • MDNS管理:MDNS即多播DNS(Multicast DNS),提供局域网内的本地服务添加、移除、发现、解析等能力。

1.1 约束与限制

使用网络管理模块的相关功能时,需要请求相应的权限。
在申请权限前,请保证符合权限使用的基本原则。然后参考访问控制-声明权限声明对应权限

权限名说明
ohos.permission.GET_NETWORK_INFO获取网络连接信息。
ohos.permission.INTERNET允许程序打开网络套接字,进行网络连接。

2 HTTP数据请求

通过HTTP发起数据请求,支持常见的GETPOSTOPTIONSHEADPUTDELETETRACECONNECT方法。
HTTP数据请求功能主要由http模块提供。
使用该功能需要申请ohos.permission.INTERNET权限。

接口名描述
createHttp()创建一个http请求。
request()根据URL地址,发起HTTP网络请求。
requestInStream()根据URL地址,发起HTTP网络请求并返回流式响应。
destroy()中断请求任务。
on(type: ‘headersReceive’)订阅HTTP Response Header 事件。
off(type: ‘headersReceive’)取消订阅HTTP Response Header 事件。
once(‘headersReceive’)订阅HTTP Response Header 事件,但是只触发一次。
on(‘dataReceive’)订阅HTTP流式响应数据接收事件。
off(‘dataReceive’)取消订阅HTTP流式响应数据接收事件。
on(‘dataEnd’)订阅HTTP流式响应数据接收完毕事件。
off(‘dataEnd’)取消订阅HTTP流式响应数据接收完毕事件。
on(‘dataReceiveProgress’)订阅HTTP流式响应数据接收进度事件。
off(‘dataReceiveProgress’)取消订阅HTTP流式响应数据接收进度事件。
on(‘dataSendProgress’)订阅HTTP网络请求数据发送进度事件。
off(‘dataSendProgress’)取消订阅HTTP网络请求数据发送进度事件。

2.1 request 接口开发步骤 

  1. 从@kit.NetworkKit中导入http命名空间。
  2. 调用createHttp()方法,创建一个HttpRequest对象。
  3. 调用该对象的on()方法,订阅http响应头事件,此接口会比request请求先返回。可以根据业务需要订阅此消息。
  4. 调用该对象的request()方法,传入http请求的url地址和可选参数,发起网络请求。
  5. 按照实际业务需要,解析返回结果。
  6. 调用该对象的off()方法,取消订阅http响应头事件。
  7. 当该请求使用完毕时,调用destroy()方法主动销毁。
// 引入包名
import { http } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';// 每一个httpRequest对应一个HTTP请求任务,不可复用
let httpRequest = http.createHttp();
// 用于订阅HTTP响应头,此接口会比request请求先返回。可以根据业务需要订阅此消息
// 从API 8开始,使用on('headersReceive', Callback)替代on('headerReceive', AsyncCallback)。 8+
httpRequest.on('headersReceive', (header) => {console.info('header: ' + JSON.stringify(header));
});
httpRequest.request(// 填写HTTP请求的URL地址,可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定"EXAMPLE_URL",{method: http.RequestMethod.POST, // 可选,默认为http.RequestMethod.GET// 开发者根据自身业务需要添加header字段header: {'Content-Type': 'application/json'},// 当使用POST请求时此字段用于传递请求体内容,具体格式与服务端协商确定extraData: "data to send",expectDataType: http.HttpDataType.STRING, // 可选,指定返回数据的类型usingCache: true, // 可选,默认为truepriority: 1, // 可选,默认为1connectTimeout: 60000, // 可选,默认为60000msreadTimeout: 60000, // 可选,默认为60000msusingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定usingProxy: false, // 可选,默认不使用网络代理,自API 10开始支持该属性caPath:'/path/to/cacert.pem', // 可选,默认使用系统预制证书,自API 10开始支持该属性clientCert: { // 可选,默认不使用客户端证书,自API 11开始支持该属性certPath: '/path/to/client.pem', // 默认不使用客户端证书,自API 11开始支持该属性keyPath: '/path/to/client.key', // 若证书包含Key信息,传入空字符串,自API 11开始支持该属性certType: http.CertType.PEM, // 可选,默认使用PEM,自API 11开始支持该属性keyPassword: "passwordToKey" // 可选,输入key文件的密码,自API 11开始支持该属性},multiFormDataList: [ // 可选,仅当Header中,'content-Type'为'multipart/form-data'时生效,自API 11开始支持该属性{name: "Part1", // 数据名,自API 11开始支持该属性contentType: 'text/plain', // 数据类型,自API 11开始支持该属性data: 'Example data', // 可选,数据内容,自API 11开始支持该属性remoteFileName: 'example.txt' // 可选,自API 11开始支持该属性}, {name: "Part2", // 数据名,自API 11开始支持该属性contentType: 'text/plain', // 数据类型,自API 11开始支持该属性// data/app/el2/100/base/com.example.myapplication/haps/entry/files/fileName.txtfilePath: `${getContext(this).filesDir}/fileName.txt`, // 可选,传入文件路径,自API 11开始支持该属性remoteFileName: 'fileName.txt' // 可选,自API 11开始支持该属性}]}, (err: BusinessError, data: http.HttpResponse) => {if (!err) {// data.result为HTTP响应内容,可根据业务需要进行解析console.info('Result:' + JSON.stringify(data.result));console.info('code:' + JSON.stringify(data.responseCode));// data.header为HTTP响应头,可根据业务需要进行解析console.info('header:' + JSON.stringify(data.header));console.info('cookies:' + JSON.stringify(data.cookies)); // 8+// 当该请求使用完毕时,调用destroy方法主动销毁httpRequest.destroy();} else {console.error('error:' + JSON.stringify(err));// 取消订阅HTTP响应头事件httpRequest.off('headersReceive');// 当该请求使用完毕时,调用destroy方法主动销毁httpRequest.destroy();}}
);

2.2 requestInStream接口开发步骤

  1. 从@kit.NetworkKit中导入http命名空间。
  2. 调用createHttp()方法,创建一个HttpRequest对象。
  3. 调用该对象的on()方法,可以根据业务需要订阅HTTP响应头事件、HTTP流式响应数据接收事件、HTTP流式响应数据接收进度事件和HTTP流式响应数据接收完毕事件。
  4. 调用该对象的requestInStream()方法,传入http请求的url地址和可选参数,发起网络请求。
  5. 按照实际业务需要,可以解析返回的响应码。
  6. 调用该对象的off()方法,取消订阅响应事件。
  7. 当该请求使用完毕时,调用destroy()方法主动销毁。
// 引入包名
// 引入包名
import { http } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';// 每一个httpRequest对应一个HTTP请求任务,不可复用
let httpRequest = http.createHttp();
// 用于订阅HTTP响应头事件
httpRequest.on('headersReceive', (header: Object) => {console.info('header: ' + JSON.stringify(header));
});
// 用于订阅HTTP流式响应数据接收事件
let res = new ArrayBuffer(0);
httpRequest.on('dataReceive', (data: ArrayBuffer) => {const newRes = new ArrayBuffer(res.byteLength + data.byteLength);const resView = new Uint8Array(newRes);resView.set(new Uint8Array(res));resView.set(new Uint8Array(data), res.byteLength);res = newRes;console.info('res length: ' + res.byteLength);
});
// 用于订阅HTTP流式响应数据接收完毕事件
httpRequest.on('dataEnd', () => {console.info('No more data in response, data receive end');
});
// 用于订阅HTTP流式响应数据接收进度事件
class Data {receiveSize: number = 0;totalSize: number = 0;
}
httpRequest.on('dataReceiveProgress', (data: Data) => {console.log("dataReceiveProgress receiveSize:" + data.receiveSize + ", totalSize:" + data.totalSize);
});let streamInfo: http.HttpRequestOptions = {method: http.RequestMethod.POST,  // 可选,默认为http.RequestMethod.GET// 开发者根据自身业务需要添加header字段header: {'Content-Type': 'application/json'},// 当使用POST请求时此字段用于传递请求体内容,具体格式与服务端协商确定extraData: "data to send",expectDataType:  http.HttpDataType.STRING,// 可选,指定返回数据的类型usingCache: true, // 可选,默认为truepriority: 1, // 可选,默认为1connectTimeout: 60000, // 可选,默认为60000msreadTimeout: 60000, // 可选,默认为60000ms。若传输的数据较大,需要较长的时间,建议增大该参数以保证数据传输正常终止usingProtocol: http.HttpProtocol.HTTP1_1 // 可选,协议类型默认值由系统自动指定
}// 填写HTTP请求的URL地址,可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定
httpRequest.requestInStream("EXAMPLE_URL", streamInfo).then((data: number) => {console.info("requestInStream OK!");console.info('ResponseCode :' + JSON.stringify(data));// 取消订阅HTTP响应头事件httpRequest.off('headersReceive');// 取消订阅HTTP流式响应数据接收事件httpRequest.off('dataReceive');// 取消订阅HTTP流式响应数据接收进度事件httpRequest.off('dataReceiveProgress');// 取消订阅HTTP流式响应数据接收完毕事件httpRequest.off('dataEnd');// 当该请求使用完毕时,调用destroy方法主动销毁httpRequest.destroy();
}).catch((err: Error) => {console.info("requestInStream ERROR : err = " + JSON.stringify(err));
});

3 WebSocket连接

使用WebSocket建立服务器与客户端的双向连接,流程如下:

  1. 需要先通过createWebSocket()方法创建WebSocket对象,
  2. 然后通过connect()方法连接到服务器。
  3. 当连接成功后,客户端会收到open事件的回调,之后客户端就可以通过send()方法与服务器进行通信。
  4. 当服务器发信息给客户端时,客户端会收到message事件的回调。
  5. 当客户端不要此连接时,可以通过调用close()方法主动断开连接,
  6. 之后客户端会收到close事件的回调。

若在上述任一过程中发生错误,客户端会收到error事件的回调。

WebSocket连接功能主要由webSocket模块提供。使用该功能需要申请ohos.permission.INTERNET权限。具体接口说明如下表。

接口名描述
createWebSocket()创建一个WebSocket连接。
connect()根据URL地址,建立一个WebSocket连接。
send()通过WebSocket连接发送数据。
close()关闭WebSocket连接。
on(type: ‘open’)订阅WebSocket的打开事件。
off(type: ‘open’)取消订阅WebSocket的打开事件。
on(type: ‘message’)订阅WebSocket的接收到服务器消息事件。
off(type: ‘message’)取消订阅WebSocket的接收到服务器消息事件。
on(type: ‘close’)订阅WebSocket的关闭事件。
off(type: ‘close’)取消订阅WebSocket的关闭事件
on(type: ‘error’)订阅WebSocket的Error事件。
off(type: ‘error’)取消订阅WebSocket的Error事件。

3.1 开发步骤

  1. 导入需要的webSocket模块
  2. 创建一个WebSocket连接,返回一个WebSocket对象。
  3. (可选)订阅WebSocket的打开、消息接收、关闭、Error事件。
  4. 根据URL地址,发起WebSocket连接。
  5. 使用完WebSocket连接之后,主动断开连接。
import { webSocket } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';let defaultIpAddress = "ws://";
let ws = webSocket.createWebSocket();
ws.on('open', (err: BusinessError, value: Object) => {console.log("on open, status:" + JSON.stringify(value));// 当收到on('open')事件时,可以通过send()方法与服务器进行通信ws.send("Hello, server!", (err: BusinessError, value: boolean) => {if (!err) {console.log("Message sent successfully");} else {console.log("Failed to send the message. Err:" + JSON.stringify(err));}});
});
ws.on('message', (err: BusinessError, value: string | ArrayBuffer) => {console.log("on message, message:" + value);// 当收到服务器的`bye`消息时(此消息字段仅为示意,具体字段需要与服务器协商),主动断开连接if (value === 'bye') {ws.close((err: BusinessError, value: boolean) => {if (!err) {console.log("Connection closed successfully");} else {console.log("Failed to close the connection. Err: " + JSON.stringify(err));}});}
});
ws.on('close', (err: BusinessError, value: webSocket.CloseResult) => {console.log("on close, code is " + value.code + ", reason is " + value.reason);
});
ws.on('error', (err: BusinessError) => {console.log("on error, error:" + JSON.stringify(err));
});
ws.connect(defaultIpAddress, (err: BusinessError, value: boolean) => {if (!err) {console.log("Connected successfully");} else {console.log("Connection failed. Err:" + JSON.stringify(err));}
});

4 Socket 连接

Socket 连接主要是通过 Socket 进行数据传输,支持 TCP/UDP/Multicast/TLS 协议。

  1. Socket:套接字,就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。
  2. TCP:传输控制协议(Transmission Control Protocol)。是一种面向连接的、可靠的、基于字节流的传输层通信协议。
  3. UDP:用户数据报协议(User Datagram Protocol)。是一个简单的面向消息的传输层,不需要连接。
  4. Multicast:多播,基于UDP的一种通信模式,用于实现组内所有设备之间广播形式的通信。
  5. LocalSocket:本地套接字,IPC(Inter-Process Communication)进程间通信的一种,实现设备内进程之间相互通信,无需网络。
  6. TLS:安全传输层协议(Transport Layer Security)。用于在两个通信应用程序之间提供保密性和数据完整性。

Socket 连接主要由 socket 模块提供。具体接口说明如下表。

接口名描述
constructUDPSocketInstance()创建一个 UDPSocket 对象。
constructTCPSocketInstance()创建一个 TCPSocket 对象。
constructTCPSocketServerInstance()创建一个 TCPSocketServer 对象。
constructMulticastSocketInstance()创建一个 MulticastSocket 对象。
constructLocalSocketInstance()创建一个 LocalSocket 对象。
constructLocalSocketServerInstance()创建一个 LocalSocketServer 对象。
listen()绑定、监听并启动服务,接收客户端的连接请求。(仅 TCP/LocalSocket 支持)。
bind()绑定 IP 地址和端口,或是绑定本地套接字路径。
send()发送数据。
close()关闭连接。
getState()获取 Socket 状态。
connect()连接到指定的 IP 地址和端口,或是连接到本地套接字(仅 TCP/LocalSocket 支持)。
getRemoteAddress()获取对端 Socket 地址(仅 TCP 支持,需要先调用 connect 方法)。
setExtraOptions()设置 Socket 连接的其他属性。
getExtraOptions()获取 Socket 连接的其他属性(仅 LocalSocket 支持)。
addMembership()加入到指定的多播组 IP 中 (仅 Multicast 支持)。
dropMembership()从指定的多播组 IP 中退出 (仅 Multicast 支持)。
setMulticastTTL()设置数据传输跳数 TTL (仅 Multicast 支持)。
getMulticastTTL()获取数据传输跳数 TTL (仅 Multicast 支持)。
setLoopbackMode()设置回环模式,允许主机在本地循环接收自己发送的多播数据包 (仅 Multicast 支持)。
getLoopbackMode()获取回环模式开启或关闭的状态 (仅 Multicast 支持)。
on(type: ‘message’)订阅 Socket 连接的接收消息事件。
off(type: ‘message’)取消订阅 Socket 连接的接收消息事件。
on(type: ‘close’)订阅 Socket 连接的关闭事件。
off(type: ‘close’)取消订阅 Socket 连接的关闭事件。
on(type: ‘error’)订阅 Socket 连接的 Error 事件。
off(type: ‘error’)取消订阅 Socket 连接的 Error 事件。
on(type: ‘listening’)订阅 UDPSocket 连接的数据包消息事件(仅 UDP 支持)。
off(type: ‘listening’)取消订阅 UDPSocket 连接的数据包消息事件(仅 UDP 支持)。
on(type: ‘connect’)订阅 Socket 的连接事件(仅 TCP/LocalSocket 支持)。
off(type: ‘connect’)取消订阅 Socket 的连接事件(仅 TCP/LocalSocket 支持)。

TLS Socket 连接主要由 tls_socket 模块提供。具体接口说明如下表。

接口名功能描述
constructTLSSocketInstance()创建一个 TLSSocket 对象。
bind()绑定 IP 地址和端口号。
close(type: ‘error’)关闭连接。
connect()连接到指定的 IP 地址和端口。
getCertificate()返回表示本地证书的对象。
getCipherSuite()返回包含协商的密码套件信息的列表。
getProtocol()返回包含当前连接协商的 SSL/TLS 协议版本的字符串。
getRemoteAddress()获取 TLSSocket 连接的对端地址。
getRemoteCertificate()返回表示对等证书的对象。
getSignatureAlgorithms()在服务器和客户端之间共享的签名算法列表,按优先级降序排列。
getState()获取 TLSSocket 连接的状态。
off(type: ‘close’)取消订阅 TLSSocket 连接的关闭事件。
off(type: ‘error’)取消订阅 TLSSocket 连接的 Error 事件。
off(type: ‘message’)取消订阅 TLSSocket 连接的接收消息事件。
on(type: ‘close’)订阅 TLSSocket 连接的关闭事件。
on(type: ‘error’)订阅 TLSSocket 连接的 Error 事件。
on(type: ‘message’)订阅 TLSSocket 连接的接收消息事件。
setExtraOptions()设置 TLSSocket 连接的其他属性。

4.1 Socket 连接主要场景

应用通过 Socket 进行数据传输,支持 TCP/UDP/Multicast/TLS 协议。主要场景有:

  1. 应用通过 TCP/UDP Socket进行数据传输
  2. 应用通过 TCP Socket Server 进行数据传输
  3. 应用通过 Multicast Socket 进行数据传输
  4. 应用通过 Local Socket进行数据传输
  5. 应用通过 Local Socket Server 进行数据传输
  6. 应用通过 TLS Socket 进行加密数据传输
  7. 应用通过 TLS Socket Server ​​​​​​​进行加密数据传输

4.1.1 TCP/UDP Socket进行数据传输 

UDP TCP 流程大体类似,下面以 TCP 为例:

  1. import 需要的 socket 模块。
  2. 创建一个 TCPSocket 连接,返回一个 TCPSocket 对象。
  3. (可选)订阅 TCPSocket 相关的订阅事件。
  4. 绑定 IP 地址和端口,端口可以指定或由系统随机分配。
  5. 连接到指定的 IP 地址和端口。
  6. 发送数据。
  7. Socket 连接使用完毕后,主动关闭。
import { socket } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';class SocketInfo {message: ArrayBuffer = new ArrayBuffer(1);remoteInfo: socket.SocketRemoteInfo = {} as socket.SocketRemoteInfo;
}
// 创建一个TCPSocket连接,返回一个TCPSocket对象。
let tcp: socket.TCPSocket = socket.constructTCPSocketInstance();
tcp.on('message', (value: SocketInfo) => {console.log("on message");let buffer = value.message;let dataView = new DataView(buffer);let str = "";for (let i = 0; i < dataView.byteLength; ++i) {str += String.fromCharCode(dataView.getUint8(i));}console.log("on connect received:" + str);
});
tcp.on('connect', () => {console.log("on connect");
});
tcp.on('close', () => {console.log("on close");
});// 绑定本地IP地址和端口。
let ipAddress : socket.NetAddress = {} as socket.NetAddress;
ipAddress.address = "192.168.xxx.xxx";
ipAddress.port = 1234;
tcp.bind(ipAddress, (err: BusinessError) => {if (err) {console.log('bind fail');return;}console.log('bind success');// 连接到指定的IP地址和端口。ipAddress.address = "192.168.xxx.xxx";ipAddress.port = 5678;let tcpConnect : socket.TCPConnectOptions = {} as socket.TCPConnectOptions;tcpConnect.address = ipAddress;tcpConnect.timeout = 6000;tcp.connect(tcpConnect).then(() => {console.log('connect success');let tcpSendOptions: socket.TCPSendOptions = {data: 'Hello, server!'}tcp.send(tcpSendOptions).then(() => {console.log('send success');}).catch((err: BusinessError) => {console.log('send fail');});}).catch((err: BusinessError) => {console.log('connect fail');});
});// 连接使用完毕后,主动关闭。取消相关事件的订阅。
setTimeout(() => {tcp.close().then(() => {console.log('close success');}).catch((err: BusinessError) => {console.log('close fail');});tcp.off('message');tcp.off('connect');tcp.off('close');
}, 30 * 1000);

4.1.2 TCP Socket Server 进行数据传输

服务端 TCP Socket 流程

  1. import 需要的 socket 模块。
  2. 创建一个 TCPSocketServer 连接,返回一个 TCPSocketServer 对象。
  3. 绑定本地 IP 地址和端口,监听并接受与此套接字建立的客户端 TCPSocket 连接。
  4. 订阅 TCPSocketServer 的 connect 事件,用于监听客户端的连接状态。
  5. 客户端与服务端建立连接后,返回一个 TCPSocketConnection 对象,用于与客户端通信。
  6. 订阅 TCPSocketConnection 相关的事件,通过 TCPSocketConnection 向客户端发送数据。
  7. 主动关闭与客户端的连接。
  8. 取消 TCPSocketConnection 和 TCPSocketServer 相关事件的订阅。
import { socket } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';// 创建一个TCPSocketServer连接,返回一个TCPSocketServer对象。
let tcpServer: socket.TCPSocketServer = socket.constructTCPSocketServerInstance();
// 绑定本地IP地址和端口,进行监听let ipAddress : socket.NetAddress = {} as socket.NetAddress;
ipAddress.address = "192.168.xxx.xxx";
ipAddress.port = 4651;
tcpServer.listen(ipAddress).then(() => {console.log('listen success');
}).catch((err: BusinessError) => {console.log('listen fail');
});class SocketInfo {message: ArrayBuffer = new ArrayBuffer(1);remoteInfo: socket.SocketRemoteInfo = {} as socket.SocketRemoteInfo;
}
// 订阅TCPSocketServer的connect事件
tcpServer.on("connect", (client: socket.TCPSocketConnection) => {// 订阅TCPSocketConnection相关的事件client.on("close", () => {console.log("on close success");});client.on("message", (value: SocketInfo) => {let buffer = value.message;let dataView = new DataView(buffer);let str = "";for (let i = 0; i < dataView.byteLength; ++i) {str += String.fromCharCode(dataView.getUint8(i));}console.log("received message--:" + str);console.log("received address--:" + value.remoteInfo.address);console.log("received family--:" + value.remoteInfo.family);console.log("received port--:" + value.remoteInfo.port);console.log("received size--:" + value.remoteInfo.size);});// 向客户端发送数据let tcpSendOptions : socket.TCPSendOptions = {} as socket.TCPSendOptions;tcpSendOptions.data = 'Hello, client!';client.send(tcpSendOptions).then(() => {console.log('send success');}).catch((err: Object) => {console.error('send fail: ' + JSON.stringify(err));});// 关闭与客户端的连接client.close().then(() => {console.log('close success');}).catch((err: BusinessError) => {console.log('close fail');});// 取消TCPSocketConnection相关的事件订阅setTimeout(() => {client.off("message");client.off("close");}, 10 * 1000);
});// 取消TCPSocketServer相关的事件订阅
setTimeout(() => {tcpServer.off("connect");
}, 30 * 1000);

4.1.3 Multicast Socket 进行数据传输

  1. import 需要的 socket 模块。
  2. 创建 multicastSocket 多播对象。
  3. 指定多播 IP 与端口,加入多播组。
  4. 开启消息 message 监听。
  5. 发送数据,数据以广播的形式传输,同一多播组中已经开启消息 message 监听的多播对象都会接收到数据。
  6. 关闭 message 消息的监听。
  7. 退出多播组。
import { socket } from '@kit.NetworkKit';// 创建Multicast对象
let multicast: socket.MulticastSocket = socket.constructMulticastSocketInstance();let addr : socket.NetAddress = {address: '239.255.0.1',port: 32123,family: 1
}// 加入多播组
multicast.addMembership(addr).then(() => {console.log('addMembership success');
}).catch((err: Object) => {console.log('addMembership fail');
});// 开启监听消息数据,将接收到的ArrayBuffer类型数据转换为String
class SocketInfo {message: ArrayBuffer = new ArrayBuffer(1);remoteInfo: socket.SocketRemoteInfo = {} as socket.SocketRemoteInfo;
}
multicast.on('message', (data: SocketInfo) => {console.info('接收的数据: ' + JSON.stringify(data))const uintArray = new Uint8Array(data.message)let str = ''for (let i = 0; i < uintArray.length; ++i) {str += String.fromCharCode(uintArray[i])}console.info(str)
})// 发送数据
multicast.send({ data:'Hello12345', address: addr }).then(() => {console.log('send success');
}).catch((err: Object) => {console.log('send fail, ' + JSON.stringify(err));
});// 关闭消息的监听
multicast.off('message')// 退出多播组
multicast.dropMembership(addr).then(() => {console.log('drop membership success');
}).catch((err: Object) => {console.log('drop membership fail');
});

4.1.4 Local Socket进行数据传输

  1. import 需要的 socket 模块。
  2. 使用 constructLocalSocketInstance 接口,创建一个 LocalSocket 客户端对象。
  3. 注册 LocalSocket 的消息(message)事件,以及一些其它事件(可选)。
  4. 连接到指定的本地套接字文件路径。
  5. 发送数据。
  6. Socket 连接使用完毕后,取消事件的注册,并关闭套接字。
import { socket } from '@kit.NetworkKit';// 创建一个LocalSocket连接,返回一个LocalSocket对象。
let client: socket.LocalSocket = socket.constructLocalSocketInstance();
client.on('message', (value: socket.LocalSocketMessageInfo) => {const uintArray = new Uint8Array(value.message)let messageView = '';for (let i = 0; i < uintArray.length; i++) {messageView += String.fromCharCode(uintArray[i]);}console.log('total receive: ' + JSON.stringify(value));console.log('message information: ' + messageView);
});
client.on('connect', () => {console.log("on connect");
});
client.on('close', () => {console.log("on close");
});// 传入指定的本地套接字路径,连接服务端。
let sandboxPath: string = getContext(this).filesDir + '/testSocket'
let localAddress : socket.LocalAddress = {address: sandboxPath
}
let connectOpt: socket.LocalConnectOptions = {address: localAddress,timeout: 6000
}
let sendOpt: socket.LocalSendOptions = {data: 'Hello world!'
}
client.connect(connectOpt).then(() => {console.log('connect success')client.send(sendOpt).then(() => {console.log('send success')}).catch((err: Object) => {console.log('send failed: ' + JSON.stringify(err))})
}).catch((err: Object) => {console.log('connect fail: ' + JSON.stringify(err));
});// 当不需要再连接服务端,需要断开且取消事件的监听时
client.off('message');
client.off('connect');
client.off('close');
client.close().then(() => {console.log('close client success')
}).catch((err: Object) => {console.log('close client err: ' + JSON.stringify(err))
})

4.1.5 Local Socket Server 进行数据传输

服务端 LocalSocket Server 流程:

  1. import 需要的 socket 模块。
  2. 使用 constructLocalSocketServerInstance 接口,创建一个 LocalSocketServer 服务端对象。
  3. 启动服务,绑定本地套接字路径,创建出本地套接字文件,监听客户端的连接请求。
  4. 注册 LocalSocket 的客户端连接(connect)事件,以及一些其它事件(可选)。
  5. 在客户端连接上来时,通过连接事件的回调函数,获取连接会话对象。
  6. 给会话对象 LocalSocketConnection 注册消息(message)事件,以及一些其它事件(可选)。
  7. 通过会话对象主动向客户端发送消息。
  8. 结束与客户端的通信,主动断开与客户端的连接。
  9. 取消 LocalSocketConnection 和 LocalSocketServer 相关事件的订阅。
import { socket } from '@kit.NetworkKit';// 创建一个LocalSocketServer连接,返回一个LocalSocketServer对象。
let server: socket.LocalSocketServer = socket.constructLocalSocketServerInstance();
// 创建并绑定本地套接字文件testSocket,进行监听
let sandboxPath: string = getContext(this).filesDir + '/testSocket'
let listenAddr: socket.LocalAddress = {address: sandboxPath
}
server.listen(listenAddr).then(() => {console.log("listen success");
}).catch((err: Object) => {console.log("listen fail: " + JSON.stringify(err));
});// 订阅LocalSocketServer的connect事件
server.on('connect', (connection: socket.LocalSocketConnection) => {// 订阅LocalSocketConnection相关的事件connection.on('error', (err: Object) => {console.log("on error success");});connection.on('message', (value: socket.LocalSocketMessageInfo) => {const uintArray = new Uint8Array(value.message);let messageView = '';for (let i = 0; i < uintArray.length; i++) {messageView += String.fromCharCode(uintArray[i]);}console.log('total: ' + JSON.stringify(value));console.log('message information: ' + messageView);});connection.on('error', (err: Object) => {console.log("err:" + JSON.stringify(err));})// 向客户端发送数据let sendOpt : socket.LocalSendOptions = {data: 'Hello world!'};connection.send(sendOpt).then(() => {console.log('send success');}).catch((err: Object) => {console.log('send failed: ' + JSON.stringify(err));})// 关闭与客户端的连接connection.close().then(() => {console.log('close success');}).catch((err: Object) => {console.log('close failed: ' + JSON.stringify(err));});// 取消LocalSocketConnection相关的事件订阅connection.off('message');connection.off('error');
});// 取消LocalSocketServer相关的事件订阅
server.off('connect');
server.off('error');

4.1.6 TLS Socket 进行加密数据传输

客户端 TLS Socket 流程:

  1. import 需要的 socket 模块。
  2. 绑定服务器 IP 和端口号。
  3. 双向认证上传客户端 CA 证书及数字证书;单向认证上传客户端 CA 证书。
  4. 创建一个 TLSSocket 连接,返回一个 TLSSocket 对象。
  5. (可选)订阅 TLSSocket 相关的订阅事件。
  6. 发送数据。
  7. TLSSocket 连接使用完毕后,主动关闭。
import { socket } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';class SocketInfo {message: ArrayBuffer = new ArrayBuffer(1);remoteInfo: socket.SocketRemoteInfo = {} as socket.SocketRemoteInfo;
}
// 创建一个(双向认证)TLS Socket连接,返回一个TLS Socket对象。
let tlsTwoWay: socket.TLSSocket = socket.constructTLSSocketInstance();
// 订阅TLS Socket相关的订阅事件
tlsTwoWay.on('message', (value: SocketInfo) => {console.log("on message");let buffer = value.message;let dataView = new DataView(buffer);let str = "";for (let i = 0; i < dataView.byteLength; ++i) {str += String.fromCharCode(dataView.getUint8(i));}console.log("on connect received:" + str);
});
tlsTwoWay.on('connect', () => {console.log("on connect");
});
tlsTwoWay.on('close', () => {console.log("on close");
});// 绑定本地IP地址和端口。
let ipAddress : socket.NetAddress = {} as socket.NetAddress;
ipAddress.address = "192.168.xxx.xxx";
ipAddress.port = 4512;
tlsTwoWay.bind(ipAddress, (err: BusinessError) => {if (err) {console.log('bind fail');return;}console.log('bind success');
});ipAddress.address = "192.168.xxx.xxx";
ipAddress.port = 1234;let tlsSecureOption : socket.TLSSecureOptions = {} as socket.TLSSecureOptions;
tlsSecureOption.key = "xxxx";
tlsSecureOption.cert = "xxxx";
tlsSecureOption.ca = ["xxxx"];
tlsSecureOption.password = "xxxx";
tlsSecureOption.protocols = [socket.Protocol.TLSv12];
tlsSecureOption.useRemoteCipherPrefer = true;
tlsSecureOption.signatureAlgorithms = "rsa_pss_rsae_sha256:ECDSA+SHA256";
tlsSecureOption.cipherSuite = "AES256-SHA256";let tlsTwoWayConnectOption : socket.TLSConnectOptions = {} as socket.TLSConnectOptions;
tlsSecureOption.key = "xxxx";
tlsTwoWayConnectOption.address = ipAddress;
tlsTwoWayConnectOption.secureOptions = tlsSecureOption;
tlsTwoWayConnectOption.ALPNProtocols = ["spdy/1", "http/1.1"];// 建立连接
tlsTwoWay.connect(tlsTwoWayConnectOption).then(() => {console.log("connect successfully");
}).catch((err: BusinessError) => {console.log("connect failed " + JSON.stringify(err));
});// 连接使用完毕后,主动关闭。取消相关事件的订阅。
tlsTwoWay.close((err: BusinessError) => {if (err) {console.log("close callback error = " + err);} else {console.log("close success");}tlsTwoWay.off('message');tlsTwoWay.off('connect');tlsTwoWay.off('close');
});// 创建一个(单向认证)TLS Socket连接,返回一个TLS Socket对象。
let tlsOneWay: socket.TLSSocket = socket.constructTLSSocketInstance(); // One way authentication// 订阅TLS Socket相关的订阅事件
tlsTwoWay.on('message', (value: SocketInfo) => {console.log("on message");let buffer = value.message;let dataView = new DataView(buffer);let str = "";for (let i = 0; i < dataView.byteLength; ++i) {str += String.fromCharCode(dataView.getUint8(i));}console.log("on connect received:" + str);
});
tlsTwoWay.on('connect', () => {console.log("on connect");
});
tlsTwoWay.on('close', () => {console.log("on close");
});// 绑定本地IP地址和端口。
ipAddress.address = "192.168.xxx.xxx";
ipAddress.port = 5445;
tlsOneWay.bind(ipAddress, (err:BusinessError) => {if (err) {console.log('bind fail');return;}console.log('bind success');
});ipAddress.address = "192.168.xxx.xxx";
ipAddress.port = 8789;
let tlsOneWaySecureOption : socket.TLSSecureOptions = {} as socket.TLSSecureOptions;
tlsOneWaySecureOption.ca = ["xxxx", "xxxx"];
tlsOneWaySecureOption.cipherSuite = "AES256-SHA256";let tlsOneWayConnectOptions: socket.TLSConnectOptions = {} as socket.TLSConnectOptions;
tlsOneWayConnectOptions.address = ipAddress;
tlsOneWayConnectOptions.secureOptions = tlsOneWaySecureOption;// 建立连接
tlsOneWay.connect(tlsOneWayConnectOptions).then(() => {console.log("connect successfully");
}).catch((err: BusinessError) => {console.log("connect failed " + JSON.stringify(err));
});// 连接使用完毕后,主动关闭。取消相关事件的订阅。
tlsTwoWay.close((err: BusinessError) => {if (err) {console.log("close callback error = " + err);} else {console.log("close success");}tlsTwoWay.off('message');tlsTwoWay.off('connect');tlsTwoWay.off('close');
});

4.1.7 TCP Socket 升级为 TLS Socket 进行加密数据传输

客户端 TCP Socket 升级为 TLS Socket 流程:

  1. import 需要的 socket 模块。
  2. 参考应用 TCP/UDP 协议进行通信,创建一个 TCPSocket 连接。
  3. 确保 TCPSocket 已连接后,使用该 TCPSocket 对象创建 TLSSocket 连接,返回一个 TLSSocket 对象。
  4. 双向认证上传客户端 CA 证书及数字证书;单向认证上传客户端 CA 证书。
  5. (可选)订阅 TLSSocket 相关的订阅事件。
  6. 发送数据。
  7. TLSSocket 连接使用完毕后,主动关闭。
import { socket } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';class SocketInfo {message: ArrayBuffer = new ArrayBuffer(1);remoteInfo: socket.SocketRemoteInfo = {} as socket.SocketRemoteInfo;
}// 创建一个TCPSocket连接,返回一个TCPSocket对象。
let tcp: socket.TCPSocket = socket.constructTCPSocketInstance();
tcp.on('message', (value: SocketInfo) => {console.log("on message");let buffer = value.message;let dataView = new DataView(buffer);let str = "";for (let i = 0; i < dataView.byteLength; ++i) {str += String.fromCharCode(dataView.getUint8(i));}console.log("on connect received:" + str);
});
tcp.on('connect', () => {console.log("on connect");
});// 绑定本地IP地址和端口。
let ipAddress: socket.NetAddress = {} as socket.NetAddress;
ipAddress.address = "192.168.xxx.xxx";
ipAddress.port = 1234;
tcp.bind(ipAddress, (err: BusinessError) => {if (err) {console.log('bind fail');return;}console.log('bind success');// 连接到指定的IP地址和端口。ipAddress.address = "192.168.xxx.xxx";ipAddress.port = 443;let tcpConnect: socket.TCPConnectOptions = {} as socket.TCPConnectOptions;tcpConnect.address = ipAddress;tcpConnect.timeout = 6000;tcp.connect(tcpConnect, (err: BusinessError) => {if (err) {console.log('connect fail');return;}console.log('connect success');// 确保TCPSocket已连接后,将其升级为TLSSocket连接。let tlsTwoWay: socket.TLSSocket = socket.constructTLSSocketInstance(tcp);// 订阅TLSSocket相关的订阅事件。tlsTwoWay.on('message', (value: SocketInfo) => {console.log("tls on message");let buffer = value.message;let dataView = new DataView(buffer);let str = "";for (let i = 0; i < dataView.byteLength; ++i) {str += String.fromCharCode(dataView.getUint8(i));}console.log("tls on connect received:" + str);});tlsTwoWay.on('connect', () => {console.log("tls on connect");});tlsTwoWay.on('close', () => {console.log("tls on close");});// 配置TLSSocket目的地址、证书等信息。ipAddress.address = "192.168.xxx.xxx";ipAddress.port = 1234;let tlsSecureOption: socket.TLSSecureOptions = {} as socket.TLSSecureOptions;tlsSecureOption.key = "xxxx";tlsSecureOption.cert = "xxxx";tlsSecureOption.ca = ["xxxx"];tlsSecureOption.password = "xxxx";tlsSecureOption.protocols = [socket.Protocol.TLSv12];tlsSecureOption.useRemoteCipherPrefer = true;tlsSecureOption.signatureAlgorithms = "rsa_pss_rsae_sha256:ECDSA+SHA256";tlsSecureOption.cipherSuite = "AES256-SHA256";let tlsTwoWayConnectOption: socket.TLSConnectOptions = {} as socket.TLSConnectOptions;tlsSecureOption.key = "xxxx";tlsTwoWayConnectOption.address = ipAddress;tlsTwoWayConnectOption.secureOptions = tlsSecureOption;tlsTwoWayConnectOption.ALPNProtocols = ["spdy/1", "http/1.1"];// 建立TLSSocket连接tlsTwoWay.connect(tlsTwoWayConnectOption, () => {console.log("tls connect success");// 连接使用完毕后,主动关闭。取消相关事件的订阅。tlsTwoWay.close((err: BusinessError) => {if (err) {console.log("tls close callback error = " + err);} else {console.log("tls close success");}tlsTwoWay.off('message');tlsTwoWay.off('connect');tlsTwoWay.off('close');});});});
});

4.1.8 TCP Socket 升级为 TLS Socket 进行加密数据传输

服务端 TLS Socket Server 流程:

  1. import 需要的 socket 模块。
  2. 启动服务,绑定 IP 和端口号,监听客户端连接,创建并初始化 TLS 会话,加载证书密钥并验证。
  3. 订阅 TLSSocketServer 的连接事件。
  4. 收到客户端连接,通过回调得到 TLSSocketConnection 对象。
  5. 订阅 TLSSocketConnection 相关的事件。
  6. 发送数据。
  7. TLSSocketConnection 连接使用完毕后,断开连接。
  8. 取消订阅 TLSSocketConnection 以及 TLSSocketServer 的相关事件。
import { socket } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';let tlsServer: socket.TLSSocketServer = socket.constructTLSSocketServerInstance();let netAddress: socket.NetAddress = {address: '192.168.xx.xxx',port: 8080
}let tlsSecureOptions: socket.TLSSecureOptions = {key: "xxxx",cert: "xxxx",ca: ["xxxx"],password: "xxxx",protocols: socket.Protocol.TLSv12,useRemoteCipherPrefer: true,signatureAlgorithms: "rsa_pss_rsae_sha256:ECDSA+SHA256",cipherSuite: "AES256-SHA256"
}let tlsConnectOptions: socket.TLSConnectOptions = {address: netAddress,secureOptions: tlsSecureOptions,ALPNProtocols: ["spdy/1", "http/1.1"]
}tlsServer.listen(tlsConnectOptions).then(() => {console.log("listen callback success");
}).catch((err: BusinessError) => {console.log("failed" + err);
});class SocketInfo {message: ArrayBuffer = new ArrayBuffer(1);remoteInfo: socket.SocketRemoteInfo = {} as socket.SocketRemoteInfo;
}
let callback = (value: SocketInfo) => {let messageView = '';for (let i: number = 0; i < value.message.byteLength; i++) {let uint8Array = new Uint8Array(value.message)let messages = uint8Array[i]let message = String.fromCharCode(messages);messageView += message;}console.log('on message message: ' + JSON.stringify(messageView));console.log('remoteInfo: ' + JSON.stringify(value.remoteInfo));
}
tlsServer.on('connect', (client: socket.TLSSocketConnection) => {client.on('message', callback);// 发送数据client.send('Hello, client!').then(() => {console.log('send success');}).catch((err: BusinessError) => {console.log('send fail');});// 断开连接client.close().then(() => {console.log('close success');}).catch((err: BusinessError) => {console.log('close fail');});// 可以指定传入on中的callback取消一个订阅,也可以不指定callback清空所有订阅。client.off('message', callback);client.off('message');
});// 取消订阅tlsServer的相关事件
tlsServer.off('connect');

5 MDNS管理

MDNS即多播DNS(Multicast DNS),提供局域网内的本地服务添加、移除、发现、解析等能力。

  • 本地服务:局域网内服务的提供方,比如打印机、扫描器等。

MDNS管理的典型场景有

  1. 管理本地服务,通过对本地服务的创建,删除和解析等管理本地服务。
  2. 发现本地服务,通过DiscoveryService对象,对指定类型的本地服务状态变化进行监听。

说明
为了保证应用的运行效率,大部分API调用都是异步的,对于异步调用的API均提供了callback和Promise两种方式,以下示例均采用promise函数,更多方式可以查阅MDNS管理-API参考。

 完整的JS API说明以及实例代码请参考:MDNS管理-API参考。

接口名描述
addLocalService(context: Context, serviceInfo: LocalServiceInfo, callback: AsyncCallback): void添加一个MDNS服务,使用callback方式作为异步方法。
removeLocalService(context: Context, serviceInfo: LocalServiceInfo, callback: AsyncCallback): void移除一个MDNS服务,使用callback方式作为异步方法。
createDiscoveryService(context: Context, serviceType: string): DiscoveryService返回一个DiscoveryService对象,该对象用于发现指定服务类型的MDNS服务。
resolveLocalService(context: Context, serviceInfo: LocalServiceInfo, callback: AsyncCallback): void解析一个MDNS服务,使用callback方式作为异步方法。
startSearchingMDNS(): void开始搜索局域网内的MDNS服务。
stopSearchingMDNS(): void停止搜索局域网内的MDNS服务。
on(type: ‘discoveryStart’, callback: Callback<{serviceInfo: LocalServiceInfo, errorCode?: MdnsError}>): void订阅开启监听MDNS服务的通知。
off(type: ‘discoveryStart’, callback?: Callback<{ serviceInfo: LocalServiceInfo, errorCode?: MdnsError }>): void取消开启监听MDNS服务的通知。
on(type: ‘discoveryStop’, callback: Callback<{serviceInfo: LocalServiceInfo, errorCode?: MdnsError}>): void订阅停止监听MDNS服务的通知。
off(type: ‘discoveryStop’, callback?: Callback<{ serviceInfo: LocalServiceInfo, errorCode?: MdnsError }>): void取消停止监听MDNS服务的通知。
on(type: ‘serviceFound’, callback: Callback): void订阅发现MDNS服务的通知。
off(type: ‘serviceFound’, callback?: Callback): void取消发现MDNS服务的通知。
on(type: ‘serviceLost’, callback: Callback): void 订阅移除MDNS服务的通知。
off(type: ‘serviceLost’, callback?: Callback): void 取消移除MDNS服务的通知。

5.1 管理本地服务 

  1. 设备连接WiFi。
  2. 从@kit.NetworkKit里导入mdns的命名空间。
  3. 调用addLocalService方法,添加本地服务。
  4. 通过resolveLocalService方法,解析本地网络的IP地址(非必要,根据需求使用)。
  5. 通过removeLocalService方法,移除本地服务。
// 从@kit.NetworkKit中导入mdns命名空间
import { mdns } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { featureAbility } from '@kit.AbilityKit';let context = getContext(this) as Context;class ServiceAttribute {key: string = "111"value: Array<number> = [1]
}// 建立LocalService对象
let localServiceInfo: mdns.LocalServiceInfo = {serviceType: "_print._tcp",serviceName: "servicename",port: 5555,host: {address: "10.14.**.***"},serviceAttribute: [{key: "111", value: [1]}]
}// addLocalService添加本地服务
mdns.addLocalService(context, localServiceInfo).then((data: mdns.LocalServiceInfo) => {console.log(JSON.stringify(data));
});// resolveLocalService解析本地服务对象(非必要,根据需求使用)
mdns.resolveLocalService(context, localServiceInfo).then((data: mdns.LocalServiceInfo) => {console.log(JSON.stringify(data));
});// removeLocalService移除本地服务
mdns.removeLocalService(context, localServiceInfo).then((data: mdns.LocalServiceInfo) => {console.log(JSON.stringify(data));
});

5.2 发现本地服务

  1. 设备连接WiFi。
  2. 从@kit.NetworkKit里导入mdns的命名空间。
  3. 创建DiscoveryService对象,用于发现指定服务类型的MDNS服务。
  4. 订阅MDNS服务发现相关状态变化。
  5. 启动搜索局域网内的MDNS服务。
  6. 停止搜索局域网内的MDNS服务。
  7. 取消订阅的MDNS服务。
// 从@kit.NetworkKit中导入mdns命名空间
import { common, featureAbility, UIAbility } from '@kit.AbilityKit';
import { mdns } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { window } from '@kit.ArkUI';// 构造单例对象
export class GlobalContext {private constructor() {}private static instance: GlobalContext;private _objects = new Map<string, Object>();public static getContext(): GlobalContext {if (!GlobalContext.instance) {GlobalContext.instance = new GlobalContext();}return GlobalContext.instance;}getObject(value: string): Object | undefined {return this._objects.get(value);}setObject(key: string, objectClass: Object): void {this._objects.set(key, objectClass);}
}// Stage模型获取context
class EntryAbility extends UIAbility {value:number = 0;onWindowStageCreate(windowStage: window.WindowStage): void{GlobalContext.getContext().setObject("value", this.value);}
}let context = GlobalContext.getContext().getObject("value") as common.UIAbilityContext;// 创建DiscoveryService对象,用于发现指定服务类型的MDNS服务
let serviceType = "_print._tcp";
let discoveryService = mdns.createDiscoveryService(context, serviceType);// 订阅MDNS服务发现相关状态变化
discoveryService.on('discoveryStart', (data: mdns.DiscoveryEventInfo) => {console.log(JSON.stringify(data));
});
discoveryService.on('discoveryStop', (data: mdns.DiscoveryEventInfo) => {console.log(JSON.stringify(data));
});
discoveryService.on('serviceFound', (data: mdns.LocalServiceInfo) => {console.log(JSON.stringify(data));
});
discoveryService.on('serviceLost', (data: mdns.LocalServiceInfo) => {console.log(JSON.stringify(data));
});// 启动搜索局域网内的MDNS服务
discoveryService.startSearchingMDNS();// 停止搜索局域网内的MDNS服务
discoveryService.stopSearchingMDNS();// 取消订阅的MDNS服务
discoveryService.off('discoveryStart', (data: mdns.DiscoveryEventInfo) => {console.log(JSON.stringify(data));
});
discoveryService.off('discoveryStop', (data: mdns.DiscoveryEventInfo) => {console.log(JSON.stringify(data));
});
discoveryService.off('serviceFound', (data: mdns.LocalServiceInfo) => {console.log(JSON.stringify(data));
});
discoveryService.off('serviceLost', (data: mdns.LocalServiceInfo) => {console.log(JSON.stringify(data));
});

参考文献:
[1]HarmonyOS NEXT Beta1开发文档


http://www.ppmy.cn/server/147448.html

相关文章

NLP 的研究任务

自然语言处理&#xff08;Natural Language Processing, NLP&#xff09; NLP 的研究任务 自然语言处理&#xff08;Natural Language Processing, NLP&#xff09;1. **机器翻译**2. **情感分析**3. **智能问答**4. **文摘生成**5. **文本分类**6. **舆论分析**7. **知识图谱*…

23种设计模式之适配器模式

目录 1. 简介1.1 定义1.2 结构和组成部分 2. 代码2.1 MediaPlayer2.2 AdvanceMediaPlayer2.3 VicPlayer2.4 Mp4Player2.5 MediaPlayerAdapter2.6 AudioPlayer2.7 Test 3. 适用场景4. 优点和缺点5. 总结 1. 简介 1.1 定义 适配器模式&#xff08;Adapter Pattern&#xff09;是…

android视频播放器之DKVideoPlayer

一个老牌子的播放器了&#xff0c;项目可能已经有些日子没有维护了。但是使用效果还是不错的。支持多种视频格式&#xff0c;及重力感应、调节亮度等多种效果。想来想去&#xff0c;还是记录下来&#xff0c;我会在文章的最后注明github地址&#xff1a; 首先引入依赖&#xff…

【Elasticsearch】06-JavaRestClient查询

1. MatchAll查询与结果解析 public class ElasticQueryTest {private RestHighLevelClient client;BeforeEachpublic void init() {client new RestHighLevelClient(RestClient.builder(HttpHost.create("http://nuaamvp.cn:9200")));}AfterEachvoid tearDown() {i…

威胁驱动的网络安全方法论

摘要 目前的网络安全风险管理实践很大程度上是由合规性要求驱动的&#xff0c;这使得公司/组织不得不在安全控制和漏洞上投入人力/物力。&#xff08;风险管理涉及多个方面&#xff0c;包括资产、威胁、漏洞和控制&#xff0c;并根据事故发生的可能性及造成的影响进行评估。威…

2024年11月一区SCI-Alpha evolution-附Matlab免费代码

引言 本期介绍了一种新的进化算法——阿尔法进化算法Alpha evolution&#xff0c;AE。它使用带有自适应基向量和随机和自适应步长的alpha算子更新解。该算法于2024年11月最新发表在JCR 1区&#xff0c;中科院2区SCI期刊Engineering Applications of Artificial Intelligence。…

数据库视图应用指南:案例详解与分析

目录 一、定义与特点二、类型与分类三、创建与使用1. 创建视图2. 查看视图3. 修改视图4. 删除视图5. 查询视图四、示例案例一. 综合简单示例案例二:简化复杂查询案例三:数据安全与访问控制案例四:数据整合与报表生成案例五:数据抽象与业务逻辑封装五、应用场景与优势数据库…

ESP32-S3模组上跑通ES8388(11)

接前一篇文章&#xff1a;ESP32-S3模组上跑通ES8388&#xff08;10&#xff09; 二、利用ESP-ADF操作ES8388 2. 详细解析 上一回解析了es8388_init函数中的第4段代码&#xff0c;本回继续往下解析。为了便于理解和回顾&#xff0c;再次贴出es8388_init函数源码&#xff0c;在…