Android 6.0一個完整的native service

来源:http://www.cnblogs.com/hackfun/archive/2017/09/06/7486847.html
-Advertisement-
Play Games

上一篇博客《Android 6.0 如何添加完整的系統服務(app-framework-kernel)》http://www.cnblogs.com/hackfun/p/7418902.html介紹瞭如何添加一個系統服務,客戶端和服務端都是基於JAVA實現的OpersysService。經過進一步的 ...


 

     上一篇博客《Android 6.0 如何添加完整的系統服務(app-framework-kernel)》http://www.cnblogs.com/hackfun/p/7418902.html
介紹瞭如何添加一個系統服務,客戶端和服務端都是基於JAVA實現的OpersysService。經過進一步的學習,我將
演示如何使用C++實現一個相同功能的系統服務hfnativeservice。為了相容OpersysService,將保留Opersys-
Service服務端中的HAL和driver,供hfnativeservice使用,即OpersysService和hfnativeservice這兩個Service
都是用相同的HAL和driver。其中,hfnativeservice增加了一個服務端死亡通知機制,即hfnative-service的服
務端進程被殺掉時,客戶端會收到這個通知,並做相應的清理工作。

    主要圍繞以下幾個步驟添加一個完整的C++系統服務:
(A) 添加HAL和Driver
(B) 添加服務介面,生成動態庫
(C) 添加服務端
(D) 註冊服務端
(E) 添加客戶端
(F) 測試

 

(A) 添加HAL和Driver
   這部分參考上一篇博客《Android 6.0 如何添加完整的系統服務(app-framework-kernel)》的

    (A) 添加circular-char驅動
    (B) 添加opersyshw_qemu HAL

(B) 添加服務介面,生成動態庫
   
為了對外只提供服務端或客戶端的介面,這裡把客戶端和服務端之間的通信實現細節放在一起,生成動態庫so
文件,服務端和客戶端在使用的時候,載入這個so就可以了。IHfNativeService.cpp對客戶端和服務端提供了相同
的介面,並實現了proxy和native之間的Binder通信細節。HfNativeManager.cpp根據IHfNativeService.cpp提供的
介面,進一步封裝,隱藏了客戶端的是操作細節,如服務的獲取,註冊死亡通知等。

相關頭文件:

frameworks/native/include/hfnative/HfNativeManager.h

 1 #ifndef ANDROID_HACKFUN_HACKFUN_NATIVE_SERVICE_H
 2 #define ANDROID_HACKFUN_HACKFUN_NATIVE_SERVICE_H
 3 
 4 #include <stdint.h>
 5 #include <sys/types.h>
 6 
 7 #include <binder/IBinder.h>
 8 
 9 #include <utils/RefBase.h>
10 #include <utils/Singleton.h>
11 #include <utils/threads.h>
12 #include <hfnative/IHfNativeService.h> 
13 
14 namespace android {
15 // ---------------------------------------------------------------------------
16 
17 class HfNativeManager : public Singleton<HfNativeManager>
18 {
19 public:
20     HfNativeManager();
21     ~HfNativeManager();
22     
23     int init_hfnative(void);
24     void deinit_hfnative(void);
25     int read_queue(char *buff, int len);
26     int write_queue(char *buff, int len);
27     int test_hfnative(int value);
28 
29     status_t assertState();
30     bool checkService() const;
31     void resetServiceStatus();
32 
33 private:
34     bool isDied;
35     // DeathRecipient interface
36     void hfNativeServiceDied();
37 
38     mutable sp<IHfNativeService> mHfNativeServer;
39     mutable sp<IBinder::DeathRecipient> mDeathObserver;
40 };
41 
42 }; // namespace android
43 
44 #endif // ANDROID_HACKFUN_HACKFUN_NATIVE_SERVICE_H

 

 

