#夏日挑战赛# 【FFH】OpenHarmony与HarmonyOS实现信息交流(一) 原创 精华

发布于 2022-6-15 09:42
浏览
8收藏

[本文正在参加星光计划3.0–夏日挑战赛] 活动链接

在过去很长一段时间,我都非常希望能够将OpenHarmony与HarmonyOS设备进行一个联动,但是碍于一些底层接口未完善一直无法实现。但是在前几个月,OpenHarmony3.1 带来了更多可能。本次,我将分享如何在搭载HarmonyOS的手机和搭载OpenHarmony的开发板上,实现socket对话!

0. 效果演示

#夏日挑战赛# 【FFH】OpenHarmony与HarmonyOS实现信息交流(一)-开源基础软件社区

1.HarmonyOS侧

1.1 新建一个JAVA工程,编写简单的测试页面

#夏日挑战赛# 【FFH】OpenHarmony与HarmonyOS实现信息交流(一)-开源基础软件社区

  • ability_main.xml (主页面)
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="center"
    ohos:orientation="vertical">
    <TextField
        ohos:id="$+id:sendfield"
        ohos:height="200px"
        ohos:width="800px"
       ohos:bottom_margin="32vp"
        ohos:text_size="32fp"
        ohos:hint="请输入发送信息"
        ohos:background_element="$graphic:tfbg"
        />
    <Button
        ohos:id="$+id:btn"
        ohos:height="120px"
        ohos:width="300px"
        ohos:text="启动"
        ohos:text_size="32fp"
       ohos:background_element="$graphic:btn"
        />
    <Text
        ohos:id="$+id:text"
        ohos:top_margin="50vp"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:text_size="32fp"
        ohos:text="暂无消息"


        />
    <Text
        ohos:id="$+id:localip"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:text="本机IP"
        ohos:top_margin="30vp"
        ohos:text_size="32fp"
        />
    <TextField
        ohos:id="$+id:textfield"
        ohos:height="200px"
        ohos:width="800px"
        ohos:top_margin="50vp"
        ohos:text_size="32fp"
        ohos:hint="请输入IP地址"
        ohos:background_element="$graphic:tfbg"
        />

</DirectionalLayout> 

这是我自己编写的一个测试页面,但不是最重要的。

1.2 编写socket功能

目前,鸿蒙的Socket通信功能只能在JAVA侧实现,并且官网对相关的功能解析不够全面,但是足够实现UDP通信。
这里直接参考官网,可以快速实现Socket功能,传送门:​​JAVA-socket
在MainAbilitySlice中编写两个主要函数,并结合个人情况绑定到测试按键上即可。

  • StartServer()
HiLog.info(LABEL_LOG, "StartServer run");

                NetManager netManager = NetManager.getInstance(null);

                if (!netManager.hasDefaultNet()) {
                    HiLog.error(LABEL_LOG,
                            "netManager.hasDefaultNet() failed");

                    return;
                }

                NetHandle netHandle = netManager.getDefaultNet();
                DatagramSocket socket = null;

                // 通过Socket绑定来进行数据传输
                try {
                    HiLog.info(LABEL_LOG, "wait receive data");

                    //通过getLocalIpAddress()快速获取本机的IP地址
                    InetAddress address = netHandle.getByName(getLocalIpAddress());
                    //端口号+主机地址
                    socket = new DatagramSocket(10006, address);
                    netHandle.bindSocket(socket);
                    /*至此绑定Socket结束*/
                    HiLog.info(LABEL_LOG, "绑定成功");

                    /*监听函数*/
                    byte[] buffer = new byte[1024];
                    DatagramPacket response = new DatagramPacket(buffer,
                            buffer.length);

                    while (true) {
                        //接收数据
                        socket.receive(response);

                        int len = response.getLength();
                        HiLog.info(LABEL_LOG, "接收成功");
                        //将数据打印到屏幕上
                        s = new String(buffer, StandardCharsets.UTF_8).substring(0,
                                len);
                                //一个textfield组件
                                text.setText(s);
                       
                        HiLog.info(LABEL_LOG, "receive data: " + s);
                    }
                } catch (IOException e) {
                    HiLog.error(LABEL_LOG, "rev IOException: ");
                }
            }
  • sendMessage()
NetManager netManager = NetManager.getInstance(null);

                if (!netManager.hasDefaultNet()) {
                    HiLog.error(LABEL_LOG,
                            "netManager.hasDefaultNet() failed");

                    return;
                }

                NetHandle netHandle = netManager.getDefaultNet();

                // 通过Socket绑定来进行数据传输
                DatagramSocket socket = null;

                try {
                    //从textfield组件获取用户输入的对端ip地址
                    HOST = iptf.getText();

                    InetAddress address = netHandle.getByName(HOST);
                    socket = new DatagramSocket();
                    netHandle.bindSocket(socket);

                    /*至此 已绑定对端Socket*/

                    //从一个textfield组件获取用户输入的要发送的信息。
                    String data = new String(sendtf.getText());

                    //这里默认还是发送至对端的10006端口
                    DatagramPacket request = new DatagramPacket(data.getBytes(
                            StandardCharsets.UTF_8), data.length(),
                            address, PORT);
                    // buffer赋值
                    // 发送数据
                    socket.send(request);
                    HiLog.info(LABEL_LOG, "send data: " + data);
                } catch (IOException e) {
                    HiLog.error(LABEL_LOG, "send IOException: ");
                } finally {
                    if (null != socket) {
                    }
                }
  • getlocalip()
