[ArkTS]实现WebSocket Client 与后台通信

265 阅读4分钟

​ 随着 HarmonyOS Next  系统的不断发展与应用拓展,开发高效、稳定的网络通信功能变得愈发重要。WebSocket 作为一种基于 TCP 协议的网络通信协议,能够在客户端和服务器之间实现双向通信,在实时性要求较高的应用场景中有着广泛的应用。本文将介绍如何在HarmonyOS Next 环境下,利用 ArkTs&ArkUI 框架构建 WebSocket 客户端,并搭配 Node.js 搭建的后台服务器来实现简单的消息交互功能,展示完整的代码实现过程及效果。

客户端-ArkTs&ArkUI

配置网络权限

在src下的module.json5里加入权限:

    "requestPermissions": [
      { "name": "ohos.permission.INTERNET" },
      ],

使用ArkTS自带的WebSocket API

import { webSocket } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';

创建WebSocket实例

  defaultIpAddress: string = 'ws://xx.xx.xx.xx:8080';//后台服务器端口为8080
  ws = webSocket.createWebSocket();

处理WebSocket事件  

1.open 事件

  • 触发时机:连接成功时。

  • 回调参数

    • err:错误信息,如果没有错误则为 null
    • value:连接成功后的信息对象,通常是空对象或包含一些连接的元数据。
    this.ws.on('open', (err: BusinessError, value: Object) => {
      if (!err) {
        this.addMessage('连接成功!');
      } else {
        this.addMessage('连接失败:' + JSON.stringify(err));
      }
    });

2. message 事件

  • 触发时机:当收到服务器的消息时。

  • 回调参数

    • err:错误信息,如果没有错误则为 null
    • value:服务器返回的消息,类型可能是 stringArrayBuffer,表示接收到的消息内容。
    this.ws.on('message', (err: BusinessError, value: string | ArrayBuffer) => {
      if (!err && typeof value === 'string') {
        this.addMessage('服务器: ' + value);
      } else {
        this.addMessage('接收消息错误: ' + JSON.stringify(err));
      }
    });

3. close 事件

  • 触发时机:当 WebSocket 连接关闭时(无论是正常关闭还是异常关闭)。

  • 回调参数

    • err:错误信息,如果没有错误则为 null
    • value:关闭连接时的结果,通常包含 codereason,描述关闭的原因和状态码。
    this.ws.on('close', (err: BusinessError, value: webSocket.CloseResult) => {
      if (!err) {
        this.addMessage(`连接关闭,代码: ${value.code}, 原因: ${value.reason}`);
      } else {
        this.addMessage('关闭连接错误: ' + JSON.stringify(err));
      }
    });

4. error 事件

  • 触发时机:发生 WebSocket 错误时。

  • 回调参数

    • err:错误信息,描述错误的具体内容。
  this.ws.on('error', (err: BusinessError) => {
      this.addMessage('WebSocket 错误: ' + JSON.stringify(err));
    });

5.connect事件

  • 触发时机:客户端主动发起连接。

  • 回调参数

    • err:错误信息,描述错误的具体内容。
    • value:连接成功的结果,通常包含 codereason,描述结果和状态码。
    this.ws.connect(this.defaultIpAddress, (err: BusinessError, value: boolean) => {
      if (err) {
        this.addMessage('无法连接到服务器: ' + JSON.stringify(err));
      }
    });

 创建UI:

 build() {
    Row(){
      Column() {
        List(){
          ForEach(this.messages, (item: string) => {
            ListItem(){
              Text(item)
                .fontSize(20)
                .padding(10);
            }
          })
        }
        .width('100%')
        .height('90%');
        Row() {
          TextInput({
            placeholder:"输入消息",
            controller:this.controller,
            text:this.inputMessage
            })
            .onChange((value) => {
              this.inputMessage = value;
            })
            .width('70%')
            .height(40);

          Button("发送")
            .onClick(() => {
              if (this.inputMessage.trim()) {
                this.sendMessage();
              }
            })
            .width('20%')
            .height(40)
            .margin({ left: 10 });
        }
        .width('100%')
        .height('15%')
        .margin({ top: 10 });
      }
      .padding(10);
    }
  }

总代码:

