基於Linux的kfifo移植到STM32(支持os的互斥訪問)

来源:https://www.cnblogs.com/iot-dev/archive/2019/10/16/11688794.html
-Advertisement-
Play Games

基於Linux的kfifo移植到STM32(支持os的互斥訪問) 關於kfifo kfifo是內核裡面的一個First In First Out數據結構,它採用環形迴圈隊列的數據結構來實現;它提供一個無邊界的位元組流服務,最重要的一點是,它使用並行無鎖編程技術,即當它用於只有一個入隊線程和一個出隊線程 ...


基於Linux的kfifo移植到STM32(支持os的互斥訪問)

關於kfifo

kfifo是內核裡面的一個First In First Out數據結構,它採用環形迴圈隊列的數據結構來實現;它提供一個無邊界的位元組流服務,最重要的一點是,它使用並行無鎖編程技術,即當它用於只有一個入隊線程和一個出隊線程的場情時,兩個線程可以併發操作,而不需要任何加鎖行為,就可以保證kfifo的線程安全。

具體什麼是環形緩衝區,請看我以前的文章

說明

關於kfifo的相關概念我不會介紹,有興趣可以看他的相關文檔,我只將其實現過程移植重寫,移植到適用stm32開發板上,並且按照我個人習慣重新命名,RingBuff->意為環形緩衝區

RingBuff_t

環形緩衝區的結構體成員變數,具體含義看註釋。
buffer: 用於存放數據的緩存
size: buffer空間的大小
in, out: 和buffer一起構成一個迴圈隊列。 in指向buffer中隊頭,而且out指向buffer中的隊尾

typedef struct ringbuff 
{
    uint8_t *buffer;    /* 數據區域 */
    uint32_t size;      /* 環形緩衝區大小 */
    uint32_t in;        /* 數據入隊指針 (in % size) */
    uint32_t out;       /* 數據出隊指針 (out % size) */
#if USE_MUTEX
    MUTEX_T *mutex;       /* 支持rtos的互斥 */
#endif
}RingBuff_t ;

Create_RingBuff

創建一個環形緩衝區,為了適應後續對緩衝區入隊出隊的高效操作,環形緩衝區的大小應為2^n位元組,
如果不是這個大小,則系統預設裁剪以對應緩衝區位元組。
當然還可以優化,不過我目前並未做,思路如下:如果系統支持動態分配記憶體,則向上對齊,避免浪費記憶體空間,否則就按照我預設的向下對齊,當記憶體越大,對齊導致記憶體泄漏則會越多。對齊採用的函數是roundup_pow_of_two。如果系統支持互斥量,那麼還將創建一個互斥量用來做互斥訪問,防止多線程同時使用導致數據丟失。

/************************************************************
  * @brief   Create_RingBuff
  * @param   rb:環形緩衝區句柄
  *          buffer:環形緩衝區的數據區域
  *          size:環形緩衝區的大小,緩衝區大小要為2^n
  * @return  err_t:ERR_OK表示創建成功,其他表示失敗
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    用於創建一個環形緩衝區
  ***********************************************************/
err_t Create_RingBuff(RingBuff_t* rb, 
                      uint8_t *buffer,
                      uint32_t size
                                )
{
    if((rb == NULL)||(buffer == NULL)||(size == 0))
    {
        PRINT_ERR("data is null!");
        return ERR_NULL;
    }
    
    PRINT_DEBUG("ringbuff size is %d!",size);
    /* 緩衝區大小必須為2^n位元組,系統會強制轉換,
         否則可能會導致指針訪問非法地址。
         空間大小越大,強轉時丟失記憶體越多 */
    if(size&(size - 1))
    {
        size = roundup_pow_of_two(size);
        PRINT_DEBUG("change ringbuff size is %d!",size);
    }

    rb->buffer = buffer;
    rb->size = size;
    rb->in = rb->out = 0;
#if USE_MUTEX   
  /* 創建信號量不成功 */
  if(!create_mutex(rb->mutex))
  {
    PRINT_ERR("create mutex fail!");
    ASSERT(ASSERT_ERR);
    return ERR_NOK;
  }
#endif
    PRINT_DEBUG("create ringBuff ok!");
    return ERR_OK;
}

roundup_pow_of_two

/************************************************************
  * @brief   roundup_pow_of_two
  * @param   size:傳遞進來的數據長度
  * @return  size:返回處理之後的數據長度
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    用於處理數據,使數據長度必須為 2^n
    *                    如果不是,則轉換,丟棄多餘部分,如
    *                    roundup_pow_of_two(66) -> 返回 64
  ***********************************************************/
static unsigned long roundup_pow_of_two(unsigned long x)
{
    return (1 << (fls(x-1)-1));             //向下對齊
  //return (1UL << fls(x - 1));         //向上對齊,用動態記憶體可用使用
}

Delete_RingBuff

刪除一個環形緩衝區,刪除之後,緩衝區真正存儲地址是不會被改變的(目前我是使用自定義數組做緩衝區的),但是刪除之後,就無法對緩衝區進行讀寫操作。並且如果支持os的話,創建的互斥量會被刪除。

/************************************************************
  * @brief   Delete_RingBuff
  * @param   rb:環形緩衝區句柄
  * @return  err_t:ERR_OK表示成功,其他表示失敗
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    刪除一個環形緩衝區
  ***********************************************************/
err_t Delete_RingBuff(RingBuff_t *rb)
{
    if(rb == NULL)
    {
        PRINT_ERR("ringbuff is null!");
        return ERR_NULL;
    }
    
    rb->buffer = NULL;
    rb->size = 0;
    rb->in = rb->out = 0;
#if USE_MUTEX   
  if(!deleta_mutex(rb->mutex))
  {
    PRINT_DEBUG("deleta mutex is fail!");
    return ERR_NOK;
  }
#endif
    return ERR_OK;
}

Write_RingBuff

向環形緩衝區寫入指定數據,支持線程互斥訪問。用戶想要寫入緩衝區的數據長度不一定是真正入隊的長度,在完成的時候還要看看返回值是否與用戶需要的長度一致~
這個函數很有意思,也是比較高效的入隊操作,將指定區域的數據拷貝到指定的緩衝區中,過程看註釋即可

/************************************************************
  * @brief   Write_RingBuff
  * @param   rb:環形緩衝區句柄
  * @param   wbuff:寫入的數據起始地址
  * @param   len:寫入數據的長度(位元組)
  * @return  len:實際寫入數據的長度(位元組)
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    這個函數會從buff空間拷貝len位元組長度的數據到
             rb環形緩衝區中的空閑空間。
  ***********************************************************/
uint32_t Write_RingBuff(RingBuff_t *rb,
                        uint8_t *wbuff, 
                        uint32_t len)
{
  uint32_t l;
#if USE_MUTEX
  /* 請求互斥量,成功才能進行ringbuff的訪問 */
  if(!request_mutex(rb->mutex))
  {
    PRINT_DEBUG("request mutex fail!");
    return 0;
  }
  else  /* 獲取互斥量成功 */
  {
#endif
    len = min(len, rb->size - rb->in + rb->out);

    /* 第一部分的拷貝:從環形緩衝區寫入數據直至緩衝區最後一個地址 */
    l = min(len, rb->size - (rb->in & (rb->size - 1)));
    memcpy(rb->buffer + (rb->in & (rb->size - 1)), wbuff, l);

    /* 如果溢出則在緩衝區頭寫入剩餘的部分
       如果沒溢出這句代碼相當於無效 */
    memcpy(rb->buffer, wbuff + l, len - l);

    rb->in += len;
    
    PRINT_DEBUG("write ringBuff len is %d!",len);
#if USE_MUTEX
  }
  /* 釋放互斥量 */
  release_mutex(rb->mutex);
#endif
  return len;
}

Read_RingBuff

讀取緩衝區數據到指定區域,用戶指定讀取長度,用戶想要讀取的長度不一定是真正讀取的長度,在讀取完成的時候還要看看返回值是否與用戶需要的長度一致~也支持多線程互斥訪問。
也是緩衝區出隊的高效操作。過程看代碼註釋即可

/************************************************************
  * @brief   Read_RingBuff
  * @param   rb:環形緩衝區句柄
  * @param   wbuff:讀取數據保存的起始地址
  * @param   len:想要讀取數據的長度(位元組)
  * @return  len:實際讀取數據的長度(位元組)
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    這個函數會從rb環形緩衝區中的數據區域拷貝len位元組
             長度的數據到rbuff空間。
  ***********************************************************/
