總結阿里雲OSS的開發坑(C/C++篇)


一、序言

OSS(Object Storage Service)是阿里雲提供的一款雲存儲服務,具有海量、安全、低成本、高可靠的特點。

由於客戶選擇了OSS,我們作為開發方也開始接觸它。在實際開發過程中遇到了各種各樣的坑,經自己多次實踐及阿里技術人員的協助,終得以完成任務。

阿里方面為OSS提供了多種語言的開發接口,我們用到了其中兩種:Java和C/C++。本文為C/C++篇,Java的已在另一篇給出。

二、OSS的一些概念

  • EndPoint, accessKeyID, accessKeySecret:欲使用OSS,先要在阿里雲上申請相應的空間資源,而EndPoint, accessKeyID, accessKeySecret則相當於域名、賬號和密碼,是所申請資源的使用憑證,需要妥善保管。
  • Bucket:是用於存儲對象的容器,所有對象都必須屬於且只屬於一個Bucket,Bucket的屬性(控制地域、訪問權限、生命周期等)對所有對象都同等有效,同一空間資源下Bucket名必須唯一,且創建后不能再改名。
  • 對象/文件:對象/文件是 OSS 存儲數據的基本單元。對象/文件由元信息(Object Meta),用戶數據(Data)和文件名(Key)組成。文件名是唯一的,重復上傳同名的對象意味着覆蓋以前內容,但OSS支持在已有對象后部追加數據。
  • 目錄:其實是一種特殊的對象(無Data),僅僅是為了管理方便,除此以外並無多大意義。
  • 其它概念,如分片、回調、追加、權限等,因開發中未涉及,不再展開,有興趣者請參考:https://help.aliyun.com/document_detail/31827.html?spm=a2c4g.11186623.4.1.TamX1d

 三、1號坑:C SDK提供的接口較少

嚴格地講,也許這算不上是坑,權當是本文為湊數。

與Java SDK相比,C SDK中缺少一些接口,比如判斷某個Bucket是否已經存在,Java SDK中有,而C SDK中沒有。

四、2號坑:Windows平台的64位庫

一開始阿里雲只提供了Windows平台的32位庫(動態和靜態),主要原因是oss-c-sdk所使用的依賴庫在windows平台需經很多修改才支持64位。后來在客戶的強烈要求下,阿里雲方面緊急補充了64位Windows庫。在此非常感謝阿里雲工程師的辛勤工作。

不過,64位庫貌似不是很穩定,運行時程序偶爾會奔潰。當然,這與本人C/C++水平比較菜的不無關系,這口鍋是由本人來背好了。

五、3號坑:關於EndPoint的特殊格式

通常情況下,OSS所用到的endPoint類似這樣:oss-cn-beijing.aliyuncs.com。

但在某些場合(如本項目客戶方的私有雲),endPoint中包含了Bucket名,類似這樣:oss-cn-beijing.aliyuncs.com/bucket01。

在Java程序中,只須將Bucket名從中解析出來,不必修改endPoint,可以正常運行。但在C/C++程序中,這樣做會報錯“Invalid host name”。

正確的做法是:將包含有Bucket名的EndPoint拆分為兩部分,"/"前為endPoint,后為Bucket名,問題解決。

六、4號坑:關於保存endPoint、accessKeyId、accessKeySecret值的變量

這是本項目遇到過的最大坑,沒有之一。

在阿里提供的示例代碼中,使用的是常量直接賦值,不會出任何問題。但本項目把這些值放在配置文件中,由程序讀出到局部變量后再賦值,問題就來了,運行一會這些值就變成亂碼。

后來把oss-c-sdk的源碼、所依賴底層庫的源碼都加進去調試跟蹤,才找到原因所在:aos_str_set函數只是簡單地賦地址指針的值,而沒有執行memcpy,因此一旦有函數傳遞,局部變量的地址空間被回收,值也變成亂碼。

解決方法:使用全局變量或類成員變量來保存從配置文件讀取到的值,確保在程序的生命周期內不會被回收。

頭文件示例代碼:

        class OssMntData : public MntData
        {
        private:
// 從配置文件讀取的參數必須保持地址空間,不能使用臨時變量
            char                    m_endpoint[64];
            char                    m_keyid[64];
            char                    m_keysecret[64];
            char                    m_bucketname[64];
            ...
       public:
            ...
       }

C/C++文件示例代嗎:

        aos_pool_t *pool = NULL;
        oss_request_options_t *options = NULL;

        aos_pool_create(&pool, NULL);
        options = oss_request_options_create(pool);
        options->config = oss_config_create(options->pool);
        aos_str_set(&options->config->endpoint, m_endpoint);
        aos_str_set(&options->config->access_key_id, m_keyid);
        aos_str_set(&options->config->access_key_secret, m_keysecret);
        options->config->is_cname = 0;
        options->ctl = aos_http_controller_create(options->pool, 0);

七、其它坑

與Java程序一樣,如果遍歷OSS對象的同時進行修改,會陷入死循環。請參加Java篇,不再重復。

如果使用UserMetaData保存屬性值,其key會在存入時自動轉換為小寫。

提醒:C SDK中,UserMetaData中的key須加上“x-oss-meta-”的前綴,以示與自帶的元數據區別。而在Java代碼中沒有這個要求。

示例代碼:

    int OssMntData::Write()
    {    
      //將相關屬性值存放到metadata中
      aos_table_t *header = aos_table_make(pool, 1);
      apr_table_set(header, "x-oss-meta-author", author);
      apr_table_set(header, "x-oss-meta-version", version);
      ...
      aos_status_t *status = oss_put_object_from_buffer(options, &m_bucket, &ossKey, &buffer, header, &resp_header);
         ...
    }            

    int OssMntData::Read()
    {
      //讀取UserMeta,為各屬性字段賦值
      header = aos_table_make(pool, 0);
      resp_header = NULL;
      status = oss_head_object(options, &m_bucket, &ossKey, header, &resp_header);
      char *s = (char *)apr_table_get(resp_header, "x-oss-meta-author");
      if (s) strcpy(mnt->author, s);
      s = (char *)apr_table_get(resp_header, "x-oss-meta-version");
      if (s) strcpy(mnt->version, s);
      ...
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM