openharmony标準系統JS、eTS 的napi socket網絡接口開發 TCP
1.設計背景
目前openharmony标準系統通過 JS、eTS 開發貌似還沒支援網絡開發的接口,故JS、eTS
方式開發隻能通過NAPI調用C/C++才能使用到網絡,本次我就使用NAPI開發openharmony APP 的網絡程式設計開發!
①.openharmony APP 本次采用eTS開發方式
②.本次實驗是基于已連接配接上網絡的
③.openharmony APP 開發環境為 DevEco Studio 3.0.0.800
④.使用的系統版本openharmony3.0 标準系統
2.openharmony标準系統網絡程式設計整體構思
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsQTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5SMwkjNxQWOxMDO3ETY4UGNyYzX3AjM1QTM3AzLcRDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL0M3Lc9CX6MHc0RHaiojIsJye.png)
①.本Demo簡單的建立一個簡單的socket server TCP
②.通過C 實作 4個NAPI接口
- 啟動socket server 接口
- 發送資料接口
- 接收資料接口 (使用NAPI回調函數實作)
- 關閉socket server 接口
③設定一個簡單的eTS APP使用NAPI網絡接口
3.napi代碼實作部分
①.代碼部分
路徑:\OpenHarmony\foundation\ace\napi\sample\native_module_socket_server\native_module_socket_server.cpp
注意:native_module_socket_server檔案夾自行建立
-
/* * Copyright (c) 2021 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. */ #include "napi/native_api.h" #include "napi/native_node_api.h" #include "utils/log.h" #include <stdlib.h> // standard library 标準庫函數頭檔案 #include <stdio.h> // standard input output 标準輸入輸出函數 #include <stdint.h> // 定義了擴充的整數類型和宏 #include <unistd.h> // POSIX 系統 API 通路功能的頭檔案 #include <fcntl.h> // unix标準中通用的頭檔案 define O_WRONLY and O_RDONLY #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> #include <ctype.h> #include <string.h> #include <signal.h> static char buf[1024]; static size_t buflen; static int wflag; static int st; static int client_st; static napi_ref CallbackReff; static napi_env envs; void* socketserverthrd(void *ptr) { napi_value jsObj, prop1,prop2,prop3, callback = nullptr,undefine = nullptr; napi_get_reference_value(envs, CallbackReff, &callback); int port = 18000; st = socket(AF_INET, SOCK_STREAM, 0); int opt = SO_REUSEADDR; setsockopt(st, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(st, (struct sockaddr *) &addr, sizeof(addr)) == -1) { HILOG_INFO("test0002 bind failed %s\n", strerror(errno)); return NULL; } if (listen(st, 20) == -1) { HILOG_INFO("test0002 listen failed %s\n", strerror(errno)); return NULL; } HILOG_INFO("test0002 listen success\n"); struct sockaddr_in client_addr; memset(&client_addr, 0, sizeof(client_addr)); socklen_t len = sizeof(client_addr); HILOG_INFO("test0002 waiting for client.......\n"); wflag = 1; char str[1024]; while(wflag) { client_st = accept(st, (struct sockaddr*) &client_addr, &len); if (client_st == -1) { HILOG_INFO("test0002 accept failed %s\n", strerror(errno)); return NULL; } HILOG_INFO("test0002 accept by %s\n", inet_ntoa(client_addr.sin_addr)); while (wflag) { memset(str, 0, sizeof(str)); int numbytes = recv(client_st, str, sizeof(str), 0); if (numbytes <= 0) break; //if(wflag == 0) break; strcpy(buf,str); if((int)str[0] == 170) { int cPara1 = (int)str[1]; int cPara2 = (int)str[2]; int cPara3 = (int)str[3]; napi_create_object(envs, &jsObj); //建立JS回調函數對應的參數對象 napi_create_int32(envs, cPara1, &prop1); napi_create_int32(envs, cPara2, &prop2); napi_create_int32(envs, cPara3, &prop3); napi_set_named_property(envs, jsObj, "prop1", prop1); //設定JS參數對象屬性值 napi_set_named_property(envs, jsObj, "prop2", prop2); napi_set_named_property(envs, jsObj, "prop3", prop3); napi_call_function(envs, nullptr, callback, 1, &jsObj, &undefine); //使用生成的JS參數,調用對應的JS回調函數 } buflen = strlen(str); //send(client_st, str, strlen(str), 0); } } return NULL; } //啟動 static napi_value ServerStart(napi_env env, napi_callback_info info) { size_t argc = 1; //參數個數定義 napi_value argv[argc]; napi_value thisVar = nullptr; void *data = nullptr; envs = env; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data)); NAPI_ASSERT(env, argc >= 1, "JSCallback Wrong number of arguments"); //參數個數校驗 napi_valuetype callbackType = napi_undefined; napi_typeof(env, argv[0], &callbackType); NAPI_ASSERT(env, callbackType == napi_function, "parameter 1 type mismatch"); //參數類型校驗,傳進來的須是函數類型 napi_create_reference(env, argv[0], 1, &CallbackReff); //建立引用 //napi_get_reference_value(env, CallbackRef, &callback); //根據引用擷取回調函數callback pthread_t thrd; HILOG_INFO("test0002 thrs start!"); //pthread_create(&thrd1, NULL, recvsocket, &client_st); pthread_create(&thrd, NULL, socketserverthrd,NULL); HILOG_INFO("test0002 end!"); napi_value result = nullptr; napi_get_undefined(env, &result); return result; } //停止 static napi_value ServerStop(napi_env env, napi_callback_info info) { close(st); wflag = 0; napi_value result = nullptr; napi_get_undefined(env, &result); return result; } //發送 static napi_value ServerWrite(napi_env env, napi_callback_info info) { size_t requireArgc = 3; size_t argc = 3; napi_value args[3] = { nullptr }; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); NAPI_ASSERT(env, argc >= requireArgc, "Wrong number of arguments"); napi_valuetype valuetype0; NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); napi_valuetype valuetype1; NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1)); napi_valuetype valuetype2; NAPI_CALL(env, napi_typeof(env, args[2], &valuetype2)); NAPI_ASSERT(env, valuetype0 == napi_number && valuetype1 == napi_number && valuetype2 == napi_number, "Wrong argument type. Numbers expected."); char str[4]; uint32_t a,b,c; NAPI_CALL(env, napi_get_value_uint32(env, args[0], &a)); NAPI_CALL(env, napi_get_value_uint32(env, args[1], &b)); NAPI_CALL(env, napi_get_value_uint32(env, args[2], &c)); str[0] = (char)0xAA; str[1] = (char)a; str[2] = (char)b; str[3] = (char)c; if (-1 == write(client_st, str,4)){ HILOG_INFO("test0002 okok servertest error"); } napi_value result = nullptr; napi_get_undefined(env, &result); return result; } EXTERN_C_START /* * function for module exports */ static napi_value Init(napi_env env, napi_value exports) { /* * Properties define */ napi_property_descriptor desc[] = { DECLARE_NAPI_FUNCTION("ServerStart", ServerStart), DECLARE_NAPI_FUNCTION("ServerStop", ServerStop), DECLARE_NAPI_FUNCTION("ServerWrite", ServerWrite) }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); return exports; } EXTERN_C_END /* * Module define */ static napi_module demoModule = { .nm_version = 1, .nm_flags = 0, .nm_filename = nullptr, .nm_register_func = Init, .nm_modname = "socketserver", .nm_priv = ((void*)0), .reserved = { 0 }, }; /* * Module register function */ extern "C" __attribute__((constructor)) void RegisterModule(void) { napi_module_register(&demoModule); }
②.編譯檔案設定
路徑:\OpenHarmony\foundation\ace\napi\sample\native_module_socket_server\BUILD.gn
import("//build/ohos.gni")
ohos_shared_library("socketserver") {
include_dirs = [
"//third_party/node/src",
"//foundation/ace/napi/interfaces/kits",
]
sources = [
"native_module_socket_server.cpp"
]
deps = [ "//foundation/ace/napi:ace_napi" ]
relative_install_dir = "module"
external_deps = [ "hiviewdfx_hilog_native:libhilog" ]
subsystem_name = "ace"
part_name = "napi"
}
③.加入編譯
路徑:\OpenHarmony\foundation\ace\napi\BUILD.gn
找到這裡
if (!build_ohos_ndk) {
group("napi_packages_test") {
testonly = true
deps = [
"sample/native_module_demo:demo",
"sample/native_module_netserver:netserver",
"sample/native_module_storage:storage",
"test/unittest:unittest",
"sample/native_module_led:led",
"sample/native_module_testdemo02:testdemo02",
"sample/native_module_netanddev:netanddev",
"sample/native_module_socket_server:socketserver" 《《《添加這個
]
if (is_standard_system) {
deps += [ "sample/native_module_ability:ability" ]
}
}
}
④.編譯
在源碼根目錄下運作
./build.sh --product-name Hi3516DV300 --build-target make_test
⑤.編譯輸出路徑
路徑:\OpenHarmony\out\hi3516dv300\ace\napi
其中這個libsocketserver.z.so檔案是我們要用的檔案
⑥.拷貝動态庫到開發闆
電腦用資料線連接配接到開發闆
1).兩個打開CMD
2).連接配接開發闆 (第一個CMD)
hdc_std shell
3).打開讀寫權限 (第一個CMD)
mount -o remount,rw /
4).發送動态庫檔案 (第二個CMD)
hdc_std file send libsocketserver.z.so /system/lib/module/
5).給動态庫添權重限 (第一個CMD)
chmod 666 /system/lib/module/libsocketserver.z.so
4.eTS APP代碼實作部分
import socket from '@ohos.socketserver';
var homebuf; //設定全局變量,用來儲存上下文
@Entry
@Component
struct Sockertest {
@State inSetValue: number = 0;
napicallback(data){ //socket server回調函數
homebuf.inSetValue = data.prop1;
console.log("test socketserver "+data.prop1+" "+data.prop2+" "+data.prop3+" "); //列印輸出所有資訊
}
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text('test socketserver')
.fontSize(50)
.fontWeight(FontWeight.Bold)
Text(this.inSetValue.toFixed(0)).fontSize(72).width('18%')
}
.width('100%')
.height('100%')
}
onPageShow() { //生命周期
socket.ServerStart(this.napicallback); //打sockerServer
homebuf=this;
}
}
5.安裝測試
①.eTS APP 安裝效果圖
②.連接配接開發闆的TCP server 并發送 AA 01 00 00 到開發闆
軟體名:網絡調試助手V4.2.1.exe
指令解釋:AA 01 00 00
AA是指令頭,01 00 00 是轉發到eTS上的資料,本次實驗在使用第一位 01 測試結果
注:你們可以寫更好的協定,以上的協定很爛是我随便寫的(哈哈),因為是測試用的
具體的你們看看我上面寫的代碼
③ .檢視開發闆接收AA 01 00 00 效果
④.發送 AA 06 00 00 到開發闆
⑤ .檢視開發闆接收AA 06 00 00 效果
⑥.測試成功!!!
6.注意事項
①.本次實驗要連接配接到網絡
②.eTS導入這個包報錯不用管
③.很多人不懂檢視ip
1.打開CMD
2.輸入hdc_std shell
3.輸入ifconfig
想了解更多關于鴻蒙的内容,請通路:
51CTO和華為官方合作共建的鴻蒙技術社群
https://ost.51cto.com/#bkwz