zoukankan      html  css  js  c++  java
  • 总结阿里云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);
          ...
        }
  • 相关阅读:
    Android 中常用代码片段
    查看oracle中的中文所占字节数
    order by 中 使用decode
    Oracle select 中case 的使用以及使用decode替换case
    pyqt5 'QWidget' object has no attribute 'setCentralWidget'(转)
    程序员之路:python3+PyQt5+pycharm桌面GUI开发(转)
    QT5入门之23 -QT串口编程(转)
    xpath-helper: 谷歌浏览器安装xpath helper 插件
    mysql给root开启远程访问权限
    Vmware无法获取快照信息 锁定文件失败
  • 原文地址:https://www.cnblogs.com/wggj/p/9176144.html
Copyright © 2011-2022 走看看