当前位置: 首页 > 科技观察

Harmonyos网络通信真机Demo演练(一)TCP聊天室

时间:2023-03-17 00:26:48 科技观察

更多内容请访问:与华为官方共建的Harmonyos技术社区https://harmonyos.51cto.com本Demo界面由ArkUI提供实现,网络逻辑部分使用java实现,服务端使用Go实现,易于部署和钻取。JAVA和GO第一次打架,这个Demo还有并发数据安全没有处理,所以这个Demo只能拿来学习。可以学习的要点如下:1、FA和PA采用ACE方式进行调用、交互、传递数据。2.Harmonyos的事件机制及使用——自定义事件。3.异步多线程TCP通信。一、效果展示1、服务端2、客户端2、设计流程图3、界面编写1、界面效果2、界面代码HML代码:tcp-clienttest

IP:
端口:
连接到服务器订阅新闻{{outcont}}发送消息
JS代码:importpromptfrom'@system.prompt';exportdefault{data:{title:'World',outcont:'',ip:'',port:'',msg:''},initConnectAction:function(code,ip,port){varactionData={};actionData.ip=ip;actionData.port=port;varaction={};action.bundleName="com.gane.tcpclient";action.abilityName="TcpClientAbility";action.messageCode=code;action.data=actionData;action.abilityType=1;action.syncOption=0;returnaction;},initAction:function(code){varactionData={};varaction={};action.bundleName="com.gane.tcpclient";action.abilityName="TcpClientAbility";action.messageCode=code;action.data=actionData;action.abilityType=1;action.syncOption=0;returnaction;},initAction2:function(code,msg){变量Data={};actionData.msg=msg;varaction={};action.bundleName="com.gane.tcpclient";action.abilityName="TcpClientAbility";action.messageCode=code;action.data=actionData;动作。abilityType=1;action.syncOption=0;returnaction;},onChange2(e){this.ip=e.value;},onChange3(e){this.port=e.value;},onConnect:asyncfunction(){尝试{varaction=this.initConnectAction(1001,this.ip,this.port);varresult=awaitFeatureAbility.callAbility(action);console.info("result="+result);this.showToast(result);}catch(pluginError){console.error("getBatteryLevel:PluginError="+pluginError);}},onSubResvMsg:asyncfunction(){try{varaction=this.initAction(1003);varthat=this;varresult=awaitFeatureAbility.subscribeAbilityEvent(action,function)(msgdata){console.info("batteryLevelinfois:"+msgdata);varmsgRet=JSON.parse(msgdata).data;that.printData(msgRet.msg);that.showToast("batteryStatechange:"+msgRet.msg);});this.showToast("订阅者ult"+result);console.info("subscribeCommonEventresult="+result);}catch(pluginError){console.error("subscribeCommonEventerror:result="+result+JSON.stringify(pluginError));}},onSend:asyncfunction(){try{varaction=this.initAction2(1002,this.msg);varresult=awaitFeatureAbility.callAbility(action);console.info("onSendresult="+result);this.showToast(result);}catch(pluginError){console.error("getBatteryLevel:PluginError="+pluginError);}},onChange4(e){this.msg=e.value;},printData(msg){if(this.outcont!=null||this.outcont!=""){this.outcont=msg+"\n"+this.outcont;}else{this.outcont=msg;}},showToast:function(msg){prompt.showToast({message:msg});}}注意:1,这里的交互方法都是异步方法,因为这样不会因为业务端阻塞UI线程,从而阻塞主线程2,仔细看每一个initAction(),理解action传递参数的构造和写法。4、PA写交互java类的实现如下:privatestaticTcpClientAbility实例;privateTcpClientAbility(){super(BUNDLE_NAME,ABILITY_NAME);}/***ACE注册*/publicvoidregister(){this.setInternalAbilityHandler(this::onRemoteRequest);HiLog.error(LABEL_LOG,"socket_register");}/***ACE注销*/publicvoidderegister(){this.setInternalAbilityHandler(null);HiLog.error(LABEL_LOG,"socket_unregister");}/***ACE事件回调接口*/publicbooleanonRemoteRequest(intcode,MessageParceldata,MessageParcelreply,MessageOptionoption){switch(code){}returntrue;}}注意:1、该类必须继承AceInternalAbility,必须实现注册、注销、事件回调接口。2.Register()和deregister()需要在合适的位置调用。我在mainAblity的onstart和onstop中调用它们。消息的接收和发送是分离的,都是异步进行的。根据业务需求,选择AsynchronousSocketChannel作为本次实现的网络基础类型,主要使用AsynchronousSocketChannel.open()、AsynchronousSocketChannel.setOption()、AsynchronousSocketChannel.connect()、AsynchronousSocketChannel.write()、AsynchronousSocketChannel.read等接口()。示例代码如下:socketChannel=AsynchronousSocketChannel.open();socketChannel.setOption(StandardSocketOptions.TCP_NODELAY,true);socketChannel.setOption(StandardSocketOptions.SO_REUSEADDR,true);socketChannel.connect(newInetSocketAddress(param.getIp(),param.getPort()),null,newCompletionHandler(){@Overridepublicvoidcompleted(Voidresult,Objectattachment){ByteBufferbyteBuffer=ByteBuffer.allocate(1024);Stringintput="我是:";try{intput=intput+socketChannel.getLocalAddress().toString();}catch(IOExceptione){e.printStackTrace();}try{byteBuffer.put(intput.getBytes("UTF-8"));}catch(UnsupportedEncodingExceptione){e.printStackTrace();}socketChannel.write(byteBuffer,1,TimeUnit.SECONDS,null,newCompletionHandler(){@Overridepublicvoidcompleted(Integerresult,Objectattachment){}publicvoidfailed(Throwableexc,Objectattachment){}});}@Overridepublicvoidfailed(Throwableexc,Objectattachment){}});if(TcpClientAbility.socketChannel!=null&&TcpClientAbility.socketChannel.isOpen()){ByteBufferbyteBuffer=ByteBuffer.allocate(1024);CompletionHandlercomphandler=newCompletionHandler(){@Overridepublicvoidcompleted(Integerresult,Objectattachment){byteBuffer.);byte[]byten=newbyte[byteBuffer.limit()];//可用字节数byteBuffer.get(byten,byteBuffer.position(),byteBuffer.limit());Stringret=newString(byten);TcpClientAbility.socketChannel.read(byteBuffer,-1,TimeUnit.SECONDS,null,this);}@Overridepublicvoidfailed(Throwableexc,Objectattachment){TcpClientAbility.socketChannel.read(byteBuffer,-1,TimeUnit.SECONDS,null,this);}};TcpClientAbility.socketChannel.read(byteBuffer,-1,TimeUnit.SECONDS,null,comphandler);}6.自定义事件灵感来自官方CommonEventManager常用事件,Harmonyos官方系统提供蓝牙、电池、时间、日期等相关的通用事件,同时也提供了电池相关的Demo,详见官方文档我这里拿CommonEventManager的CommonEventManager.subscribeCommonEvent()订阅事件、CommonEventManager.publishCommonEvent()发布事件给大家看下:MatchingSkillsmatchingSkills=newMatchingSkills();matchingSkills.addEvent(SELF_SOCKET_MSG);IRemoteObjectnotifier=data.readRemoteObject();CommonEventSubscribeInfosubscribeInfo=newCommonEventSubscribeInfo(matchingSkills);subscriber=newCommonEventSubscriber(subscribeInfo){@OverridepublicvoidonReceiveEvent(CommonEventDatacommonEventData){//HiLog.info(LABEL_LOG,"socket===shijian"+commonEventData.getData()+ret);}};try{CommonEventManager.subscribeCommonEvent(订阅者);}catch(RemoteExceptione){}}Intentintent=newIntent();Operationoperation=newIntent.OperationBuilder().withAction(TcpClientAbility.SELF_SOCKET_MSG).build();intent.setOperation(operation);intent.setParam("msg",ret);CommonEventDataeventData=newCommonEventData(intent);eventData.setData(ret);try{CommonEventManager.publishCommonEvent(eventData);}catch(RemoteExceptione){e.printStackTrace();}7、总结一下大概的思路,用到的关键知识点上面分别列出。做完之后觉得很简单,但其实用一个或多个门并不是很熟悉和相关开发思路参考比较少的开发框架写东西的时候,确实会感觉一头雾水才开始做.不要退缩。还是那句话,没有程序解决不了的问题,只有没有想法的程序员。只要他们要动手,就必须将整体拆散,化成碎片,一个一个的砸碎。本文虽然实现了一个简单的多客户端免费聊天,但是还有很多不足,比如保存聊天记录,跳转到页面后如何恢复页面,websocket、UDP、HTTP、蓝牙等通信方式的探索与实践等等,后面有时间就没法继续探索了。如有不足之处,请留言帮助我改进。文章相关附件可点击下方链接下载原文https://harmonyos.51cto.com/resource/1567更多信息请访问:与华为官方共建鸿蒙科技社区https:///harmonyos.51cto.com