frameworks/native/include/hfnative/IHfNativeService.h

 1 #ifndef ANDROID_HACKFUN_HACKFUN_COMPOSER_CLIENT_H
 2 #define ANDROID_HACKFUN_HACKFUN_COMPOSER_CLIENT_H
 3 
 4 #include <stdint.h>
 5 #include <sys/types.h>
 6 
 7 #include <utils/Errors.h>
 8 #include <utils/RefBase.h>
 9 
10 #include <binder/IInterface.h>
11 
12 namespace android {
13 // ----------------------------------------------------------------------------
14 
15 class IHfNativeService : public IInterface
16 {
17 public:
18     DECLARE_META_INTERFACE(HfNativeService);
19 
20     virtual int init_native(void) = 0;
21     virtual void finalize_native(void) = 0;
22     virtual int read_native(char *Buff, int Len) = 0;
23     virtual int write_native(char *Buff, int Len) = 0;
24     virtual int test_native(int value) = 0;
25 };
26 
27 // ----------------------------------------------------------------------------
28 
29 class BnHfNativeService: public BnInterface<IHfNativeService> {
30 public:
31     virtual status_t onTransact(uint32_t code, const Parcel& data,
32             Parcel* reply, uint32_t flags = 0);
33 };
34 
35 // ----------------------------------------------------------------------------
36 
37 }; // namespace android
38 
39 #endif // ANDROID_HACKFUN_HACKFUN_COMPOSER_CLIENT_H

 

 

源文件:

frameworks/native/libs/hfnative/IHfNativeService.cpp

  1 #define LOG_TAG "HfNativeService"
  2 
  3 #include <stdio.h>
  4 #include <stdint.h>
  5 #include <malloc.h>
  6 #include <sys/types.h>
  7 
  8 #include <binder/Parcel.h>
  9 #include <binder/IMemory.h>
 10 #include <binder/IPCThreadState.h>
 11 #include <binder/IServiceManager.h>
 12 #include <hfnative/IHfNativeService.h>
 13 
 14 namespace android {
 15 
 16 enum {
 17     INIT_NATIVE = IBinder::FIRST_CALL_TRANSACTION,
 18     FINALIZE_NATIVE,
 19     READ_NATIVE,
 20     WRITE_NATIVE,
 21     TEST_NATIVE
 22 };
 23 
 24 class BpHfNativeService : public BpInterface<IHfNativeService>
 25 {
 26 public:
 27     BpHfNativeService(const sp<IBinder>& impl)
 28         : BpInterface<IHfNativeService>(impl)
 29     {
 30     }
 31 
 32     int init_native(void)
 33     {
 34         Parcel data, reply;
 35         
 36         data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor()); 
 37         remote()->transact(INIT_NATIVE, data, &reply);
 38 
 39         return (int)reply.readInt32();
 40     }
 41 
 42     void finalize_native(void)
 43     {
 44         Parcel data, reply;
 45 
 46         data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor());
 47         remote()->transact(FINALIZE_NATIVE, data, &reply);
 48     }
 49 
 50     int read_native(char *Buff, int Len)
 51     {
 52         Parcel data, reply;
 53 
 54         data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor());
 55         data.writeInt32(Len);
 56         remote()->transact(READ_NATIVE, data, &reply);
 57         reply.read((void *)Buff, (size_t)Len);
 58         return (int) reply.readInt32();
 59     }
 60 
 61 
 62     int write_native(char *Buff, int Len)
 63     {
 64         Parcel data, reply;
 65 
 66         data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor());
 67         data.writeInt32(Len);
 68         data.write((const void *)Buff, (size_t)Len);
 69         remote()->transact(WRITE_NATIVE, data, &reply);
 70         return (int) reply.readInt32();
 71     }
 72 
 73     int test_native(int value)
 74     {
 75         Parcel data, reply;
 76 
 77         data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor());
 78         data.writeInt32(value);
 79         remote()->transact(TEST_NATIVE, data, &reply);
 80         return (int) reply.readInt32();
 81     }
 82 };
 83 
 84 IMPLEMENT_META_INTERFACE(HfNativeService, "android.hfnative.HfNativeService");
 85 
 86 status_t BnHfNativeService::onTransact(
 87     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 88 {
 89     char *buff;
 90     int len, retval;
 91     status_t status;
 92 
 93     switch(code) {
 94         case INIT_NATIVE: 
 95             CHECK_INTERFACE(IHfNativeService, data, reply);
 96             retval = init_native();
 97             reply->writeInt32(retval); 
 98             return NO_ERROR;
 99 
100         case FINALIZE_NATIVE:
101             CHECK_INTERFACE(IHfNativeService, data, reply); 
102             finalize_native();
103             return NO_ERROR; 
104 
105         case READ_NATIVE: {
106             CHECK_INTERFACE(IHfNativeService, data, reply);
107             len = data.readInt32();
108             buff = (char *)malloc(len);
109             retval = read_native(buff, len);
110             reply->write((const void *)buff, (size_t)len);
111             free(buff);
112             reply->writeInt32(retval);
113             return NO_ERROR;
114         } break;
115 
116         case WRITE_NATIVE: {
117             CHECK_INTERFACE(IHfNativeService, data, reply);
118             len = data.readInt32(); 
119             buff = (char *)malloc(len);
120             status = data.read((void *)buff, (size_t)len);      
121             retval = write_native(buff, len);
122             free(buff);
123             reply->writeInt32(retval);
124             return NO_ERROR;
125         } break;
126 
127         case TEST_NATIVE:
128             CHECK_INTERFACE(IHfNativeService, data, reply);
129             retval = test_native(data.readInt32());
130             reply->writeInt32(retval);
131             return NO_ERROR;
132 
133         default:
134           return BBinder::onTransact(code, data, reply, flags);
135     }
136 }
137 
138 }; // namespace android

 

 

