You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用OpenLDAP 2.6 C客户端高效收集LDAP搜索属性值至char*[]

优化OpenLDAP 2.6 C客户端搜索结果处理代码

需求背景

使用OpenLDAP 2.6 C客户端库实现LDAP搜索,仅查询mail、mailAlias和mailAccount三个属性。这三个属性均为多值IA5字符串(RFC822邮件地址格式),需要将所有返回的属性值合并为char*[]格式,无需关心值所属的属性或条目。

示例输入结果:

dn: uid=johndoe,ou=users,dc=my-domain,dc=tld
mail: john.doe@somewhere.tld
mail: jdoe@here.tld
mailAccount: john.doe@my-domain.tld
mailAlias: doe@my-domain.tld

期望输出:

char* result[] = { "john.doe@somewhere.tld", "jdoe@here.tld", "john.doe@my-domain.tld", "doe@my-domain.tld" };

当前核心代码

LDAPMessage* ldap_result_msg = NULL;
int result_code = ldap_search_ext_s( ldap_handle, ..., &ldap_result_msg );
// ... 省略错误处理 ...
struct string_array_t* result = create_string_array(); // 类似C++的std::vector<std::string>的动态数组
for(
    LDAPMessage* ldap_entry_msg = ldap_first_entry( ldap_handle, ldap_result_msg );
    ldap_entry_msg != NULL;
    ldap_entry_msg = ldap_next_entry( ldap_handle, ldap_entry_msg )
) {
    BerElement* berptr;
    for(
        char* ldap_attr = ldap_first_attribute( ldap_handle, ldap_entry_msg, &berptr );
        ldap_attr != NULL;
        ldap_attr = ldap_next_attribute( ldap_handle, ldap_entry_msg, berptr )
    ) {
        struct berval** values = ldap_get_values_len( ldap_handle, ldap_entry_msg, ldap_attr );
        char* value = NULL;
        for( int i = 0; values[i] != NULL; ++i ) {
            value = malloc( values[i]->bv_len + 1 );
            strncpy( value, values[i]->bv_val, values[i]->bv_len );
            value[ values[i]->bv_len ] = '\0';
            push_onto_string_array( result, value );
            free( value );
        }
        ldap_value_free_len( values );
        ldap_memfree( ldap_attr );
    }
    ber_free( berptr, 0 );
}
ldap_msgfree( ldap_result_msg );

待优化问题

  1. 遍历效率低下
    当前通过ldap_next_entry遍历条目,再用ldap_next_attribute遍历属性,最后调用ldap_get_values_len获取值。而ldap_get_values_len会从头搜索目标属性,对于仅需所有值合集的场景,这种嵌套遍历存在冗余,希望找到更高效的遍历方式。

  2. 不必要的内存分配与释放
    push_onto_string_array( result, value )会对传入的char * const做深拷贝,但当前循环中:

  • 为每个属性分配释放berval** values
  • 为每个属性值额外执行malloc、拷贝并添加终止符,之后又被push_onto_string_array再次拷贝,存在冗余的内存操作。

优化方案

1. 优化遍历效率:直接针对目标属性取值

由于已经明确指定了要查询的三个属性,无需遍历所有返回属性,直接循环这三个属性名调用ldap_get_values_len,省去属性遍历的开销:

// 定义目标属性列表
const char* target_attrs[] = { "mail", "mailAlias", "mailAccount", NULL };

LDAPMessage* ldap_result_msg = NULL;
int result_code = ldap_search_ext_s( ldap_handle, ..., target_attrs, &ldap_result_msg );
// ... 错误处理 ...
struct string_array_t* result = create_string_array();

for(
    LDAPMessage* ldap_entry_msg = ldap_first_entry( ldap_handle, ldap_result_msg );
    ldap_entry_msg != NULL;
    ldap_entry_msg = ldap_next_entry( ldap_handle, ldap_entry_msg )
) {
    // 直接遍历目标属性,无需处理所有属性
    for( int attr_idx = 0; target_attrs[attr_idx] != NULL; attr_idx++ ) {
        struct berval** values = ldap_get_values_len( ldap_handle, ldap_entry_msg, target_attrs[attr_idx] );
        if( values == NULL ) continue; // 属性不存在时跳过
        
        // 处理属性值(后续内存优化逻辑放在此处)
        for( int i = 0; values[i] != NULL; ++i ) {
            // 内存优化代码
        }
        ldap_value_free_len( values );
    }
}
ldap_msgfree( ldap_result_msg );

这种方式避免了ldap_first_attribute/ldap_next_attribute的遍历,也减少了ldap_get_values_len的无效查找,因为我们只针对已知存在的目标属性调用。

2. 优化内存操作:减少冗余拷贝

根据是否能修改push_onto_string_array接口,提供两种优化方案:

方案A:不修改现有接口

使用strndup直接生成带终止符的字符串,替代手动malloc+strncpy的操作:

// 在属性值循环中
for( int i = 0; values[i] != NULL; ++i ) {
    // strndup自动分配内存并添加终止符
    char* value = strndup( values[i]->bv_val, values[i]->bv_len );
    if( value != NULL ) {
        push_onto_string_array( result, value );
        free( value ); // 因push_onto_string_array会深拷贝,释放临时内存
    }
}

方案B:修改接口支持长度参数

新增push_onto_string_array_len(struct string_array_t* arr, const char* data, size_t len)接口,内部直接根据长度拷贝数据,无需提前添加终止符:

// 在属性值循环中
for( int i = 0; values[i] != NULL; ++i ) {
    push_onto_string_array_len( result, values[i]->bv_val, values[i]->bv_len );
}

这种方式彻底省去中间的内存分配与拷贝,直接复用OpenLDAP返回的berval数据,大幅减少内存操作开销。


内容的提问来源于stack exchange,提问作者user2690527

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 20:14:52