深入浅出学习eTs之TCP聊天的功能实现

描述

一、需求分析

UDP

本章节我们来实现一个TCP聊天的功能

连接指定IP和端口

显示接收的内容

具有发送的功能

二、控件介绍

(1)Socket连接

场景介绍

应用通过Socket进行数据传输,支持TCP和UDP两种协议。

接口说明

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

接口名 功能描述
constructUDPSocketInstance() 创建一个UDPSocket对象。
constructTCPSocketInstance() 创建一个TCPSocket对象。
bind() 绑定IP地址和端口。
send() 发送数据。
close() 关闭连接。
getState() 获取Socket状态。
connect() 连接到指定的IP地址和端口(仅TCP支持)
getRemoteAddress() 获取对端Socket地址(仅TCP支持,需要先调用connect方法)
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’) 订阅TCPSocket的连接事件(仅TCP支持)。
off(type: ‘connect’) 取消订阅TCPSocket的连接事件(仅TCP支持)。

基本例程(参考我之前的家庭医生终端系统)

import socket from '@ohos.net.socket';
let tcp = socket.constructTCPSocketInstance();

tcp.bind({address: '0.0.0.0', port: 12121, family: 1}, err => {
  if (err) {
    console.log('bind fail');
    return;
  }
  console.log('bind success');
})

tcp.on('message', value => {
  console.log("on message, message:" + value.message + ", remoteInfo:" + value.remoteInfo)
  let da = resolveArrayBuffer(value.message);
  let dat_buff = String(da);
//此处对接受到的数据进行处理


});
//将接受到的数据转化为文本型           
function resolveArrayBuffer(message){

  if (message instanceof ArrayBuffer) {
    let dataView = new DataView(message)
    let str = ""
    for (let i = 0;i < dataView.byteLength; ++i) {
      let c = String.fromCharCode(dataView.getUint8(i))
      if (c !== "n") {
        str += c
      }
    }
    return str;
  }
}
//数据的发送函数
function send_once(Con_buff) {
  if (flag == false) {

    let promise = tcp.connect({ address: { address: 'xxx.xxx.xxx.xxx', port: xxxx, family: 1 }, timeout: 2000 });
    promise.then(() => {
      console.log('connect success');
      flag = true;
      tcp.send({
        data: Con_buff
      }, err => {
        if (err) {
          console.log('send fail');
          return;
        }
        console.log('send success');
      })
    }).catch(err => {
      console.log('connect fail');
    });

  } else if (flag == true) {
    tcp.send({
      data: Con_buff
    }, err => {
      if (err) {
        console.log('send fail');
        return;
      }
      console.log('send success');
    })
  }
}

(2)AppStorage与组件同步

在管理组件拥有的状态中,已经定义了如何将组件的状态变量与父组件或祖先组件中的@State装饰的状态变量同步,主要包括@Prop、@Link、@Consume。

本章节定义如何将组件变量与AppStorage同步,主要提供@StorageLink和@StorageProp装饰器。

@StorageLink装饰器

组件通过使用@StorageLink(key)装饰的状态变量,与AppStorage建立双向数据绑定,key为AppStorage中的属性键值。当创建包含@StorageLink的状态变量的组件时,该状态变量的值将使用AppStorage中的值进行初始化。在UI组件中对@StorageLink的状态变量所做的更改将同步到AppStorage,并从AppStorage同步到任何其他绑定实例中,如PersistentStorage或其他绑定的UI组件。

@StorageProp装饰器

组件通过使用@StorageProp(key)装饰的状态变量,将与AppStorage建立单向数据绑定,key标识AppStorage中的属性键值。当创建包含@StoageProp的状态变量的组件时,该状态变量的值将使用AppStorage中的值进行初始化。AppStorage中的属性值的更改会导致绑定的UI组件进行状态更新。

let varA = AppStorage.Link('varA')
let envLang = AppStorage.Prop('languageCode')
@Entry
@Component
struct ComponentA {
  @StorageLink('varA') varA: number = 2
  @StorageProp('languageCode') lang: string = 'en'
  private label: string = 'count'

  private aboutToAppear() {
    this.label = (this.lang === 'zh') ? '数' : 'Count'
  }

  build() {
    Row({ space: 20 }) {

      Button(`${this.label}: ${this.varA}`)
        .onClick(() => {
          AppStorage.Set('varA', AppStorage.Get('varA') + 1)
        })
      Button(`lang: ${this.lang}`)
        .onClick(() => {
          if (this.lang === 'zh') {
            AppStorage.Set('languageCode', 'en')
          } else {
            AppStorage.Set('languageCode', 'zh')
          }
          this.label = (this.lang === 'zh') ? '数' : 'Count'
        })
    }
  }
}

即通过AppStorage.Link和 @StorageLink的方式,可实现外部动态刷新Text组件和image组件(等等之类都可以),方便我们在全局调用时更新数据。

三、UI设计

本项目的基本内容是可以在预览器中看到的,所以先在预览器中简单设计UI

(1)基本界面

UDP

以后不会大时间讲解UI了,会直接放成品,且我的源码都在Gitee仓上存在,需要的可以自己下载,会着重体现程序部分

(2)接口绑定

首先是接收框处的变量绑定

let Rc_message = AppStorage.Link('Rc_message')
@StorageLink('Rc_message') Rc_message: String = '收到消息'
      Text(`${this.Rc_message}`)
        .width("98%")
        .height("35%")
        .borderStyle(BorderStyle.Solid).borderWidth(8).borderColor(0xAFEEEE).borderRadius(20)
        .fontSize(25)

(3)TCP回调设置

tcp.on('message', value => {
  console.log("on message, message:" + value.message + ", remoteInfo:" + value.remoteInfo)
  let da = resolveArrayBuffer(value.message);
  let dat_buff = String(da);
  AppStorage.Set('Rc_message',dat_buff);
//AppStorage.Set('ID_1_stata','rgba(0, 109, 229, 0.95)');
});

 

该部分实现聊天框内部的文字刷新

(4)IP设置

这里我是使用的合宙的TCP工具[wstool (luatos.com)](
 

UDP

在此处修改IP和端口
 

UDP

(5)远端模拟器

UDP

在模拟器中打开如上

四、实际测试

UDP

使用模拟器进行发送
 

UDP

在TCP工具处有接收到内容,此时进行回复
 

UDP

在APP端可以接收到并显示(暂时可能只支持英文接受显示)
 

UDP


 

UDP


 

UDP

五、动态图

UDP

TCP助手显示如下
 

UDP


编辑:黄飞

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分