private String getLocalIpAddress() {
        WifiDevice wifiDevice = WifiDevice.getInstance(getContext());
        Optional<IpInfo> ipInfo = wifiDevice.getIpInfo();
        int ip = ipInfo.get().getIpAddress();
        return (ip & 0xFF) + "." + ((ip >> 8) & 0xFF) + "." + ((ip >> 16) & 0xFF) + "." + (ip >> 24 & 0xFF);
    }

至此,接收信息和发送信息的函数都编写完了。但并没有结束,这样的函数并不能跑在UI线程上,我们必须让其在其他线程上运作,那必须请出我们最爱的EventRunner.

1.3 编写Mythread类

EventRunner传送门

package com.example.hoop.util;

import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;


public class Mythread {
    public static void inUI(Runnable runnable) {
        //返回主线程
        EventRunner runner = EventRunner.getMainEventRunner();

        EventHandler eventHandler = new EventHandler(runner);

        eventHandler.postSyncTask(runnable);
    }

    public static void inBG(Runnable runnable) {
        EventRunner runner = EventRunner.create(true);

        EventHandler eventHandler = new EventHandler(runner);
        //投递任务,我们的Socket函数应该投递于此。
        eventHandler.postTask(runnable, 0, EventHandler.Priority.IMMEDIATE);
    }
}
  • 将任务投递给EventRunner

只需要将刚刚的两个主要函数投递就行了

private void sendMessage() {
        Mythread.inBG(new Runnable() {
            @Override
            public void run() {
                NetManager netManager = NetManager.getInstance(null);
                if (!netManager.hasDefaultNet()) {
                    HiLog.error(LABEL_LOG,"netManager.hasDefaultNet() failed");
                    return;
                }
                NetHandle netHandle = netManager.getDefaultNet();
                // 通过Socket绑定来进行数据传输
                DatagramSocket socket = null;
                try {
                    //从textfield组件获取用户输入的对端ip地址
                    HOST=iptf.getText();
                    InetAddress address = netHandle.getByName(HOST);
                    socket = new DatagramSocket();
                    netHandle.bindSocket(socket);
                    /*至此 已绑定对端Socket*/

                    //从一个textfield组件获取用户输入的要发送的信息。
                    String data = new String(sendtf.getText());
                    //这里默认还是发送至对端的10006端口
                    DatagramPacket request = new DatagramPacket(data.getBytes(StandardCharsets.UTF_8), data.length(), address, PORT);
                    // buffer赋值
                    // 发送数据
                    socket.send(request);
                    HiLog.info(LABEL_LOG,"send data: " + data);

                } catch (IOException e) {

                    HiLog.error(LABEL_LOG,"send IOException: ");
                } finally {
                    if (null != socket) {

                    }
                }
            }
        });
    }

    private void StartServer() {
        Mythread.inBG(new Runnable() {
            @Override
            public void run() {

                HiLog.info(LABEL_LOG,"StartServer run");
                NetManager netManager = NetManager.getInstance(null);
                if (!netManager.hasDefaultNet()) {

                    HiLog.error(LABEL_LOG,"netManager.hasDefaultNet() failed");
                    return;
                }
                NetHandle netHandle = netManager.getDefaultNet();
                DatagramSocket socket = null;
                // 通过Socket绑定来进行数据传输
                try {

                    HiLog.info(LABEL_LOG,"wait receive data");
                    //通过getLocalIpAddress()快速获取本机的IP地址
                    InetAddress address = netHandle.getByName(getLocalIpAddress());
                    //端口号+主机地址
                    socket = new DatagramSocket(10006, address);
                    netHandle.bindSocket(socket);
                    /*至此绑定Socket结束*/
                    HiLog.info(LABEL_LOG,"绑定成功");

                    /*监听函数*/
                    byte[] buffer = new byte[1024];
                    DatagramPacket response = new DatagramPacket(buffer, buffer.length);
                    while(true){
                        //接收数据
                        socket.receive(response);
                        int len = response.getLength();
                        HiLog.info(LABEL_LOG,"接收成功");
                        //将数据打印到屏幕上
                        s = new String(buffer, StandardCharsets.UTF_8).substring(0, len);
                        Mythread.inUI(new Runnable() {
                            @Override
                            public void run() {
                                //一个textfield组件
                                text.setText(s);
                            }
                        });

                        HiLog.info(LABEL_LOG,"receive data: " + s);
                    }
                } catch (IOException e) {
                    HiLog.error(LABEL_LOG,"rev IOException: " );
                }
            }
        });

    }

