1# 使用WebSocket访问网络 2<!--Kit: Network Kit--> 3<!--Subsystem: Communication--> 4<!--Owner: @wmyao_mm--> 5<!--Designer: @guo-min_net--> 6<!--Tester: @tongxilin--> 7<!--Adviser: @zhang_yixin13--> 8 9## 场景介绍 10 11WebSocket是一种网络通信协议,它允许客户端和服务器之间建立一个持久的连接,并在该连接上进行全双工通信,连接之后客户端和服务器端可以同时主动发送数据,这是WebSocket和传统的HTTP协议最大的区别,HTTP以单向通信为主,客户端发起请求,服务器端响应数据,一次传输之后,连接会断开。一般情况下,HTTP适用于一次性数据获取(如网页内容加载),Websocket适用于实时性要求高的场景下(如在线聊天、实时游戏),以避免频繁建立连接提升用户体验。 12 13该模块给第三方应用提供webSocket客户端和服务端能力,实现客户端与服务端的双向连接,目前服务端仅支持智慧屏使用。 14 15客户端:使用WebSocket建立服务器与客户端的双向连接,需要先通过[createWebSocket()](../reference/apis-network-kit/js-apis-webSocket.md#websocketcreatewebsocket6)方法创建[WebSocket](../reference/apis-network-kit/js-apis-webSocket.md#websocket6)对象,然后通过[connect()](../reference/apis-network-kit/js-apis-webSocket.md#connect6)方法连接到服务器。当连接成功后,客户端会收到[open](../reference/apis-network-kit/js-apis-webSocket.md#onopen6)事件的回调,之后客户端就可以通过[send()](../reference/apis-network-kit/js-apis-webSocket.md#send6)方法与服务器进行通信。当服务器发信息给客户端时,客户端会收到[message](../reference/apis-network-kit/js-apis-webSocket.md#onmessage6)事件的回调。当客户端想要取消此连接时,通过调用[close()](../reference/apis-network-kit/js-apis-webSocket.md#close6)方法主动断开连接后,客户端会收到[close](../reference/apis-network-kit/js-apis-webSocket.md#onclose6)事件的回调。若在上述任一过程中发生错误,客户端会收到[error](../reference/apis-network-kit/js-apis-webSocket.md#onerror6)事件的回调。 16 17服务端:(目前服务端仅支持智慧屏使用)使用WebSocket建立服务器与客户端的双向连接,需要先通过[createWebSocketServer()](../reference/apis-network-kit/js-apis-webSocket.md#websocketcreatewebsocketserver19)方法创建[WebSocketServer](../reference/apis-network-kit/js-apis-webSocket.md#websocketserver19)对象,然后通过[start()](../reference/apis-network-kit/js-apis-webSocket.md#start19)方法启动服务器,监听客户端申请建链的消息。当连接成功后,服务端会收到[connect](../reference/apis-network-kit/js-apis-webSocket.md#onconnect19)事件的回调,之后服务端可以通过[send()](../reference/apis-network-kit/js-apis-webSocket.md#send19)方法与客户端进行通信,可以通过[listAllConnections()](../reference/apis-network-kit/js-apis-webSocket.md#listallconnections19)方法列举出当前与服务端建链的所有客户端信息。当客户端给服务端发消息时,服务端会收到[messageReceive](../reference/apis-network-kit/js-apis-webSocket.md#onmessagereceive19)事件回调。当服务端想断开某个与客户端的连接时,可以通过调用[close()](../reference/apis-network-kit/js-apis-webSocket.md#close19)方法主动断开与某个客户端的连接,之后服务端会收到[close](../reference/apis-network-kit/js-apis-webSocket.md#onclose19)事件的回调。当服务端想停止service时,可以调用[stop()](../reference/apis-network-kit/js-apis-webSocket.md#stop19)方法。若在上述任一过程中发生错误,服务端会收到[error](../reference/apis-network-kit/js-apis-webSocket.md#onerror19)事件的回调。 18 19> **说明:** 20> 21> websocket支持[心跳检测机制](https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.2),在客户端和服务端建立webSocket连接之后,从连接建立或者客户端收到Pong帧开始计时,每间隔pingInterval秒客户端会发送Ping帧给服务器。服务器若支持websocket协议则会在收到Ping帧后自动回复Pong帧,表示连接正常,若服务端异常或服务端不支持websocket协议则不会回复Pong帧;若Ping帧发出去后,pongTimeout秒内没有收到Pong帧,则会主动断开连接。支持开发者关闭心跳检测机制,自定义pingInterval与pongTimeout,详情请参考[WebsocketRequestOptions](../reference/apis-network-kit/js-apis-webSocket.md#websocketrequestoptions)。 22 23## client端开发步骤 24 251. 导入webSocket以及错误码模块。 26 27 ```js 28 import { webSocket } from '@kit.NetworkKit'; 29 import { BusinessError } from '@kit.BasicServicesKit'; 30 ``` 31 322. 创建WebSocket连接,返回一个WebSocket对象。 33 34 ```js 35 let defaultIpAddress = "ws://"; 36 let ws = webSocket.createWebSocket(); 37 ``` 38 393. 订阅WebSocket的打开、消息接收、关闭、Error事件(可选),当收到on('open')事件时,可以通过send()方法与服务器进行通信,当收到服务器的`bye`消息时(此消息字段仅为示意,具体字段需要与服务器协商),主动断开连接。。 40 41 ```js 42 ws.on('open', (err: BusinessError, value: Object) => { 43 console.log("on open, status:" + JSON.stringify(value)); 44 // 当收到on('open')事件时,可以通过send()方法与服务器进行通信。 45 ws.send("Hello, server!", (err: BusinessError, value: boolean) => { 46 if (!err) { 47 console.log("Message send successfully"); 48 } else { 49 console.error("Failed to send the message. Err:" + JSON.stringify(err)); 50 } 51 }); 52 }); 53 ws.on('message', (err: BusinessError, value: string | ArrayBuffer) => { 54 console.log("on message, message:" + value); 55 // 当收到服务器的`bye`消息时(此消息字段仅为示意,具体字段需要与服务器协商),主动断开连接。 56 if (value === 'bye') { 57 ws.close((err: BusinessError, value: boolean) => { 58 if (!err) { 59 console.log("Connection closed successfully"); 60 } else { 61 console.error("Failed to close the connection. Err: " + JSON.stringify(err)); 62 } 63 }); 64 } 65 }); 66 ws.on('close', (err: BusinessError, value: webSocket.CloseResult) => { 67 console.log("on close, code is " + value.code + ", reason is " + value.reason); 68 }); 69 ws.on('error', (err: BusinessError) => { 70 console.error("on error, error:" + JSON.stringify(err)); 71 }); 72 ``` 73 744. 根据URL地址,发起WebSocket连接。 75 76 ```js 77 ws.connect(defaultIpAddress, (err: BusinessError, value: boolean) => { 78 if (!err) { 79 console.log("Connected successfully"); 80 } else { 81 console.error("Connection failed. Err:" + JSON.stringify(err)); 82 } 83 }); 84 ``` 85 86## server端开发步骤 87 881. 导入webSocket以及错误码模块。 89 90 ```js 91 import { webSocket } from '@kit.NetworkKit'; 92 import { BusinessError } from '@kit.BasicServicesKit'; 93 ``` 94 952. 创建WebSocketServer对象。 96 97 ```js 98 let localServer: webSocket.WebSocketServer; 99 localServer = webSocket.createWebSocketServer(); 100 ``` 101 1023. 订阅WebSocketServer的客户端连接事件、消息接收事件、关闭事件、Error事件(可选),在收到客户端连接事件后,服务端可以通过send()方法与客户端进行通信,当收到客户端的"bye"消息时(此消息字段仅为示意,具体字段需要与客户端协商),主动断开连接。 103 104 ```js 105 localServer.on('connect', async (connection: webSocket.WebSocketConnection) => { 106 console.info(`New client connected! Client ip: ${connection.clientIP}, Client port: ${connection.clientPort}`); 107 // 当收到on('connect')事件时,可以通过send()方法与客户端进行通信。 108 localServer.send("Hello, I'm server!", connection).then((success: boolean) => { 109 if (success) { 110 console.info('message send successfully'); 111 } else { 112 console.error('message send failed'); 113 } 114 }).catch((error: BusinessError) => { 115 console.error(`message send failed, Code: ${error.code}, message: ${error.message}`); 116 }); 117 }); 118 119 localServer.on('messageReceive', (message: webSocket.WebSocketMessage) => { 120 try{ 121 console.info(`on message received, client: ${message.clientConnection}, data: ${message.data}`); 122 // 当收到客户端的"bye"消息时(此消息字段仅为示意,具体字段需要与客户端协商),主动断开连接。 123 if (message.data === 'bye') { 124 localServer.close(message.clientConnection).then((success: boolean) => { 125 if (success) { 126 console.info('close client successfully'); 127 } else { 128 console.error('close client failed'); 129 } 130 }); 131 } 132 } catch (error) { 133 console.error(`on messageReceive failed. Code: ${error.code}, message: ${error.message}`); 134 } 135 }); 136 137 localServer.on('close', (clientConnection: webSocket.WebSocketConnection, closeReason: webSocket.CloseResult) => { 138 console.info(`client close, client: ${clientConnection}, closeReason: Code: ${closeReason.code}, reason: ${closeReason.reason}`); 139 }); 140 141 localServer.on('error', (error: BusinessError) => { 142 console.error(`error. Code: ${error.code}, message: ${error.message}`); 143 }); 144 ``` 145 1464. 配置config参数启动server端服务。 147 148 ```js 149 let config: webSocket.WebSocketServerConfig = { 150 // 监听端口。 151 serverPort: 8080, 152 maxConcurrentClientsNumber: 10, 153 maxConnectionsForOneClient: 10, 154 } 155 localServer.start(config).then((success: boolean) => { 156 if (success) { 157 console.info('webSocket server start success'); 158 } else { 159 console.error('websocket server start failed'); 160 } 161 }).catch((error: BusinessError) => { 162 console.error(`Failed to start. Code: ${error.code}, message: ${error.message}`); 163 }); 164 ``` 165 1665. 服务端监听所有客户端连接状态(可选)。 167 168 ```js 169 let connections: webSocket.WebSocketConnection[] = []; 170 try { 171 connections = await localServer.listAllConnections(); 172 if (connections.length === 0) { 173 console.info('client list is empty'); 174 } else { 175 console.error(`client list cnt: ${connections.length}, client connections list is: ${connections}`); 176 } 177 } catch (error) { 178 console.error(`Failed to listAllConnections. Code: ${error.code}, message: ${error.message}`); 179 } 180 ``` 181 1826. 需要关闭WebSocketServer端服务器时,可以通过stop()停止服务。 183 184 ```js 185 localServer.stop().then((success: boolean) => { 186 if (success) { 187 console.info('server stop service successfully'); 188 } else { 189 console.error('server stop service failed'); 190 } 191 }); 192 ``` 193 194## 客户端完整示例 195 196**示例:** 197 198```js 199import { webSocket } from '@kit.NetworkKit'; 200import { BusinessError } from '@kit.BasicServicesKit'; 201 202let defaultIpAddress = "ws://"; 203let ws = webSocket.createWebSocket(); 204ws.on('open', (err: BusinessError, value: Object) => { 205 console.log("on open, status:" + JSON.stringify(value)); 206 // 当收到on('open')事件时,可以通过send()方法与服务器进行通信。 207 ws.send("Hello, server!", (err: BusinessError, value: boolean) => { 208 if (!err) { 209 console.log("Message send successfully"); 210 } else { 211 console.error("Failed to send the message. Err:" + JSON.stringify(err)); 212 } 213 }); 214}); 215ws.on('message', (err: BusinessError, value: string | ArrayBuffer) => { 216 console.log("on message, message:" + value); 217 // 当收到服务器的`bye`消息时(此消息字段仅为示意,具体字段需要与服务器协商),主动断开连接。 218 if (value === 'bye') { 219 ws.close((err: BusinessError, value: boolean) => { 220 if (!err) { 221 console.log("Connection closed successfully"); 222 } else { 223 console.error("Failed to close the connection. Err: " + JSON.stringify(err)); 224 } 225 }); 226 } 227}); 228ws.on('close', (err: BusinessError, value: webSocket.CloseResult) => { 229 console.log("on close, code is " + value.code + ", reason is " + value.reason); 230}); 231ws.on('error', (err: BusinessError) => { 232 console.error("on error, error:" + JSON.stringify(err)); 233}); 234ws.connect(defaultIpAddress, (err: BusinessError, value: boolean) => { 235 if (!err) { 236 console.log("Connected successfully"); 237 } else { 238 console.error("Connection failed. Err:" + JSON.stringify(err)); 239 } 240}); 241``` 242 243## server端完整示例 244 2451. 导入需要的webSocket模块。 246 2472. 创建一个WebSocketServer对象。 248 2493. (可选)订阅WebSocketServer的客户端连接事件、消息接收事件、关闭事件、Error事件。 250 2514. 配置config参数,通过start()启动server端服务。 252 2535. 通过WebSocketServer收发消息、监听事件等。 254 2556. 使用完WebSocketServer端服务器后,通过stop()停止服务。 256 257**示例:** 258 259```js 260import { webSocket } from '@kit.NetworkKit'; 261import { BusinessError } from '@kit.BasicServicesKit'; 262 263let connections: webSocket.WebSocketConnection[] = []; 264let localServer: webSocket.WebSocketServer; 265let config: webSocket.WebSocketServerConfig = { 266 // 监听端口。 267 serverPort: 8080, 268 maxConcurrentClientsNumber: 10, 269 maxConnectionsForOneClient: 10, 270} 271 272localServer = webSocket.createWebSocketServer(); 273 274localServer.on('connect', async (connection: webSocket.WebSocketConnection) => { 275 console.info(`New client connected! Client ip: ${connection.clientIP}, Client port: ${connection.clientPort}`); 276 // 当收到on('connect')事件时,可以通过send()方法与客户端进行通信。 277 localServer.send("Hello, I'm server!", connection).then((success: boolean) => { 278 if (success) { 279 console.info('message send successfully'); 280 } else { 281 console.error('message send failed'); 282 } 283 }).catch((error: BusinessError) => { 284 console.error(`message send failed, Code: ${error.code}, message: ${error.message}`); 285 }); 286 287 try { 288 connections = await localServer.listAllConnections(); 289 if (connections.length === 0) { 290 console.info('client list is empty'); 291 } else { 292 console.info(`client list cnt: ${connections.length}, client connections list is: ${connections}`); 293 } 294 } catch (error) { 295 console.error(`Failed to listAllConnections. Code: ${error.code}, message: ${error.message}`); 296 } 297}); 298 299localServer.on('messageReceive', (message: webSocket.WebSocketMessage) => { 300 try{ 301 console.info(`on message received, client: ${message.clientConnection}, data: ${message.data}`); 302 // 当收到客户端的"bye"消息时(此消息字段仅为示意,具体字段需要与客户端协商),主动断开连接。 303 if (message.data === 'bye') { 304 localServer.close(message.clientConnection).then((success: boolean) => { 305 if (success) { 306 console.info('close client successfully'); 307 } else { 308 console.error('close client failed'); 309 } 310 }); 311 } 312 } catch (error) { 313 console.error(`on messageReceive failed. Code: ${error.code}, message: ${error.message}`); 314 } 315}); 316 317localServer.on('close', (clientConnection: webSocket.WebSocketConnection, closeReason: webSocket.CloseResult) => { 318 console.info(`client close, client: ${clientConnection}, closeReason: Code: ${closeReason.code}, reason: ${closeReason.reason}`); 319}); 320 321localServer.on('error', (error: BusinessError) => { 322 console.error(`error. Code: ${error.code}, message: ${error.message}`); 323}); 324 325localServer.start(config).then((success: boolean) => { 326 if (success) { 327 console.info('webSocket server start success'); 328 } else { 329 console.error('websocket server start failed'); 330 } 331}).catch((error: BusinessError) => { 332 console.error(`Failed to start. Code: ${error.code}, message: ${error.message}`); 333}); 334 335localServer.stop().then((success: boolean) => { 336 if (success) { 337 console.info('server stop service successfully'); 338 } else { 339 console.error('server stop service failed'); 340 } 341}); 342``` 343 344## 相关实例 345 346针对WebSocket连接的开发,有以下相关实例可供参考: 347 348- [WebSocket(ArkTS)(API9)](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/Connectivity/WebSocket) 349 350- [WebSocket连接](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/DocsSample/NetWork_Kit/NetWorkKit_Datatransmission/WebSocket_case) 351