积分584 / 贡献0

提问0答案被采纳0文章52

[经验分享] OpenHarmony_WebSocket连接 原创

Laval社区小助手 显示全部楼层 发表于 2024-7-5 14:58:24

前言

WebSocket是一种在单个TCP连接上进行全双工通信的协议,于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。WebSocket与Http相比具有更强的实时性和压缩效果、更好的二进制支持、较少的控制开销,并能够保持连接状态。

WebSocket介绍

在OpenHarmony中,WebSocket连接功能主要由@ohos.net.webSocket模块提供。使用该功能需要申请ohos.permission.INTERNET权限。

接口说明

接口名 功能描述
createWebSocket() 创建一个WebSocket对象,该对象里面包括了建立/关闭连接、发送数据、订阅/取消WebSocket连接的打开事件、接收到服务器消息事件、关闭事件、错误事件 等一系列方法
connect() 根据URL地址,建立一个WebSocket连接,使用callback和promise方式进行异步回调
send() 通过WebSocket连接发送数据,使用callback和promise方式进行异步回调
close() 关闭WebSocket连接, 使用callback和promise方式进行异步回调
on(type: 'open') 订阅WebSocket的打开事件,使用callback方式进行异步回调
off(type: 'open') 取消订阅WebSocket的打开事件,使用callback方式进行异步回调
on(type: 'message') 订阅WebSocket的接收到服务器消息事件,使用callback方式进行异步回调
off(type: 'message') 取消订阅WebSocket的接收到服务器消息事件,使用callback方式进行异步回调
on(type: 'close') 订阅WebSocket的关闭事件 ,使用callback方式进行异步回调
off(type: 'close') 取消订阅WebSocket的关闭事件,使用callback方式进行异步回调
on(type: 'error') 订阅WebSocket的Error事件,使用callback方式进行异步回调
off(type: 'error') 取消订阅WebSocket的Error事件,使用callback方式进行异步回调

使用场景介绍

要实现WebSocket建立服务器与客户端的双向连接,需要先通过createWebSocket()方法创建WebSocket对象,然后通过connect()方法连接到服务器。当连接成功后,客户端会收到open事件的回调,之后客户端就可以通过send()方法与服务器进行通信。当服务器发信息给客户端时,客户端会收到message事件的回调。当客户端不要此连接时,可以通过调用close()方法主动断开连接,之后客户端会收到close事件的回调。若在上述任一过程中发生错误,客户端会收到error事件的回调。

开发步骤

  • 导入@ohos.net.webSocket模块
  • 创建WebSocket对象
  • (可选)订阅WebSocket的打开、消息接收、关闭、Error事件
  • 根据URL地址,发起WebSocket连接,与服务器进行通信
  • 使用完WebSocket连接之后,主动断开连接

WebSocket连接示例

目标

使用webSocket模块相关接口与服务器进行双向通信

开发环境

示例开发环境:

IDE: DevEco Studio 3.0 Release(build:3.0.0.993)
SDK: Api Version9
开发模型:Stage

具体实现

创建工程

打开DevEco Studio,创建SDK版本为API9、模型为Stage的OpenHarmony项目。工程目录结构如下:

配置权限

在工程中的module.json5文件中配置ohos.permission.INTERNET 权限。

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

包装WebSocket接口

在ets/service目录下创建SocketService.ets文件。为了方便在UI页面中调用WebSocket相关的功能,在该文件中定义SocketService类对WebSocket相关接口进行包装。

SocketService.ets:

import webSocket from '@ohos.net.webSocket';
import Logger from '../util/logger'

const TAG = "WebSocketDemo"

export class SocketService {
  private socket: webSocket.WebSocket ;
  private messageCallback: MessageCallback;

  constructor() {
    this.createWebSocket();
    this.onOpen();
    this.onMessage();
    this.onClose();
    this.onError();
  }

  /**
   * 注册监听器,对服务端发送的消息进行处理
   * @param messageListener
   */
  public registerMessageListener(messageCallback: MessageCallback) {
    this.messageCallback = messageCallback;
  }

  /**
   * 创建WebSocket对象,该对象负责有服务端进行通信
   */
  private createWebSocket() {
    Logger.info(TAG, "start create websocket");
    this.socket = webSocket.createWebSocket();
    Logger.info(TAG, "create socket sucess");
  }

  /**
   * 根据指定的url与服务器进行连接
   * @param url 协议格式 ws://或wss://
   */
  public connect(url: string) {
    this.socket.connect(url)
      .then((isConnect) => {
        if (isConnect) {
          Logger.info(TAG, "connect sucess");
        }
      })
  }

  /**
   * 连接成功后,向服务端发送消息
   * @param data
   */
  public sendMessage(data: string) {
    this.socket.send(data)
      .then((isSucess) => {
        Logger.info(TAG, "send result:" + isSucess);
        if (isSucess) {
          Logger.info(TAG, "send message sucess")
        }
      })
      .catch((e) => {
        Logger.info(TAG, "send message fail:" + JSON.stringify(e))
      })
  }

  /**
   * 主动与服务器断开连接
   */
  public closeConnect() {
    this.socket.close();
  }

  /**
   * 监听连接打开的事件,当与服务端的连接打开时触发回调
   *
   *
   */
  private onOpen() {
    this.socket.on("open", (err, data) => {
      Logger.info(TAG, "on open status" + JSON.stringify(data));
    })
  }

  /**
   * 监听服务器发送消息的事件,当服务器向客户端发送消息时触发回调
   *
   */
  private onMessage() {
    this.socket.on("message", (err, data) => {
      Logger.info(TAG, "receive from server:message is:" + JSON.stringify(data));
      this.messageCallback && this.messageCallback(data);
    })
  }

