> 技术文档 > 开源 Arkts 鸿蒙应用 开发(九)通讯--tcp客户端

开源 Arkts 鸿蒙应用 开发(九)通讯--tcp客户端

  文章的目的为了记录使用Arkts 进行Harmony app 开发学习的经历。本职为嵌入式软件开发,公司安排开发app,临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

 相关链接:

开源 Arkts 鸿蒙应用 开发(一)工程文件分析-CSDN博客

开源 Arkts 鸿蒙应用 开发(二)封装库.har制作和应用-CSDN博客

开源 Arkts 鸿蒙应用 开发(三)Arkts的介绍-CSDN博客

开源 Arkts 鸿蒙应用 开发(四)布局和常用控件-CSDN博客

开源 Arkts 鸿蒙应用 开发(五)控件组成和复杂控件-CSDN博客

开源 Arkts 鸿蒙应用 开发(六)数据持久--文件和首选项存储-CSDN博客

开源 Arkts 鸿蒙应用 开发(七)数据持久--sqlite关系数据库-CSDN博客

开源 Arkts 鸿蒙应用 开发(八)多媒体--相册和相机-CSDN博客

开源 Arkts 鸿蒙应用 开发(九)通讯--tcp客户端-CSDN博客

开源 Arkts 鸿蒙应用 开发(十)通讯--Http数据传输-CSDN博客

 推荐链接:

开源 java android app 开发(一)开发环境的搭建-CSDN博客

开源 java android app 开发(二)工程文件结构-CSDN博客

开源 java android app 开发(三)GUI界面布局和常用组件-CSDN博客

开源 java android app 开发(四)GUI界面重要组件-CSDN博客

开源 java android app 开发(五)文件和数据库存储-CSDN博客

开源 java android app 开发(六)多媒体使用-CSDN博客

开源 java android app 开发(七)通讯之Tcp和Http-CSDN博客

开源 java android app 开发(八)通讯之Mqtt和Ble-CSDN博客

开源 java android app 开发(九)后台之线程和服务-CSDN博客

开源 java android app 开发(十)广播机制-CSDN博客

开源 java android app 开发(十一)调试、发布-CSDN博客

开源 java android app 开发(十二)封库.aar-CSDN博客

推荐链接:

开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客

开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客

开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客

开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-CSDN博客

开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客

本章内容主要是演示鸿蒙的tcp客户端的通讯:

实现TCP客户端功能,可以连接指定IP和端口的服务器。支持发送和接收文本消息,显示连接状态和通信历史。

新建DevEco的工程,选择Empty Ability,只需要修改module.json5,和Index.ets文件,就可以实现TCP客户端的APP。

一、设置权限,修改module.json5文件。

文件位置

module.json5代码

