更新时间:2026-07-13 GMT+08:00
分享

上传限速(C SDK)

开发过程中,您有任何问题可以在GitHub上提交issue,或者在华为云对象存储服务论坛中发帖求助。

功能说明

上传限速是指在上传对象时对单链接请求的带宽进行限制,避免因单个上传请求占用过多带宽而影响其他业务。通过obs_put_properties结构体的upload_limit字段设置限速值,SDK将限速值写入x-obs-traffic-limit请求头,由OBS服务端进行精确的带宽控制

支持上传限速的接口包括:

接口约束

  • 您必须是桶拥有者或拥有上传对象的权限,才能使用上传限速功能。建议使用IAM或桶策略进行授权,如果使用IAM则需授予obs:object:PutObject权限,如果使用桶策略则需授予PutObject权限。相关授权方式介绍可参见OBS权限控制概述,配置方式详见使用IAM自定义策略配置对象策略
  • OBS支持的Region与Endpoint的对应关系,详细信息请参见地区与终端节点
  • 限速值upload_limit为0时表示不限速。
  • 限速值为服务端强制执行,设置后上传请求的最大带宽不会超过设定值,精确度由服务端保证。
  • 分段上传(upload_file)也支持限速,通过obs_upload_file_configuration结构体的upload_limit字段设置。

方法定义

上传限速通过obs_put_properties结构体的upload_limit字段实现,该结构体作为上传接口的参数传入:

void put_object(const obs_options *options, char *key, uint64_t content_length,
    obs_put_properties *put_properties,
    server_side_encryption_params *encryption_params,
    obs_put_object_handler *handler, void *callback_data);

void put_object_content(const obs_options *options, const char *key,
    const char *content, uint64_t content_length,
    obs_put_properties *put_properties,
    server_side_encryption_params *encryption_params,
    obs_put_object_handler *handler, void *callback_data);

void put_file(const obs_options *options, const char *key,
    const char *file_path,
    obs_put_properties *put_properties,
    server_side_encryption_params *encryption_params,
    obs_put_object_handler *handler, void *callback_data);

请求参数说明

上传限速相关的参数在obs_put_properties结构体中,可通过init_put_properties初始化该结构体。

表1 obs_put_properties中的限速相关参数

参数名称

参数类型

是否必选

描述

upload_limit

uint64_t

可选

参数解释:

对单链接请求的服务端带宽限制,SDK会将此值写入x-obs-traffic-limit请求头,由OBS服务端执行限速。

约束限制:

取值范围:

0表示不限速;819200~838860800表示限速,单位为bit/s。其中819200 bit/s = 100 KB/s,838860800 bit/s = 100 MB/s。

默认取值:

0(不限速)

限速值选择指南

场景

推荐upload_limit值

说明

不限速(默认)

0

使用默认带宽,适用于无带宽限制的场景

低带宽保底

819200(100 KB/s)

确保上传不会占用过多带宽,适用于带宽紧张环境

中等限速

8192000(1 MB/s)

平衡上传速度与其他业务需求

高带宽限速

81920000(10 MB/s)

限制大文件上传的峰值带宽,适用于大文件场景

接近不限速

838860800(100 MB/s)

设置上限但实际基本不受影响

  • 限速值过低会导致大文件上传耗时显著增加,请根据业务需求合理设置。
  • 限速仅控制单个上传请求的带宽,并发上传时每个请求独立限速,总带宽为所有请求之和。
  • 建议在网络带宽充裕时使用默认值(0,不限速),仅在确实需要限制带宽时设置限速。

代码示例:流式上传时设置限速