  /**
   *
   * 监听连接断开事件,当与服务器断开连接时触发回调
   */
  private onClose() {
    this.socket.on("close", (err, data) => {
      Logger.info(TAG, "on close :close code is:" + data.code + ",close reason is:" + data.reason);
    })
  }

  /**
   *监听err事件,只要在建立连接、发送数据等任意过程中发生错误,都会触发回调
   *
   */
  private onError() {
    this.socket.on("error", (data) => {
      Logger.info(TAG, "on err :err is" + JSON.stringify(data));
    })
  }
}


interface MessageCallback {
  (data: Object): void;
}

let socketService = new SocketService();

export default socketService

创建请求界面

在ets/pages目录下创建建index.ets文件,使用Flex、TextInput、Text等组件构建一个简易的WebSocket客户端页面,导入SocketService对象进行WebSocket通信操作。

index.ets:

import socketService from '../service/SocketService'
import prompt from '@ohos.prompt';

@Entry
@Component
struct Index {

  /**
   * 请求地址,以ws/wss开头,默认地址为:wss://s2.ripple.com:443
   */
  url: string = "wss://s2.ripple.com:443";
  /**
   * 需要向服务端发送的数据,这里发送一个JSON的字符串
   */
  message: string = JSON.stringify({
    "id": 1,
    "command": "account_info",
    "account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
  });

  build() {
    Flex({ direction: FlexDirection.Column }) {
      Column() {
        Row() {
          Text("URL:")
            .fontSize(25)
            .fontColor(Color.Blue)
          TextInput()
            .fontSize(25)
            .fontWeight(FontWeight.Bold)
            .onChange((value) => {
              this.url = value;
            })
        }
        .margin({ top: 5, bottom: 5 })

        Button("开始连接")
          .width("60%")
          .fontSize(25)
          .onClick(() => {
            socketService.connect(this.url);
          })

      }
      .border({ width: 1, color: Color.Red })


      Column() {
        Row() {
          Text("DATA:")
            .fontSize(25)
            .fontColor(Color.Blue)
          TextInput()
            .fontSize(25)
            .fontWeight(FontWeight.Bold)
            .onChange((value) => {
              this.message = value;
            })
        }
        .margin({ top: 5, bottom: 5 })

        Button("发送")
          .width("60%")
          .fontSize(25)
          .onClick(() => {
            socketService.sendMessage(this.message);
          })
      }
      .margin({ top: 25 })
      .border({ width: 1, color: Color.Green })

      Column() {
        Button("断开连接")
          .width("60%")
          .fontSize(25)
          .onClick(() => {
            socketService.closeConnect();
          })
      }
      .margin({ top: 25 })

    }
    .width("100%")
    .height("100%")
  }

  /**
   * 在声明周期aboutToAppear中注册消息监听器
   * @param data
   */
  aboutToAppear() {
    socketService.registerMessageListener((data) => {
      prompt.showDialog({ message: "服务端发来消息:" + JSON.stringify(data) });
    })
  }
}

效果预览如下:

测试结果

开发板型号:WAGNER

OH版本:3.2.5.5

测试服务器url: wss://s2.ripple.com:443

发送的数据:

{
 "id": 1,
 "command": "account_info",
 "account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
}

日志打印:

08-03 17:07:47.421  8160  8160 I 02200/JsApp: WebSocketDemo: start create websocket
08-03 17:07:47.421  8160  8160 I 02200/JsApp: WebSocketDemo: create socket sucess

 //连接成功
08-03 17:07:58.176  8160  8160 I 02200/JsApp: WebSocketDemo: connect sucess
08-03 17:07:59.614  8160  8160 I 02200/JsApp: WebSocketDemo: on open status{"status":101,"message":""}
08-03 17:08:03.053  8160  8160 I 02200/JsApp: WebSocketDemo: send result:true

//成功发送消息
08-03 17:08:03.053  8160  8160 I 02200/JsApp: WebSocketDemo: send message sucess 

//服务端返回的数据
08-03 17:08:04.124  8160  8160 I 02200/JsApp: WebSocketDemo: receive from server:message is:"{\"id\":1,\"result\":{\"account_data\":{\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"Balance\":\"1331561
2686\",\"Flags\":0,\"LedgerEntryType\":\"AccountRoot\",\"OwnerCount\":17,\"PreviousTxnID\":\"02059D06C1A5AFDA5712FD3B9B7F6B48A3B7DA0D6D38D457BEC357BC180910C0\",\"PreviousTxnLgrSeq\":66854742,\"Sequenc
e\":1406,\"index\":\"4F83A2CF7E70F77F79A307E6A472BFC2585B806A70833CCD1C26105BAE0D6E05\"},\"ledger_hash\":\"6FF8D9EE2A3340FB01BC630D52994D9B1B8EA8FCF77014BFFB3E6E086982ADA1\",\"ledger_index\":73440377,
\"validated\":true,\"warnings\":[{\"id\":1004,\"message\":\"This is a reporting server.  The default behavior of a reporting server is to only return validated data. If you are looking for not yet val
idated data, include \\\"ledger_index : current\\\" in your request, which will cause this server to forward the request to a p2p node. If the forward is successful the response will include \\\"forwa
rded\\\" : \\\"true\\\"\"}]},\"status\":\"success\",\"type\":\"respon

//连接断开
08-03 17:08:08.016  8160  8160 I 02200/JsApp: WebSocketDemo: on close :close code is:1000,close reason is:

参考文献

[1] 应用权限列表. https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md

[2] 使用ArkTS语言开发(Stage模型). https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets-stage.md

[3] WebSocket连接. https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-webSocket.md

[4] WebSocket连接示例. https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/connectivity/websocket-connection.md

[5] WebSocket介绍-百度百科. https://baike.baidu.com/item/WebSocket/1953845?fr=aladdin

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部