【HarmonyOS NEXT】鸿蒙Socket 连接

简介

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

基本概念

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

场景介绍

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

  • 应用通过 TCP/UDP Socket进行数据传输
  • 应用通过 TCP Socket Server 进行数据传输
  • 应用通过 Multicast Socket 进行数据传输
  • 应用通过 Local Socket进行数据传输
  • 应用通过 Local Socket Server 进行数据传输
  • 应用通过 TLS Socket 进行加密数据传输
  • 应用通过 TLS Socket Server 进行加密数据传输

接口说明

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 连接的接收消息事件。
send()发送数据。
setExtraOptions()设置 TLSSocket 连接的其他属性。

应用 TCP/UDP 协议进行通信

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);

应用通过 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);

应用通过 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');
});

应用通过 LocalSocket 进行数据传输

开发步骤:

  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))
})

应用通过 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');

应用通过 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');
});

应用通过 TLS Socket Server 进行加密数据传输

开发步骤

服务端 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');

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

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

相关文章

常见问题记录

conda操作 conda精确查找某个包的版本 conda list 包名下载源 -i https://pypi.mirrors.ustc.edu.cn/simple/conda查看下载源 conda config --show channels下载torch conda install pytorch1.13.0 torchvision0.14.0 torchaudio0.13.0 cpuonlyconda环境没有名字 利用vsc…

【java计算机毕设】美容院管理系统 项目源代码MySQL springboot vue html maven+文档 前后端可分离也可不分离

目录 1项目功能 2项目介绍 3项目地址 1项目功能 【java计算机毕设】美容院管理系统 项目源代码MySQL springboot vue html maven文档 前后端可分离也可不分离 2项目介绍 系统功能&#xff1a; 美容院管理系统包括管理员、用户俩种角色。 管理员功能包括个人中心模块用于修改…

“第六感”真的存在吗?

现在已有证据表明&#xff0c;人类除视觉、听觉、嗅觉、味觉和触觉五种感觉以外&#xff0c;确实存在“第六感” “第六感”的学术名称为“超感自知觉”(简称ESP)&#xff0c;它能透过正感官之外的渠道接收信息&#xff0c; 预知将要发生的事&#xff0c;而且与当事人之前的经…

苹果(apple)ios系统和安卓(Android) apk系统开发者账号类型及申请步骤

苹果(Apple) iOS系统和安卓(Android) APK系统的开发者账号类型及申请步骤如下&#xff1a; ### 苹果(Apple) iOS系统开发者账号类型&#xff1a; 1. **个人开发者账号&#xff08;Individual&#xff09;**: - 适用于个人开发者和小型公司。 - 可以发布应用程序到App Store。 -…

Prompt Engineering 探险

Introduction, Concepts Text generation models generation pre-trained transformers, GPT for short. 所以呢&#xff0c;前置知识是Transformer Assistants 助手指的是能够为用户执行任务的实体&#xff1b; Embeddings 是数据的一种vector形式&#xff0c;含有原来的…

向量数据库、主键存储引擎、高速网络 RDMA 框架……DolphinDB 版本更新啦!

盛夏已至&#xff0c;炎热的七月伊始&#xff0c;DolphinDB 也迎来了版本的更新。此次更新的 3.00.1 与 2.00.13 版本从多个维度进行了优化扩展&#xff0c;进一步深化了 DolphinDB 在机器学习、数据分析等领域的尝试与探索。 为了响应用户日益增长的 AI 运算需求&#xff0c;…

C语言自定义类型(结构体,枚举,联合):

大家好久不见&#xff0c;今天我们来学习一下C语言中的自定义类型&#xff1a; C语言的自定义类型包括&#xff1a;结构体&#xff0c;枚举和联合&#xff0c;接下来大家跟我来一起认识一下这三种类型。 目录 1. 结构体 1.1.1 结构体类型的声明 1.1.2 结构的特殊声明 1.1…

钡铼RTU无线S270用于风力发电站机房远程状态监测和故障预警系统集成

在现代风力发电行业中&#xff0c;机房的远程监测和故障预警系统对于保障风力发电机组的稳定运行至关重要。钡铼第4代S270工业级4G远程遥测终端&#xff08;RTU&#xff09;&#xff0c;以其先进的技术和多功能应用&#xff0c;成为风力发电站机房智能化管理的理想选择。 技术…

深入理解计算机系统 CSAPP 8.4.2 fork函数