{ \"module\": { \"name\": \"entry\", \"type\": \"entry\", \"description\": \"$string:module_desc\", \"mainElement\": \"EntryAbility\", \"deviceTypes\": [ \"phone\" ], \"deliveryWithInstall\": true, \"installationFree\": false, \"pages\": \"$profile:main_pages\", \"abilities\": [ { \"name\": \"EntryAbility\", \"srcEntry\": \"./ets/entryability/EntryAbility.ets\", \"description\": \"$string:EntryAbility_desc\", \"icon\": \"$media:layered_image\", \"label\": \"$string:EntryAbility_label\", \"startWindowIcon\": \"$media:startIcon\", \"startWindowBackground\": \"$color:start_window_background\", \"exported\": true, \"skills\": [ { \"entities\": [  \"entity.system.home\" ], \"actions\": [  \"action.system.home\" ] } ] } ], \"extensionAbilities\": [ { \"name\": \"EntryBackupAbility\", \"srcEntry\": \"./ets/entrybackupability/EntryBackupAbility.ets\", \"type\": \"backup\", \"exported\": false, \"metadata\": [ { \"name\": \"ohos.extension.backup\", \"resource\": \"$profile:backup_config\" } ], } ], \"requestPermissions\": [ { \"name\": \"ohos.permission.INTERNET\" } ] }}

二、Index.ets的代码分析

2.1  初始化

当TcpClientPage组件被加载时,首先会初始化所有@State装饰的变量(serverIp, serverPort, message, receivedData, isConnected)

创建TCP套接字实例tcpSocket和获取UI上下文context

aboutToAppear生命周期:

再次创建TCP套接字实例(这里重复创建了,可以优化)

设置TCP连接选项(address, port, family, timeout)

注册三个事件监听器:

message:接收服务器数据时触发

close:连接关闭时触发

error:发生错误时触发

以下为代码

// 初始化TCP套接字 aboutToAppear() { this.tcpSocket = socket.constructTCPSocketInstance(); // 设置TCP连接参数 let tcpOptions: socket.TCPConnectOptions = { address: { address: this.serverIp, port: parseInt(this.serverPort), family: 1 // 1表示IPv4 }, timeout: 5000 // 连接超时时间5秒 }; // 监听接收数据 this.tcpSocket.on(\'message\', (messageInfo: socket.SocketMessageInfo) => { console.info(\'Received message\'); // 从 SocketMessageInfo 中获取 ArrayBuffer const buffer = messageInfo.message; // message 是 ArrayBuffer 类型 const data = this.arrayBufferToString(buffer); this.receivedData += `[接收] ${new Date().toLocaleTimeString()}: ${data}\\n`; }); // 监听连接关闭 this.tcpSocket.on(\'close\', () => { console.info(\'Connection closed\'); this.isConnected = false; promptAction.showToast({ message: \'连接已关闭\', duration: 2000 }); }); // 监听错误事件 this.tcpSocket.on(\'error\', (err) => { console.error(\'Socket error: \' + JSON.stringify(err)); promptAction.showToast({ message: \'发生错误: \' + JSON.stringify(err), duration: 3000 }); this.isConnected = false; }); }

2.2  UI代码

build()方法构建了以下UI元素:

服务器IP输入框

端口号输入框

连接/断开按钮(根据连接状态改变文字和颜色)

消息输入框

发送按钮

消息显示区域(带滚动条)

以下为代码

 build() { Column({ space: 10 }) { // 标题 Text(\'TCP客户端\') .fontSize(24) .fontWeight(FontWeight.Bold) .margin({ bottom: 20 }) // 服务器地址输入 Row({ space: 10 }) { Text(\'服务器IP:\') .fontSize(16) .width(80) TextInput({ text: this.serverIp }) .width(\'60%\') .onChange((value: string) => { this.serverIp = value; }) }.width(\'100%\') .justifyContent(FlexAlign.Start) // 端口号输入 Row({ space: 10 }) { Text(\'端口号:\') .fontSize(16) .width(80) TextInput({ text: this.serverPort }) .width(\'60%\') .onChange((value: string) => { this.serverPort = value; }) }.width(\'100%\') .justifyContent(FlexAlign.Start) // 连接按钮 Button(this.isConnected ? \'断开连接\' : \'连接\') .width(\'80%\') .height(40) .backgroundColor(this.isConnected ? \'#ff4d4f\' : \'#1890ff\') .onClick(() => { this.toggleConnection(); }) // 消息输入框 TextInput({ placeholder: \'输入要发送的消息\', text: this.message }) .width(\'90%\') .height(60) .margin({ top: 20 }) .onChange((value: string) => { this.message = value; }) // 发送按钮 Button(\'发送\') .width(\'80%\') .height(40) .margin({ top: 10 }) .onClick(() => { this.sendMessage(); }) // 消息显示区域 Scroll() { Text(this.receivedData) .width(\'90%\') .fontSize(14) .textAlign(TextAlign.Start) .padding(10) .backgroundColor(\'#f5f5f5\') } .width(\'100%\') .height(200) .margin({ top: 20 }) .border({ width: 1, color: \'#d9d9d9\' }) } .width(\'100%\') .height(\'100%\') .padding(20) .justifyContent(FlexAlign.Start) }

2.3  建立连接和发送

调用tcpSocket.connect()建立连接

点击\"发送\"按钮:

触发sendMessage()方法

以下为代码

// 连接到服务器 private async connect() { try { let tcpOptions: socket.TCPConnectOptions = { address: { address: this.serverIp, port: parseInt(this.serverPort), family: 1 }, timeout: 5000 }; await this.tcpSocket.connect(tcpOptions); this.isConnected = true; promptAction.showToast({ message: \'连接成功\', duration: 2000 }); // 开始接收数据 this.tcpSocket.getState().then(state => { console.info(\'Socket state: \' + JSON.stringify(state)); }); } catch (err) { console.error(\'Connect failed: \' + JSON.stringify(err)); promptAction.showToast({ message: \'连接失败: \' + JSON.stringify(err), duration: 3000 }); this.isConnected = false; } }

2.4  所有代码

// MainAbility.etsimport socket from \'@ohos.net.socket\';import common from \'@ohos.app.ability.common\';import promptAction from \'@ohos.promptAction\';import { BusinessError } from \'@kit.BasicServicesKit\';@Entry@Componentstruct TcpClientPage { @State serverIp: string = \'192.168.3.146\'; // 默认服务器IP @State serverPort: string = \'1000\'; // 默认端口 @State message: string = \'\'; // 要发送的消息 @State receivedData: string = \'\'; // 接收到的数据 @State isConnected: boolean = false; // 连接状态 private tcpSocket: socket.TCPSocket = socket.constructTCPSocketInstance(); private context = getContext(this) as common.UIAbilityContext; // 初始化TCP套接字 aboutToAppear() { this.tcpSocket = socket.constructTCPSocketInstance(); // 设置TCP连接参数 let tcpOptions: socket.TCPConnectOptions = { address: { address: this.serverIp, port: parseInt(this.serverPort), family: 1 // 1表示IPv4 }, timeout: 5000 // 连接超时时间5秒 }; // 监听接收数据 this.tcpSocket.on(\'message\', (messageInfo: socket.SocketMessageInfo) => { console.info(\'Received message\'); // 从 SocketMessageInfo 中获取 ArrayBuffer const buffer = messageInfo.message; // message 是 ArrayBuffer 类型 const data = this.arrayBufferToString(buffer); this.receivedData += `[接收] ${new Date().toLocaleTimeString()}: ${data}\\n`; }); // 监听连接关闭 this.tcpSocket.on(\'close\', () => { console.info(\'Connection closed\'); this.isConnected = false; promptAction.showToast({ message: \'连接已关闭\', duration: 2000 }); }); // 监听错误事件 this.tcpSocket.on(\'error\', (err) => { console.error(\'Socket error: \' + JSON.stringify(err)); promptAction.showToast({ message: \'发生错误: \' + JSON.stringify(err), duration: 3000 }); this.isConnected = false; }); } private arrayBufferToString(buffer: ArrayBuffer): string { const uint8Array = new Uint8Array(buffer); let str = \'\'; for (let i = 0; i < uint8Array.length; i++) { str += String.fromCharCode(uint8Array[i]); } return str; } // 字符串转ArrayBuffer private stringToArrayBuffer(str: string): ArrayBuffer { let buf = new ArrayBuffer(str.length); let bufView = new Uint8Array(buf); for (let i = 0; i  { console.info(\'Socket state: \' + JSON.stringify(state)); }); } catch (err) { console.error(\'Connect failed: \' + JSON.stringify(err)); promptAction.showToast({ message: \'连接失败: \' + JSON.stringify(err), duration: 3000 }); this.isConnected = false; } } // 断开连接 private disconnect() { try { this.tcpSocket.close(); this.isConnected = false; promptAction.showToast({ message: \'已断开连接\', duration: 2000 }); } catch (err) { console.error(\'Disconnect failed: \' + JSON.stringify(err)); promptAction.showToast({ message: \'断开连接失败: \' + JSON.stringify(err), duration: 3000 }); } } private sendMessage() { if (!this.isConnected) { promptAction.showToast({ message: \'请先连接到服务器\', duration: 2000 }); return; } if (!this.message.trim()) { promptAction.showToast({ message: \'消息不能为空\', duration: 2000 }); return; } try { const buffer = this.stringToArrayBuffer(this.message); this.tcpSocket.send({ data: buffer }) .then(() => { this.receivedData += `[发送] ${new Date().toLocaleTimeString()}: ${this.message}\\n`; this.message = \'\'; }) .catch((err: BusinessError) => { console.error(`Send failed: code=${err.code}, message=${err.message}`); promptAction.showToast({ message: `发送失败: ${err.message}`, duration: 3000 }); }); } catch (err) { console.error(`Send error: code=${err.code}, message=${err.message}`); promptAction.showToast({ message: `发送错误: ${err.message}`, duration: 3000 }); } } build() { Column({ space: 10 }) { // 标题 Text(\'TCP客户端\') .fontSize(24) .fontWeight(FontWeight.Bold) .margin({ bottom: 20 }) // 服务器地址输入 Row({ space: 10 }) { Text(\'服务器IP:\') .fontSize(16) .width(80) TextInput({ text: this.serverIp }) .width(\'60%\') .onChange((value: string) => { this.serverIp = value; }) }.width(\'100%\') .justifyContent(FlexAlign.Start) // 端口号输入 Row({ space: 10 }) { Text(\'端口号:\') .fontSize(16) .width(80) TextInput({ text: this.serverPort }) .width(\'60%\') .onChange((value: string) => { this.serverPort = value; }) }.width(\'100%\') .justifyContent(FlexAlign.Start) // 连接按钮 Button(this.isConnected ? \'断开连接\' : \'连接\') .width(\'80%\') .height(40) .backgroundColor(this.isConnected ? \'#ff4d4f\' : \'#1890ff\') .onClick(() => { this.toggleConnection(); }) // 消息输入框 TextInput({ placeholder: \'输入要发送的消息\', text: this.message }) .width(\'90%\') .height(60) .margin({ top: 20 }) .onChange((value: string) => { this.message = value; }) // 发送按钮 Button(\'发送\') .width(\'80%\') .height(40) .margin({ top: 10 }) .onClick(() => { this.sendMessage(); }) // 消息显示区域 Scroll() { Text(this.receivedData) .width(\'90%\') .fontSize(14) .textAlign(TextAlign.Start) .padding(10) .backgroundColor(\'#f5f5f5\') } .width(\'100%\') .height(200) .margin({ top: 20 }) .border({ width: 1, color: \'#d9d9d9\' }) } .width(\'100%\') .height(\'100%\') .padding(20) .justifyContent(FlexAlign.Start) }}

三、效果演示

3.1  首先搭建服务器端,这里使用了网络调试助手,设置ip和端口号,打开。

3.2  APP的效果和设置