介绍
本示例主要演示了Socket在网络通信方面的应用,展示了Socket在两端设备的连接验证、聊天通信方面的应用。
效果预览
使用说明
1.打开应用,点击用户文本框选择要登录的用户,并输入另一个设备的IP地址,点击确定按钮进入已登录的用户页面(两个设备都要依次执行此步骤)。
2.在其中一个设备上点击创建房间按钮,任意输入房间号,另一个设备会收到有房间号信息的弹框,点击确定按钮后,两个设备进入聊天页面。
3.在其中一个设备上输入聊天信息并点击发送按钮后,另一个设备的聊天页面会收到该聊天消息。
4.点击顶部标题栏右侧的退出图标按钮,则返回已登录的用户页面。
5.点击聊天页面中的昵称栏,会弹出一个菜单,选择离线选项后,两端设备的状态图标都会切换为离线图标,并且昵称栏都会变成灰色,此时任何一端发送消息另一端都接收不到消息。
6.当点击昵称栏再次切换为在线状态,则两端的己方账号状态会切换为在线图标,同时两端的昵称栏会显示蓝色,此时可正常收发消息。
工程目录
entry/src/main/ets/MainAbility
|---app.ets
|---model
| |---chatBox.ts // 聊天页面
| |---DataSource.ts // 数据获取
| |---Logger.ts // 日志工具
|---pages
| |---Index.ets // 监听消息页面
| |---Login.ets // 首页登录页面
|---Utils
| |---Utils.ets
具体实现
- 本示例分为三个模块
- 输入对端IP模块
- 使用wifi.getIpInfo()方法获取IP地址,constructUDPSocketInstance方法创建一个UDPSocket对象
- 源码链接:[Login.ets]
- 输入对端IP模块
/*
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import wifi from '@ohos.wifi';
import router from '@ohos.router';
import { resolveIP } from '../Utils/Util'
import socket from '@ohos.net.socket';
import Logger from '../model/Logger'
const TAG: string = '[Login]'
let localAddr = {
address: resolveIP(wifi.getIpInfo().ipAddress),
family: 1,
port: 0
}
let oppositeAddr = {
address: '',
family: 1,
port: 0
}
let loginCount = 0
let udp = socket.constructUDPSocketInstance()
@Entry
@Component
struct Login {
@State login_feng: boolean = false
@State login_wen: boolean = false
@State user: string = ''
@State roomDialog: boolean = false
@State confirmDialog: boolean = false
@State ipDialog: boolean = true
@State warnDialog: boolean = false
@State warnText: string = ''
@State roomNumber: string = ''
@State receiveMsg: string = ''
bindOption() {
let bindOption = udp.bind(localAddr);
bindOption.then(() => {
Logger.info(TAG, 'bind success');
}).catch(err => {
Logger.info(TAG, 'bind fail');
})
udp.on('message', data => {
Logger.info(TAG, `data:${JSON.stringify(data)}`);
let buffer = data.message;
let dataView = new DataView(buffer);
Logger.info(TAG, `length = ${dataView.byteLength}`);
let str = '';
for (let i = 0;i < dataView.byteLength; ++i) {
let c = String.fromCharCode(dataView.getUint8(i));
if (c != '') {
str += c;
}
}
if (str == 'ok') {
router.clear();
loginCount += 1;
router.push({
url: 'pages/Index',
params: { address: oppositeAddr.address, port: oppositeAddr.port, loginCount: loginCount }
})
}
else {
this.receiveMsg = str;
this.confirmDialog = true;
}
})
}
build() {
Stack({ alignContent: Alignment.Center }) {
Column() {
Text($r('app.string.MainAbility_label'))
.width('100%')
.height(50)
.backgroundColor('#0D9FFB')
.textAlign(TextAlign.Start)
.fontSize(25)
.padding({ left: 10 })
.fontColor(Color.White)
.fontWeight(FontWeight.Bold)
if (!this.ipDialog) {
Column() {
Image(this.login_feng ? $r('app.media.fengziOn') : $r('app.media.wenziOn'))
.width(100)
.height(100)
.objectFit(ImageFit.Fill)
Text('用户名:'