uint32_t Read_RingBuff(RingBuff_t *rb,
                       uint8_t *rbuff, 
                       uint32_t len)
{
  uint32_t l;
#if USE_MUTEX
  /* 請求互斥量,成功才能進行ringbuff的訪問 */
  if(!request_mutex(rb->mutex))
  {
    PRINT_DEBUG("request mutex fail!");
    return 0;
  }
  else
  {
#endif
    len = min(len, rb->in - rb->out);

    /* 第一部分的拷貝:從環形緩衝區讀取數據直至緩衝區最後一個 */
    l = min(len, rb->size - (rb->out & (rb->size - 1)));
    memcpy(rbuff, rb->buffer + (rb->out & (rb->size - 1)), l);

    /* 如果溢出則在緩衝區頭讀取剩餘的部分
       如果沒溢出這句代碼相當於無效 */
    memcpy(rbuff + l, rb->buffer, len - l);

    rb->out += len;
    
    PRINT_DEBUG("read ringBuff len is %d!",len);
#if USE_MUTEX
  }
  /* 釋放互斥量 */
  release_mutex(rb->mutex);
#endif
  return len;
}

獲取緩衝區信息

這些就比較簡單了,看看緩衝區可讀可寫的數據有多少

/************************************************************
  * @brief   CanRead_RingBuff
    * @param   rb:環形緩衝區句柄
    * @return  uint32:可讀數據長度 0 / len
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    可讀數據長度
  ***********************************************************/
uint32_t CanRead_RingBuff(RingBuff_t *rb)
{
    if(NULL == rb)
    {
        PRINT_ERR("ringbuff is null!");
        return 0;
    }
    if(rb->in == rb->out)
        return 0;
    
    if(rb->in > rb->out)
        return (rb->in - rb->out);
    
    return (rb->size - (rb->out - rb->in));
}

/************************************************************
  * @brief   CanRead_RingBuff
    * @param   rb:環形緩衝區句柄
    * @return  uint32:可寫數據長度 0 / len
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    可寫數據長度
  ***********************************************************/
uint32_t CanWrite_RingBuff(RingBuff_t *rb)
{
    if(NULL == rb)
    {
        PRINT_ERR("ringbuff is null!");
        return 0;
    }

    return (rb->size - CanRead_RingBuff(rb));
}

附帶

這裡的代碼我是用於測試的,隨便寫的

    RingBuff_t ringbuff_handle;
    
    uint8_t rb[64];
    uint8_t res[64];
    Create_RingBuff(&ringbuff_handle, 
                                rb,
                                sizeof(rb));
            Write_RingBuff(&ringbuff_handle,
                     res, 
                     datapack.data_length);
            
            PRINT_DEBUG("CanRead_RingBuff = %d!",CanRead_RingBuff(&ringbuff_handle));
            PRINT_DEBUG("CanWrite_RingBuff = %d!",CanWrite_RingBuff(&ringbuff_handle));
            
            Read_RingBuff(&ringbuff_handle,
                     res, 
                     datapack.data_length);

支持多個os的互斥量操作

此處模仿了文件系統的互斥操作

#if USE_MUTEX
#define  MUTEX_TIMEOUT   1000     /* 超時時間 */
#define  MUTEX_T         mutex_t  /* 互斥量控制塊 */
#endif

/*********************************** mutex **************************************************/
#if USE_MUTEX
/************************************************************
  * @brief   create_mutex
  * @param   mutex:創建信號量句柄
  * @return  創建成功為1,0為不成功。
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    創建一個互斥量,用戶在os中互斥使用ringbuff,
  *          支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
  ***********************************************************/