frameworks/native/libs/hfnative/HfNativeManager.cpp

  1 #define LOG_TAG "HfNative"
  2 
  3 #include <stdint.h>
  4 #include <sys/types.h>
  5 
  6 #include <utils/Errors.h>
  7 #include <utils/RefBase.h>
  8 #include <utils/Singleton.h>
  9 
 10 #include <binder/IBinder.h>
 11 #include <binder/IServiceManager.h>
 12 
 13 #include <hfnative/IHfNativeService.h>
 14 #include <hfnative/HfNativeManager.h>
 15 
 16 // ----------------------------------------------------------------------------
 17 namespace android {
 18 // ----------------------------------------------------------------------------
 19 
 20 HfNativeManager::HfNativeManager() : isDied(false)
 21 {
 22     
 23 }
 24 
 25 HfNativeManager::~HfNativeManager()
 26 {
 27 }
 28 
 29 void HfNativeManager::hfNativeServiceDied()
 30 {
 31     isDied = true;
 32     mHfNativeServer.clear();
 33 }
 34 
 35 status_t HfNativeManager::assertState() {
 36     if (mHfNativeServer == NULL) {
 37         // try for one second
 38         const String16 name("hfnativeservice");
 39         for (int i=0 ; i<4 ; i++) {
 40             status_t err = getService(name, &mHfNativeServer);
 41             if (err == NAME_NOT_FOUND) {
 42                 usleep(250000);
 43                 continue;
 44             }
 45             if (err != NO_ERROR) {
 46                 return err;
 47             }
 48             break;
 49         }
 50         
 51         init_hfnative();
 52         ALOGI("test hfnativeservice [%d]", test_hfnative(20));
 53 
 54 
 55         class DeathObserver : public IBinder::DeathRecipient {
 56             HfNativeManager& mHfNativeManager;
 57             virtual void binderDied(const wp<IBinder>& who) {
 58                 ALOGW("hfnativeservice died [%p]", who.unsafe_get());
 59                 mHfNativeManager.hfNativeServiceDied();
 60             }
 61         public:
 62             DeathObserver(HfNativeManager& mgr) : mHfNativeManager(mgr) { }
 63         };
 64 
 65         mDeathObserver = new DeathObserver(*const_cast<HfNativeManager *>(this));
 66         mHfNativeServer->asBinder(mHfNativeServer)->linkToDeath(mDeathObserver);
 67     }
 68 
 69     return NO_ERROR;
 70 }
 71 
 72 bool HfNativeManager::checkService() const 
 73 {
 74     return isDied? true:false;
 75 }
 76 
 77 void HfNativeManager::resetServiceStatus() 
 78 {
 79     isDied = false; 
 80 }
 81 
 82 
 83 int HfNativeManager::init_hfnative(void)
 84 {
 85     return mHfNativeServer->init_native(); 
 86 }
 87 
 88 void HfNativeManager::deinit_hfnative(void)
 89 {
 90     mHfNativeServer->finalize_native();
 91 }
 92 
 93 int HfNativeManager::read_queue(char *buff, int len)
 94 {
 95     return mHfNativeServer->read_native(buff,len);
 96 }
 97 
 98 int HfNativeManager::write_queue(char *buff, int len)
 99 {
100     return mHfNativeServer->write_native(buff,len);
101 }
102 
103 int HfNativeManager::test_hfnative(int value)
104 {
105     return mHfNativeServer->test_native(value);
106 }
107 // ----------------------------------------------------------------------------
108 }; // namespace android

 

 