//fork.c #include <sys/types.h> #include <unistd.h> #include <stdio.h>int main() {pid_t fpid; //fpid表示fork函数返回的值int count 0;fpid fork();if (fpid < 0)printf("error in fork!");else if (fpid 0) {printf("\ni am th…

初始化 Kubernetes 集群的必要步骤

以下是成功初始化 Kubernetes 集群的必要步骤: 1. 配置 Kubelet 创建并编辑 /etc/default/kubelet 文件: sudo nano /etc/default/kubelet添加以下内容: KUBELET_EXTRA_ARGS="--container-runtime=remote --container-runtime-endpoint=unix:///var/run/cri-dockerd.s…

相机网线RJ45连接器双端带线5米8芯绿色网线注塑成型

相机网线RJ45连接器双端带线5米8芯绿色网线注塑成型&#xff0c;这款网线采用了环保的绿色材质&#xff0c;线长5米&#xff0c;足够满足大多数拍摄场景的需求。更重要的是&#xff0c;它采用了8芯设计&#xff0c;保证了数据传输的稳定性和高速性。在接口方面&#xff0c;它采…

电容的作用和应用

电容是一种常见的电子元件&#xff0c;在电路中起着多种重要作用&#xff0c;并广泛应用于各种电子设备和系统中。 一、电容的主要作用 储能&#xff1a;电容的基本作用是储存电荷。当电容两端加上电压时&#xff0c;电容会储存电荷&#xff0c;储存的电荷量与电压成正比。这…

数据增强:目标检测算法中的性能提升利器

引言 目标检测是计算机视觉领域的核心任务之一&#xff0c;旨在从图像或视频中识别和定位感兴趣的对象。然而&#xff0c;由于训练数据的局限性&#xff0c;目标检测模型往往面临过拟合和泛化能力不足的问题。数据增强作为一种有效的解决方案&#xff0c;通过增加数据多样性来…

RpcChannel的调用过程

目录 1. RPC调用方&#xff08;caller&#xff09;的调用(消费)过程 2.在caller下创建文件&#xff1a;calluserservice.cc 3.在src的include下创建文件&#xff1a;mprpcchannel.h 4.在src下创建mprpcchannel.cc 1. RPC调用方&#xff08;caller&#xff09;的调用(消费)过…

Android14之RRO资源文件替换策略(二百二十一)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+AOSP…

【chatgpt】pytorch打印模型model参数,使用parameters()方法和named_parameters()方法

在 PyTorch 中&#xff0c;一个模型的参数通常指模型中所有可训练的权重和偏置。每个 nn.Module 对象&#xff08;包括自定义的神经网络类&#xff09;都有一个 parameters() 方法和一个 named_parameters() 方法&#xff0c;这些方法可以用来访问模型中的所有参数。以下是这些…

代码随想录算法训练营第67天:图论5[1]

代码随想录算法训练营第67天&#xff1a;图论5 ‍ 105.有向图的完全可达性 卡码网题目链接&#xff08;ACM模式&#xff09;(opens new window) 【题目描述】 给定一个有向图&#xff0c;包含 N 个节点&#xff0c;节点编号分别为 1&#xff0c;2&#xff0c;…&#xff0…

IT大门为你开,欢迎牛马走进来

IT专业入门&#xff0c;高考假期预习指南 七月来临&#xff0c;各省高考分数已揭榜完成。而高考的完结并不意味着学习的结束&#xff0c;而是新旅程的开始。对于有志于踏入IT领域的高考少年们&#xff0c;这个假期是开启探索IT世界的绝佳时机。作为该领域的前行者和经验前辈&a…

【操作与配置】VSCode配置Python及Jupyter

Python环境配置 可以参见&#xff1a;【操作与配置】Python&#xff1a;CondaPycharm_pycharmconda-CSDN博客 官网下载Python&#xff1a;http://www.python.org/download/官网下载Conda&#xff1a;Miniconda — Anaconda documentation VSCode插件安装 插件安装后需重启V…

matrix-breakout-2-morpheus靶场

1 信息收集 1.1 主机发现 arp-scan -l 1.2 端口与服务扫描 发现开放22、80、81端口 2 访问服务 2.1 访问80端口 查看源代码 2.2 访问81端口 3 目录扫描 3.1 dirsearch目录扫描 dirsearch -u 192.168.1.14 发现robots.txt文件和javascript文件 访问文件 http://192.168…