一、需求分析

本章節(jié)我們來(lái)實(shí)現(xiàn)一個(gè)TCP聊天的功能
連接指定IP和端口
顯示接收的內(nèi)容
具有發(fā)送的功能
二、控件介紹
(1)Socket連接
場(chǎng)景介紹
應(yīng)用通過(guò)Socket進(jìn)行數(shù)據(jù)傳輸,支持TCP和UDP兩種協(xié)議。
接口說(shuō)明
Socket連接主要由socket模塊提供。具體接口說(shuō)明如下表。
| 接口名 | 功能描述 |
|---|---|
| constructUDPSocketInstance() | 創(chuàng)建一個(gè)UDPSocket對(duì)象。 |
| constructTCPSocketInstance() | 創(chuàng)建一個(gè)TCPSocket對(duì)象。 |
| bind() | 綁定IP地址和端口。 |
| send() | 發(fā)送數(shù)據(jù)。 |
| close() | 關(guān)閉連接。 |
| getState() | 獲取Socket狀態(tài)。 |
| connect() | 連接到指定的IP地址和端口(僅TCP支持) |
| getRemoteAddress() | 獲取對(duì)端Socket地址(僅TCP支持,需要先調(diào)用connect方法) |
| on(type: ‘message’) | 訂閱Socket連接的接收消息事件。 |
| off(type: ‘message’) | 取消訂閱Socket連接的接收消息事件。 |
| on(type: ‘close’) | 訂閱Socket連接的關(guān)閉事件。 |
| off(type: ‘close’) | 取消訂閱Socket連接的關(guān)閉事件。 |
| on(type: ‘error’) | 訂閱Socket連接的Error事件。 |
| off(type: ‘error’) | 取消訂閱Socket連接的Error事件。 |
| on(type: ‘listening’) | 訂閱UDPSocket連接的數(shù)據(jù)包消息事件(僅UDP支持)。 |
| off(type: ‘listening’) | 取消訂閱UDPSocket連接的數(shù)據(jù)包消息事件(僅UDP支持)。 |
| on(type: ‘connect’) | 訂閱TCPSocket的連接事件(僅TCP支持)。 |
| off(type: ‘connect’) | 取消訂閱TCPSocket的連接事件(僅TCP支持)。 |
基本例程(參考我之前的家庭醫(yī)生終端系統(tǒng))
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);
//此處對(duì)接受到的數(shù)據(jù)進(jìn)行處理
});
//將接受到的數(shù)據(jù)轉(zhuǎn)化為文本型
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;
}
}
//數(shù)據(jù)的發(fā)送函數(shù)
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與組件同步
在管理組件擁有的狀態(tài)中,已經(jīng)定義了如何將組件的狀態(tài)變量與父組件或祖先組件中的@State裝飾的狀態(tài)變量同步,主要包括@Prop、@Link、@Consume。
本章節(jié)定義如何將組件變量與AppStorage同步,主要提供@StorageLink和@StorageProp裝飾器。
@StorageLink裝飾器
組件通過(guò)使用@StorageLink(key)裝飾的狀態(tài)變量,與AppStorage建立雙向數(shù)據(jù)綁定,key為AppStorage中的屬性鍵值。當(dāng)創(chuàng)建包含@StorageLink的狀態(tài)變量的組件時(shí),該狀態(tài)變量的值將使用AppStorage中的值進(jìn)行初始化。在UI組件中對(duì)@StorageLink的狀態(tài)變量所做的更改將同步到AppStorage,并從AppStorage同步到任何其他綁定實(shí)例中,如PersistentStorage或其他綁定的UI組件。
@StorageProp裝飾器
組件通過(guò)使用@StorageProp(key)裝飾的狀態(tài)變量,將與AppStorage建立單向數(shù)據(jù)綁定,key標(biāo)識(shí)AppStorage中的屬性鍵值。當(dāng)創(chuàng)建包含@StoageProp的狀態(tài)變量的組件時(shí),該狀態(tài)變量的值將使用AppStorage中的值進(jìn)行初始化。AppStorage中的屬性值的更改會(huì)導(dǎo)致綁定的UI組件進(jìn)行狀態(tài)更新。
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') ? '數(shù)' : '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') ? '數(shù)' : 'Count'
})
}
}
}
即通過(guò)AppStorage.Link和 @StorageLink的方式,可實(shí)現(xiàn)外部動(dòng)態(tài)刷新Text組件和image組件(等等之類都可以),方便我們?cè)谌终{(diào)用時(shí)更新數(shù)據(jù)。
三、UI設(shè)計(jì)
本項(xiàng)目的基本內(nèi)容是可以在預(yù)覽器中看到的,所以先在預(yù)覽器中簡(jiǎn)單設(shè)計(jì)UI
(1)基本界面

以后不會(huì)大時(shí)間講解UI了,會(huì)直接放成品,且我的源碼都在Gitee倉(cāng)上存在,需要的可以自己下載,會(huì)著重體現(xiàn)程序部分
(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回調(diào)設(shè)置
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)');
});
該部分實(shí)現(xiàn)聊天框內(nèi)部的文字刷新
(4)IP設(shè)置
這里我是使用的合宙的TCP工具[wstool (luatos.com)](

在此處修改IP和端口

(5)遠(yuǎn)端模擬器

在模擬器中打開如上
四、實(shí)際測(cè)試

使用模擬器進(jìn)行發(fā)送

在TCP工具處有接收到內(nèi)容,此時(shí)進(jìn)行回復(fù)

在APP端可以接收到并顯示(暫時(shí)可能只支持英文接受顯示)



五、動(dòng)態(tài)圖

TCP助手顯示如下

編輯:黃飛
-
TCP
+關(guān)注
關(guān)注
8文章
1425瀏覽量
83516 -
UDP
+關(guān)注
關(guān)注
0文章
334瀏覽量
35419 -
ets
+關(guān)注
關(guān)注
0文章
20瀏覽量
1938 -
OpenHarmony
+關(guān)注
關(guān)注
33文章
3952瀏覽量
21103
發(fā)布評(píng)論請(qǐng)先 登錄
#深入淺出學(xué)習(xí)eTs#(八)“猜大小”小游戲
#深入淺出學(xué)習(xí)eTs#(十)藍(lán)藥丸還是紅藥丸
#深入淺出學(xué)習(xí)eTs#(六)編寫eTs第一個(gè)控件
#深入淺出學(xué)習(xí)eTs#(七)判斷密碼是否正確
#深入淺出學(xué)習(xí)eTs#(十九)TCP聊天室
深入淺出學(xué)習(xí)eTs(一)模擬器/真機(jī)環(huán)境搭建
深入淺出學(xué)習(xí)eTs(七)如何判斷密碼是否正確
深入淺出學(xué)習(xí)eTs之九宮格密碼鎖功能實(shí)現(xiàn)
深入淺出學(xué)習(xí)eTs之TCP聊天的功能實(shí)現(xiàn)
評(píng)論