frameworks/native/libs/hfnative/Android.mk

 1 LOCAL_PATH:= $(call my-dir)
 2 include $(CLEAR_VARS)
 3 
 4 LOCAL_SRC_FILES:= \
 5     IHfNativeService.cpp \
 6     HfNativeManager.cpp
 7 
 8 LOCAL_SHARED_LIBRARIES := \
 9     libbinder \
10     libcutils \
11     libutils 
12 
13 LOCAL_MODULE:= libhfnativemgriface
14 
15 #ifneq ($(filter generic%,$(TARGET_DEVICE)),)
16     # Emulator build
17 #    LOCAL_CFLAGS += -DUSE_FENCE_SYNC
18 #endif
19 
20 include $(BUILD_SHARED_LIBRARY)
21 
22 #ifeq (,$(ONE_SHOT_MAKEFILE))
23 #include $(call first-makefiles-under,$(LOCAL_PATH))
24 #endif

 

 

(C) 添加服務端

    服務端說白了就是客戶端的遠程調用,如,客戶端調用write_native()的時候,服務端的write_native()
也會被調用。為什麼客戶端不能直接調用服務端的write_native(),就是因為客戶端和服務端分別處於不同的
進程中,進程間的通訊必須通過Binder、socket等機制進行傳遞。

frameworks/native/services/hfnativeservice/HfNativeService.h

 1 #ifndef ANDROID_HACKFUN_NATIVE_SERVICE_H
 2 #define ANDROID_HACKFUN_NATIVE_SERVICE_H
 3 
 4 #include <stdint.h>
 5 #include <sys/types.h>
 6 
 7 #include <cutils/compiler.h>
 8 
 9 #include <utils/Atomic.h>
10 #include <utils/Errors.h>
11 #include <utils/KeyedVector.h>
12 #include <utils/RefBase.h>
13 #include <utils/SortedVector.h>
14 #include <utils/threads.h>
15 
16 #include <binder/BinderService.h>
17 
18 #include <hfnative/IHfNativeService.h>
19 
20 namespace android {
21 
22 // ---------------------------------------------------------------------------
23 
24 // ---------------------------------------------------------------------------
25 class HfNativeService : public BinderService<HfNativeService>,
26                        public BnHfNativeService
27 {
28 public:
29     static char const* getServiceName() {
30         return "hfnativeservice";
31     }
32 
33     HfNativeService();
34 
35 private:
36     virtual int init_native(void);
37     virtual void finalize_native(void);
38     virtual int read_native(char *Buff, int Len);
39     virtual int write_native(char *Buff, int Len);
40     virtual int test_native(int value);
41 };
42 
43 // ---------------------------------------------------------------------------
44 }; // namespace android
45 
46 #endif // ANDROID_HACKFUN_NATIVE_SERVICE_H

 

 