2.OpenHarmony侧

2.1 新建工程,编写测试页面

#夏日挑战赛# 【FFH】OpenHarmony与HarmonyOS实现信息交流(一)-开源基础软件社区

  • index.hml
<div class="container"> 
   <text class="title">
     {{ title }} 
   </text> 
   <!--    <div style="width: 30%;height: 30%;background-color: blueviolet;">--> 
   <!--    </div>--> 
   <!--    <input  type="text" id="localip" placeholder="输入本机IP"--> 
   <!--           @change="newlocalip">--> 
   <!--    </input>--> 
   <text style="width: 300px;height: 70px;">
     本机IP{{getIpAddress()}} 
   </text> 
   <button type="capsule" style="width: 300px;height: 70px;" onclick="creatScoket"> 点击创建 </button> 
   <input id="remoteip" placeholder="输入服务器IP" @change="newremoteip" />  
   <button type="capsule" style="width: 300px;height: 70px;margin-top: 5%;" onclick="sendMessage"> 点击连接 </button> 
   <input placeholder="输入需要发送的信息" type="text" enterkeytype="done" @change="newMessage" />  
  </div>


2.2 编写Socket功能

OpenHarmony-Socket

import socket from '@ohos.net.socket';
import wifi from '@ohos.wifi';
export default {
    data: {
        title: "等待新的消息...",
        tcp: socket.constructTCPSocketInstance(),
        remoteip:'none',
        localip:'none',
        msg:"A NEW WORLD",
        udp:socket.constructUDPSocketInstance(),

    },
    onInit() {
      this.getIpAddress();
      this.creatScoket();
      this.title="暂无新消息"
    },
    //创建udpSocket 默认端口10006
    creatScoket: async function(){
        this.udp.bind({address: this.getIpAddress(), port: 10006, family: 1}, err => {
            if (err) {
                console.info('bind fail');
                this.title='bind fail'
                return;
            }
            this.title='bind success';
            console.info('bind success');
        })
//          this.tcp.bind({address: this.localip, port: 10006,family: 1}, err => {
//            if (err) {
//                console.log('bind fail');
//                this.title='bind fail';
//                return;
//            }
//            this.title='bind success';
//            console.log('bind success');
//        })
        //监听收到的信息 打印到屏幕上
       this.udp.on('message', value => {
           let buffer = value.message;
           let dataView = new DataView(buffer);
           let str = "";
           for (let i = 0;i < dataView.byteLength; ++i) {
               str += String.fromCharCode(dataView.getUint8(i))
           }
           this.title =str;
        });
    },
    sendMessage: async function(){

//        let promise1 = this.udp.connect({ address: {address: this.remoteip, port: 10006, family: 1} , timeout: 6000});
//        promise1.then(() => {
//            console.log('connect success');
//            let promise2 =this.udp.send({
//                data:this.msg
//            });
//            promise2.then(() => {
//                console.log('send success');
//            }).catch(err => {
//                console.log('send fail');
//            });
//        }).catch(err => {
//            this.title='connect fail';
//            console.log('connect fail');
//        });
        //发送信息
        let promise = this.udp.send({
            data:this.msg,
            address: {
                address:this.remoteip,
                port:10006,
                family:1
            }
        });
        promise.then(() => {
            this.title='send success';
            console.info('send success');
        }).catch(err => {
            this.title='send fail'
            console.info('send fail');
        });
    },
    newlocalip(e){
       this.localip = e.value;
        this.title = e.value;
    },
    newremoteip(e){
        this.remoteip = e.value;
    },
    newMessage(e){
        this.msg=e.value;
        this.title=e.value;
    },
    //获取本机ip地址
    getIpAddress(){
       let ip=wifi.getIpInfo().ipAddress;
       this.localip = (ip >> 24 & 0xFF)+"."+ ((ip >> 16) & 0xFF)+"."+((ip >> 8) & 0xFF)+"."+(ip & 0xFF);
    },

}

3.测试

这里为了便于测试,我们最好下载一个网络调试助手
网络调试助手

3.1结果

  • OpenHarmony侧
    #夏日挑战赛# 【FFH】OpenHarmony与HarmonyOS实现信息交流(一)-开源基础软件社区
  • HarmonyOS侧
    #夏日挑战赛# 【FFH】OpenHarmony与HarmonyOS实现信息交流(一)-开源基础软件社区
  • OpenHarmony&HarmonyOS 联动
    #夏日挑战赛# 【FFH】OpenHarmony与HarmonyOS实现信息交流(一)-开源基础软件社区

4 结语

实现了OpenHarmony与HarmonyOS的简单通讯后,应用开发,软硬件联动都有了更多的可能性。目前可能存在一些稳定性,不完整性问题,未来两侧基础功能不断完善之后,将会变得更有趣也更好用。如有明显错误,希望读者能够积极提出,我会尽力完善。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
已于2022-6-15 09:57:05修改
16
收藏 8
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