static err_t create_mutex(MUTEX_T *mutex)
{
  err_t ret = 0;

//  *mutex = rt_mutex_create("test_mux",RT_IPC_FLAG_PRIO); /* rtt */
//  ret = (err_t)(*mutex != RT_NULL);
    
//  *mutex = CreateMutex(NULL, FALSE, NULL);        /* Win32 */
//  ret = (err_t)(*mutex != INVALID_HANDLE_VALUE);

//  *mutex = OSMutexCreate(0, &err);        /* uC/OS-II */
//  ret = (err_t)(err == OS_NO_ERR);

//  *mutex = xSemaphoreCreateMutex();   /* FreeRTOS */
//  ret = (err_t)(*mutex != NULL);

//  ret = LOS_MuxCreate(&mutex);  /* LiteOS */
//  ret = (err_t)(ret != LOS_OK);
  return ret;
}
/************************************************************
  * @brief   deleta_mutex
  * @param   mutex:互斥量句柄
  * @return  NULL
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    刪除一個互斥量,支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
  ***********************************************************/
static err_t deleta_mutex(MUTEX_T *mutex)
{
    err_t ret;
    
//  ret = rt_mutex_delete(mutex);   /* rtt */
    
//  ret = CloseHandle(mutex);   /* Win32 */

//  OSMutexDel(mutex, OS_DEL_ALWAYS, &err); /* uC/OS-II */
//  ret = (err_t)(err == OS_NO_ERR);

//  vSemaphoreDelete(mutex);        /* FreeRTOS */
//  ret = 1;

//  ret = LOS_MuxDelete(&mutex);  /* LiteOS */
//  ret = (err_t)(ret != LOS_OK);

    return ret;
}
/************************************************************
  * @brief   request_mutex
  * @param   mutex:互斥量句柄
  * @return  NULL
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    請求一個互斥量,得到互斥量的線程才允許進行訪問緩衝區
  *          支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
  ***********************************************************/
static err_t request_mutex(MUTEX_T *mutex)
{
    err_t ret;

//  ret = (err_t)(rt_mutex_take(mutex, MUTEX_TIMEOUT) == RT_EOK);/* rtt */
    
//  ret = (err_t)(WaitForSingleObject(mutex, MUTEX_TIMEOUT) == WAIT_OBJECT_0);  /* Win32 */

//  OSMutexPend(mutex, MUTEX_TIMEOUT, &err));       /* uC/OS-II */
//  ret = (err_t)(err == OS_NO_ERR);

//  ret = (err_t)(xSemaphoreTake(mutex, MUTEX_TIMEOUT) == pdTRUE);  /* FreeRTOS */

//  ret = (err_t)(LOS_MuxPend(mutex,MUTEX_TIMEOUT) == LOS_OK);          /* LiteOS */

    return ret;
}
/************************************************************
  * @brief   release_mutex
  * @param   mutex:互斥量句柄
  * @return  NULL
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    釋放互斥量,當線程使用完資源必須釋放互斥量
  *          支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
  ***********************************************************/
static void release_mutex(MUTEX_T *mutex)
{
//  rt_mutex_release(mutex);/* rtt */
    
//  ReleaseMutex(mutex);        /* Win32 */

//  OSMutexPost(mutex);     /* uC/OS-II */

//  xSemaphoreGive(mutex);  /* FreeRTOS */

//  LOS_MuxPost(mutex);   /* LiteOS */
}
#endif
/*********************************** mutex **************************************************/

debug.h

最後送一份debug的簡便操作源碼,因為前文很多時候會調用
PRINT_ERR
PRINT_DEBUG

#ifndef _DEBUG_H
#define _DEBUG_H
/************************************************************
  * @brief   debug.h
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    此文件用於列印日誌信息
  ***********************************************************/
/**
* @name Debug print 
* @{
*/
#define PRINT_DEBUG_ENABLE      1       /* 列印調試信息 */
#define PRINT_ERR_ENABLE            1   /* 列印錯誤信息 */
#define PRINT_INFO_ENABLE           0       /* 列印個人信息 */


#if PRINT_DEBUG_ENABLE
#define PRINT_DEBUG(fmt, args...)    do{(printf("\n[DEBUG] >> "), printf(fmt, ##args));}while(0)     
#else
#define PRINT_DEBUG(fmt, args...)        
#endif

#if PRINT_ERR_ENABLE
#define PRINT_ERR(fmt, args...)      do{(printf("\n[ERR] >> "), printf(fmt, ##args));}while(0)     
#else
#define PRINT_ERR(fmt, args...)        
#endif