以下示例展示如何在上传对象时设置上传限速:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#include "eSDKOBS.h"
#include <stdio.h>
// 响应回调函数,可以在这个回调中把properties的内容记录到callback_data(用户自定义回调数据)中
obs_status response_properties_callback(const obs_response_properties *properties, void *callback_data);
void put_buffer_complete_callback(obs_status status, const obs_error_details *error, void *callback_data);
typedef struct put_buffer_object_callback_data
{
    char *put_buffer;
    uint64_t buffer_size;
    uint64_t cur_offset;
    obs_status ret_status;
} put_buffer_object_callback_data;
int put_buffer_data_callback(int buffer_size, char *buffer, void *callback_data);
char* generate_upload_buffer(uint64_t buffer_size);
int main()
{
    // 以下示例展示如何通过put_object流式上传对象
    // 在程序入口调用obs_initialize方法来初始化网络、内存等全局资源
    obs_initialize(OBS_INIT_ALL); 
    obs_options options;
    // 创建并初始化options,该参数包括访问域名(host_name)、访问密钥(access_key_id和access_key_secret)、桶名(bucket_name)、桶存储类别(storage_class)等配置信息
    init_obs_options(&options);
    // host_name填写桶所在的endpoint, 此处以华北-北京四为例,其他地区请按实际情况填写。
    options.bucket_options.host_name = "obs.cn-north-4.myhuaweicloud.com";
    // 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全
    // 本示例以ak和sk保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量ACCESS_KEY_ID和SECRET_ACCESS_KEY
    options.bucket_options.access_key = getenv("ACCESS_KEY_ID");
    options.bucket_options.secret_access_key = getenv("SECRET_ACCESS_KEY");
    // 填写Bucket名称,例如example-bucket-name。
    char * bucketName = "example-bucket-name";
    options.bucket_options.bucket_name = bucketName;
    // 初始化上传对象属性
    obs_put_properties put_properties;
    init_put_properties(&put_properties);
    // 限速100 KB/s(819200 bit/s)
    put_properties.upload_limit = 819200;
    //初始化存储上传数据的结构体
    put_buffer_object_callback_data data;
    memset(&data, 0, sizeof(put_buffer_object_callback_data));
    // 设置buffersize
    data.buffer_size = 10 * 1024 * 1024;
    // 创建模拟的流式上传数据buffer, 并赋值到上传数据结构中
    data.put_buffer = generate_upload_buffer(data.buffer_size);
    if (NULL == data.put_buffer) {
        printf("generate put buffer failed. \n");
        return -1;
    }
    // 上传的对象名
    char *key = "example_put_buffer_test.txt";
    obs_put_object_handler putobjectHandler =
    {
        { &response_properties_callback, &put_buffer_complete_callback },
          &put_buffer_data_callback
    };
    put_object(&options, key, data.buffer_size, &put_properties, 0, &putobjectHandler, &data);
    if (OBS_STATUS_OK == data.ret_status) {
        printf("put object from buffer successfully. \n");
    }
    else
    {
        printf("put object from buffer failed(%s).\n",
            obs_get_status_name(data.ret_status));
    }
    // 释放模拟的流式上传数据buffer
    free(data.put_buffer);
    // 释放分配的全局资源
    obs_deinitialize();
    return 0;    
}
// 响应回调函数,可以在这个回调中把properties的内容记录到callback_data(用户自定义回调数据)中
obs_status response_properties_callback(const obs_response_properties *properties, void *callback_data)
{
    if (properties == NULL)
    {
        printf("error! obs_response_properties is null!");
        if (callback_data != NULL)
        {
            obs_sever_callback_data *data = (obs_sever_callback_data *)callback_data;
            printf("server_callback buf is %s, len is %llu",
                data->buffer, data->buffer_len);
            return OBS_STATUS_OK;
        }
        else {
            printf("error! obs_sever_callback_data is null!");
            return OBS_STATUS_OK;
        }
    }
    // 打印响应信息
#define print_nonnull(name, field)                                 \
    do {                                                           \
        if (properties-> field) {                                  \
            printf("%s: %s\n", name, properties->field);          \
        }                                                          \
    } while (0)
    print_nonnull("request_id", request_id);
    print_nonnull("request_id2", request_id2);
    print_nonnull("content_type", content_type);
    if (properties->content_length) {
        printf("content_length: %llu\n", properties->content_length);
    }
    print_nonnull("server", server);
    print_nonnull("ETag", etag);
    print_nonnull("expiration", expiration);
    print_nonnull("website_redirect_location", website_redirect_location);
    print_nonnull("version_id", version_id);
    print_nonnull("allow_origin", allow_origin);
    print_nonnull("allow_headers", allow_headers);
    print_nonnull("max_age", max_age);
    print_nonnull("allow_methods", allow_methods);
    print_nonnull("expose_headers", expose_headers);
    print_nonnull("storage_class", storage_class);
    print_nonnull("server_side_encryption", server_side_encryption);
    print_nonnull("kms_key_id", kms_key_id);
    print_nonnull("customer_algorithm", customer_algorithm);
    print_nonnull("customer_key_md5", customer_key_md5);
    print_nonnull("bucket_location", bucket_location);
    print_nonnull("obs_version", obs_version);
    print_nonnull("restore", restore);
    print_nonnull("obs_object_type", obs_object_type);
    print_nonnull("obs_next_append_position", obs_next_append_position);
    print_nonnull("obs_head_epid", obs_head_epid);
    print_nonnull("reserved_indicator", reserved_indicator);
    int i;
    for (i = 0; i < properties->meta_data_count; i++) {
        printf("x-obs-meta-%s: %s\n", properties->meta_data[i].name,
            properties->meta_data[i].value);
    }
    return OBS_STATUS_OK;
}
void put_buffer_complete_callback(obs_status status, const obs_error_details *error, void *callback_data)
{
    if (callback_data) {
        put_buffer_object_callback_data *data = (put_buffer_object_callback_data *)callback_data;
        data->ret_status = status;
    }
    else {
        printf("Callback_data is NULL");
    }
    if (error && error->message) {
        printf("Error Message: \n   %s\n", error->message);
    }
    if (error && error->resource) {
        printf("Error Resource: \n  %s\n", error->resource);
    }
    if (error && error->further_details) {
        printf("Error further_details: \n   %s\n", error->further_details);
    }
    if (error && error->extra_details_count) {
        int i;
        for (i = 0; i < error->extra_details_count; i++) {
            printf("Error Extra Detail(%d):\n   %s:%s\n", i, error->extra_details[i].name,
                error->extra_details[i].value);
        }
    }
    if (error && error->error_headers_count) {
        int i;
        for (i = 0; i < error->error_headers_count; i++) {
            const char *errorHeader = error->error_headers[i];
            printf("Error Headers(%d):\n    %s\n", i, errorHeader == NULL ? "NULL Header" : errorHeader);
        }
    }
}
int put_buffer_data_callback(int buffer_size, char *buffer, void *callback_data)
{
    put_buffer_object_callback_data *data =
        (put_buffer_object_callback_data *)callback_data;
    int toRead = 0;
    if (data->buffer_size) {
        toRead = ((data->buffer_size > (unsigned)buffer_size) ?
            (unsigned)buffer_size : data->buffer_size);
        memcpy_s(buffer, buffer_size, data->put_buffer + data->cur_offset, toRead);
    }
    uint64_t originalContentLength = data->buffer_size;
    data->buffer_size -= toRead;
    data->cur_offset += toRead;
    if (data->buffer_size) {
        printf("%llu bytes remaining ", (unsigned long long)data->buffer_size);
        printf("(%d%% complete) ...\n",
            (int)(((originalContentLength - data->buffer_size) * 100) / originalContentLength));
    }
    return toRead;
}
// 创建模拟的流式上传数据
char* generate_upload_buffer(uint64_t buffer_size) {
    void* upload_buffer = NULL;
    if (buffer_size > 0) {
        upload_buffer = malloc(buffer_size);
        if (upload_buffer != NULL) {
            memset(upload_buffer, 't', buffer_size);
        }
    }
    return upload_buffer;
}

相关链接

  • 关于上传限速的API说明,请参见PUT上传
  • 上传限速过程中返回的错误码含义、问题原因及处理措施可参考OBS错误码

相关文档