frameworks/native/services/hfnativeservice/HfNativeService.cpp

  1 #include <stdint.h>
  2 #include <math.h>
  3 #include <sys/types.h>
  4 
  5 #include <utils/Errors.h>
  6 #include <utils/RefBase.h>
  7 #include <utils/Singleton.h>
  8 #include <utils/String16.h>
  9 
 10 #include <binder/BinderService.h>
 11 #include <binder/IServiceManager.h>
 12 
 13 #include <hfnative/IHfNativeService.h>
 14 
 15 #include "HfNativeService.h"
 16 
 17 #include <utils/misc.h>
 18 #include <hardware/hardware.h>
 19 #include <hardware/opersyshw.h> 
 20 
 21 #include <stdio.h>
 22 
 23 namespace android {
 24 // ---------------------------------------------------------------------------
 25 
 26 
 27 opersyshw_device_t* opersyshw_dev; 
 28 
 29 
 30 HfNativeService::HfNativeService()
 31 {
 32 }
 33 
 34 int HfNativeService::init_native(void)
 35 {
 36     int err;
 37     hw_module_t* module;
 38     opersyshw_device_t* dev = NULL;
 39     
 40     ALOGI("init_native()"); 
 41     
 42     err = hw_get_module(OPERSYSHW_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
 43     if (err == 0) {
 44         if (module->methods->open(module, "", ((hw_device_t**) &dev)) != 0) {
 45             ALOGE("Can't open opersys module!!!");
 46             return 0;
 47         }
 48     } else {
 49         ALOGE("Can't get opersys module!!!"); 
 50         return 0;
 51     }
 52     
 53     opersyshw_dev = dev;
 54 
 55     return 0;
 56 }
 57 
 58 void HfNativeService::finalize_native(void)
 59 {
 60     opersyshw_device_t* dev = opersyshw_dev;
 61     
 62     ALOGI("finalize_native()");
 63 
 64     if (dev == NULL) {
 65         return;
 66     }
 67 
 68     dev->close();
 69 
 70     free(dev);
 71 }
 72 
 73 
 74 int HfNativeService::read_native(char *Buff, int Len)
 75 {
 76     opersyshw_device_t* dev = opersyshw_dev;
 77     char* real_byte_array = Buff;
 78     int length;
 79     
 80     ALOGI("read_native()");
 81 
 82     if (dev == NULL) {
 83         return 0;
 84     }
 85 
 86     length = dev->read((char*) real_byte_array, Len);
 87     
 88     ALOGI("read data from hal: %s", (char *)real_byte_array);
 89 
 90     return length;
 91 }
 92 
 93 int HfNativeService::write_native(char *Buff, int Len)
 94 {
 95     opersyshw_device_t* dev = opersyshw_dev;
 96     char* real_byte_array = Buff;
 97     int length;
 98 
 99     ALOGI("write_native()");
100 
101     if (dev == NULL) {
102         return 0;
103     }
104 
105     length = dev->write((char*) real_byte_array, Len);
106     
107     ALOGI("write data to hal: %s", (char *)real_byte_array);
108 
109     return length;
110 }
111 
112 int HfNativeService::test_native(int value)
113 {
114     opersyshw_device_t* dev = opersyshw_dev;
115 
116     if (dev == NULL) {
117         return 0;
118     }
119     
120     ALOGI("test_native()");
121 
122     return dev->test(value);
123 }
124 
125 // ---------------------------------------------------------------------------
126 }; // namespace android

 

 

frameworks/native/services/hfnativeservice/Android.mk

 1 LOCAL_PATH:= $(call my-dir)
 2 include $(CLEAR_VARS)
 3 
 4 LOCAL_SRC_FILES:= \
 5     HfNativeService.cpp \
 6 
 7 LOCAL_CFLAGS:= -DLOG_TAG=\"HfNativeService\"
 8 
 9 LOCAL_C_INCLUDES += \
10     $(call include-path-for, libhardware)/hardware
11 
12 LOCAL_SHARED_LIBRARIES := \
13     libcutils \
14     libutils \
15     libbinder \
16     libhardware \
17     libhfnativemgriface
18 
19 LOCAL_MODULE:= libhfnativeservice
20 
21 include $(BUILD_SHARED_LIBRARY)

 

 

(D) 註冊服務端
這裡啟動添加的的服務,使其運行於一個獨立的進程中,等待客戶端的請求。

frameworks/native/cmds/hfnative/main_hfnativeservice.cpp

 1 #include <binder/BinderService.h>
 2 #include <HfNativeService.h>
 3 #include <binder/IPCThreadState.h>
 4 #include <binder/ProcessState.h>
 5 #include <binder/IServiceManager.h>
 6 
 7 #include <hfnative/IHfNativeService.h>
 8 
 9 using namespace android;
10 
11 int main(int argc, char** argv) {
12 #if 1
13     HfNativeService::publishAndJoinThreadPool(true);
14     // Like the SurfaceFlinger, limit the number of binder threads to 4.
15     ProcessState::self()->setThreadPoolMaxThreadCount(4);
16 #else
17     
18     sp<ProcessState> proc(ProcessState::self());
19 
20     sp<IServiceManager> sm = defaultServiceManager();
21 
22     sm->addService(String16("hfnativeservice"), new HfNativeService());
23 
24     ProcessState::self()->startThreadPool();
25     ProcessState::self()->giveThreadPoolName();

              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、安裝環境 1、安裝VS2017 2、安裝Xamarin擴展包 3、安裝NDK 工具欄中,一個為AVD(模擬器管理)一個為NDK(管理Andoid SDK) 3.1 先打開NDK,在Tools\Options中設置代理(因是要從Goolge下載,所以需要設置代理) ,這裡我使用的是mirrors. ...
  • 1.Manifest合併 在Android studio編譯項目時,無論你使用了幾個Module都會把所有Manifest最終合併成一個,需要我們註意的是application標簽下這個幾個屬性引用的值。 如果多個Module有相同名字的資源,在編譯時會不知道引用哪個資源而導致Manifest合併失 ...
  • post方式請求數據 分析: 1、將請求方式改成post conn.setRequestMethod("POST"); 2、設置連接可以輸出 conn.setDoOutput(true); 3、告訴伺服器客戶端提交的數據類型(表單數據) conn.setRequestProperty("Conten ...
  • 在這個競爭激烈的設計行業里,只滿足自己當下的成績是愚昧的,比你優秀的人還在努力,你怎麼可以躺屍呢?作為一名UX設計師,提高自己的設計水平是為了給自己增值,讓更多人能看到你優秀的作品。然而要如何提高自身的設計水平呢? 1. 好記性不如爛筆頭—多畫圖 畫圖不是為了好看美觀,是為了能保留設計師腦袋裡的想法 ...
  • FileUriExposedException 在給app做版本升級的時候,先從伺服器下載新版本的apk文件到sdcard路徑,然後調用安裝apk的代碼,一般寫法如下: 這樣的寫法在Android7.0版本之前是沒有任何問題,只要給一個apk文件路徑就能打開安裝。但是在Android7.0版本上會報 ...
  • 最近項目有個需求,手機設備連接多個藍牙4.0 設備 並獲取這些設備的數據。 查詢了很多資料終於實現,現進行總結。 從零開始實現一個連接多個藍牙4.0 設備並獲取數據的 Demo 註:如果不想看實現過程的,直接看最下麵的demo源碼即可,或每一步後相關操作步驟的完整代碼。 一、Demo需求 1、搜索設 ...
  • 輸入:Bitmap對象、保存的路徑、保存的文件名 註意路徑的最後要帶上 '/' 符號 ...
  • Html代碼查看器 效果: 分析: 1、連接網路需要許可權 <uses-permission android:name="android.permission.INTERNET" /> 2、要把預設協議和預設埠http和80寫上 3、把訪問網路的代碼放在AsyncTask裡面 4、得到內容類型兩種方 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...