#if PRINT_INFO_ENABLE
#define PRINT_INFO(fmt, args...)     do{(printf("\n[INFO] >> "), printf(fmt, ##args));}while(0)     
#else
#define PRINT_INFO(fmt, args...)           
#endif

/**@} */
    
//針對不同的編譯器調用不同的stdint.h文件
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
    #include <stdint.h>
#endif

/* 斷言 Assert */
#define AssertCalled(char,int)  printf("\nError:%s,%d\r\n",char,int)
#define ASSERT(x)   if((x)==0)  AssertCalled(__FILE__,__LINE__)
  
typedef enum 
{
    ASSERT_ERR = 0,                             /* 錯誤 */
    ASSERT_SUCCESS = !ASSERT_ERR    /* 正確 */
} Assert_ErrorStatus;

typedef enum 
{
    FALSE = 0,      /* 假 */
    TRUE = !FALSE   /* 真 */
}ResultStatus;

#endif /* __DEBUG_H */

喜歡就關註我吧!

歡迎關註我公眾號

相關代碼可以在公眾號後臺獲取。
更多資料歡迎關註“物聯網IoT開發”公眾號!


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

-Advertisement-
Play Games
更多相關文章
  • 消息隊列 在前一篇文章中 "【TencentOS tiny學習】源碼分析(3)——隊列" 我們描述了TencentOS tiny的隊列實現,同時也點出了TencentOS tiny的隊列是依賴於消息隊列的,那麼我們今天來看看消息隊列的實現。 其實消息隊列是TencentOS tiny的一個 基礎組件 ...
  • 隊列基本概念 隊列是一種常用於任務間通信的數據結構,隊列可以在 傳遞消息,實現了任務接收來自其他任務或中斷的不固定長度的消息,任務能夠從隊列裡面讀取消息,當隊列中的消息是空時,讀取消息的任務將被阻塞,用戶還可以指定任務等待消息的時間 ,在這段時間中,如果隊列為空,該任務將 狀態以等待隊列數據有效。當 ...
  • 溫馨提示:本文不描述與浮點相關的寄存器的內容,如需瞭解自行查閱(畢竟我自己也不懂) 調度器的基本概念 中提供的任務調度器是基於優先順序的全搶占式調度,在系統運行過程中,當有比當前任務優先順序更高的任務就緒時,當前任務將立刻被 ,高優先順序任務 處理器運行。 內核中也允許創建相同優先順序的任務。相同優先順序的任 ...
  • 任務的基本概念 從系統的角度看,任務是競爭系統資源的最小運行單元。TencentOS tiny是一個支持多任務的操作系統,任務可以使用或等待CPU、使用記憶體空間等系統資源,並獨立於其它任務運行,理論上任何數量的任務都可以共用同一個優先順序,這樣子處於就緒態的多個相同優先順序任務將會以時間片切換的方式共用 ...
  • 移植前的準備工作 1. 獲取STM32的裸機工程模板 STM32的裸機工程模板直接使用野火STM32開發板配套的固件庫常式即可。可以從我 上獲取 "https://github.com/jiejieTop/TencentOS Demo" 下載TencentOS tiny 源碼 TencentOS t ...
  • 新聞 2019年9月18日,騰訊宣佈將 `自主研發 輕量級`物聯網實時操作系統 TencentOS tiny 。相比市場上其它系統,騰訊TencentOS tiny在資源占用、設備成本、功耗管理以及安全穩定等層面極具競爭力。該系統的開源可大幅降低物聯網應用開發成本,提升開發效率,同時支持一鍵上雲,對 ...
  • 今天,需要再本地使用git管理代碼,但是當代碼創建好的時候,想發佈到github上面的私有倉庫中,但是沒有提前創建遠端倉庫,所以需要把本地git倉庫推送到遠端另外一個倉庫了,下麵進行簡要記錄,剛剛經過的過程,方便之後再次使用的時候,不會重覆勞動: git 設置 git config user.nam ...
  • button drive 傑傑自己寫的一個按鍵驅動,支持單雙擊、連按、長按;採用回調處理按鍵事件(自定義消抖時間),使用只需3步,創建按鍵,按鍵事件與回調處理函數鏈接映射,周期檢查按鍵。 源碼地址: "https://github.com/jiejieTop/ButtonDrive" 。作者: "傑 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...