import { webSocket } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct Index {
  @State messages: string[] = [];
  @State inputMessage: string = '';
  defaultIpAddress: string = 'ws://10.23.102.19:8080';
  ws = webSocket.createWebSocket();
  controller: TextInputController = new TextInputController();

  build() {
    Row(){
      Column() {
        List(){
          ForEach(this.messages, (item: string) => {
            ListItem(){
              Text(item)
                .fontSize(20)
                .padding(10);
            }
          })
        }
        .width('100%')
        .height('90%');
        Row() {
          TextInput({
            placeholder:"输入消息",
            controller:this.controller,
            text:this.inputMessage
            })
            .onChange((value) => {
              this.inputMessage = value;
            })
            .width('70%')
            .height(40);

          Button("发送")
            .onClick(() => {
              if (this.inputMessage.trim()) {
                this.sendMessage();
              }
            })
            .width('20%')
            .height(40)
            .margin({ left: 10 });
        }
        .width('100%')
        .height('15%')
        .margin({ top: 10 });
      }
      .padding(10);
    }
  }

  aboutToAppear() :void{
    this.connectWebSocket();
  }

  onDisappear() {
    this.closeWebSocket();
  }


   connectWebSocket() {
    this.ws.on('open', (err: BusinessError, value: Object) => {
      if (!err) {
        this.addMessage('连接成功!');
      } else {
        this.addMessage('连接失败:' + JSON.stringify(err));
      }
    });

    this.ws.on('message', (err: BusinessError, value: string | ArrayBuffer) => {
      if (!err && typeof value === 'string') {
        this.addMessage('服务器: ' + value);
      } else {
        this.addMessage('接收消息错误: ' + JSON.stringify(err));
      }
    });

    this.ws.on('close', (err: BusinessError, value: webSocket.CloseResult) => {
      if (!err) {
        this.addMessage(`连接关闭,代码: ${value.code}, 原因: ${value.reason}`);
      } else {
        this.addMessage('关闭连接错误: ' + JSON.stringify(err));
      }
    });

    this.ws.on('error', (err: BusinessError) => {
      this.addMessage('WebSocket 错误: ' + JSON.stringify(err));
    });

    this.ws.connect(this.defaultIpAddress, (err: BusinessError, value: boolean) => {
      if (err) {
        this.addMessage('无法连接到服务器: ' + JSON.stringify(err));
      }
    });
  }

  closeWebSocket() {
    if (this.ws) {
      this.ws.close((err: BusinessError, value: boolean) => {
        if (!err) {
          this.addMessage('WebSocket 连接已关闭');
        } else {
          this.addMessage('关闭 WebSocket 失败: ' + JSON.stringify(err));
        }
      });
    }
  }

  // 发送消息
  sendMessage() {
    if (this.inputMessage.trim() === '') {
      this.addMessage('请先输入消息');
      return;
    }

    const message = this.inputMessage;
    this.inputMessage = ''; // 清空输入框
    this.ws.send(message, (err: BusinessError, value: boolean) => {
      if (!err) {
        this.addMessage('我: ' + message);
      } else {
        this.addMessage('消息发送失败: ' + JSON.stringify(err));
      }
    });
  }

  // 添加消息到列表
  addMessage(msg: string) {
    this.messages = [...this.messages, msg];
  }
}

后台创建

用Node.js 快速构建

安装WebSocket模块:

npm install ws

后台代码:

const WebSocket = require('ws');

// 创建一个 WebSocket 服务器
const wss = new WebSocket.Server({ port: 8080 });

console.log('WebSocket 服务器正在运行,监听端口 8080');

// 监听客户端连接
wss.on('connection', (ws) => {
    console.log('客户端已连接');

    // 监听客户端发送的消息
    ws.on('message', (message) => {
        console.log(`收到客户端消息: ${message}`);
        
        // 向客户端发送回执消息
        ws.send(`服务端收到: ${message}`);
    });

    // 处理连接关闭
    ws.on('close', () => {
        console.log('客户端已断开连接');
    });

    // 处理错误
    ws.on('error', (error) => {
        console.error(`WebSocket 错误: ${error.message}`);
    });

    // 发送欢迎消息
    ws.send('欢迎连接到 WebSocket 服务器');
});

效果展示: