curl 设置回调CURLOPT_WRITEFUNCTION接收时会出现接收不全的现象

        今天在在写一个向一个url申请相关数据时发现了一个很奇怪的现象,就是有时候解析相应的数据时有时候报错,还不是必现的。。。(头痛),,然后通过增加打印,终于锁定了是因为发送后调用CURLOPT_WRITEFUNCTION接收的数据有时候不全,打印如下

那么问题又来了,为什么有时候没有接收全,,,,

        于是我还是觉得自己代码写的不对,部分代码如下

static int getConfigData(TGAT1400ClientConfig *_pstTGAT1400ClientConfig,char *_sign,char *_nonce)
{

    int iRet = -1;
    CURL* curl;
    CURLcode res;
    char response[4096];
    memset(response,0,sizeof(response));
    char configurl[256];
    memset(configurl,0,sizeof(configurl));
    if(_sign == NULL ||_pstTGAT1400ClientConfig == NULL || _nonce == NULL )
    {
        Gat1400Log_Error("json_data   _pstTGAT1400ClientConfig  == NULL \n");
        iRet = -1;
        goto EXIT;

    }
    
    struct MemoryStruct chunk;
    chunk.memory = malloc(1024);  /* will be grown as needed by the realloc above */\
    if (chunk.memory == NULL)
    {
        Gat1400Log_Error("chunk.memory == NULL\n");
        iRet = -1;
        goto EXIT;
    } 
    chunk.size = 0;    /* no data at this point */ 

    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    if (!curl) 
    {
        Gat1400Log_Error("Failed to initialize CURL.\n");
        curl_global_cleanup();
        iRet = -1;
        goto EXIT;
    }

    snprintf(configurl, 255,"https://aaabbb:8800", _pstTGAT1400ClientConfig->m_pcUserName, _nonce, _sign);//地址就不给了哈哈哈哈
    Gat1400Log_Debug("configurl  is [%s]\n",configurl);
    response[0] = '\0';
    curl_easy_setopt(curl, CURLOPT_URL, configurl);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20L); 	 
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);	
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 5L);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
    if (strncmp(configurl, "https://", strlen("https://")) == 0)
    {  
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 
  	    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    }

    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        Gat1400Log_Error("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        curl_easy_cleanup(curl);
        curl_global_cleanup();
        iRet = -1;
        goto EXIT;
    }

    // 解析返回的JSON数据
    Gat1400Log_Error("chunk.memory is %s\n",chunk.memory);
    iRet = parseJson(chunk.memory, _pstTGAT1400ClientConfig);

    free(chunk.memory);
    curl_easy_cleanup(curl);
    curl_global_cleanup();

EXIT:
    return iRet;
}

在使用parseJson解析的时候有时候解析不对,所以应该问题就出在WriteMemoryCallback回调里

WriteMemoryCallback接口如下

size_t WriteMemoryCallback(void *pvSrc, size_t size, size_t nmemb, void *pvStream)
{
    if (NULL == pvSrc || NULL == pvStream)
    {
        Gat1400Log_Error("invalid pvSrc(%p) pvStream(%p)", pvSrc, pvStream);
        return 0;
    }

    char *p = (char *)pvStream;
    char *q = (char *)pvSrc;
    int len = strlen(p);
    (void)strncat(p, q, (1024 - len) - 1);
    Gat1400Log_Debug("recv is %s\n", p);
    //Gat1400Log_Debug("nmemb * size=%d", nmemb * size);
    
    return nmemb * size;
}

emmm当时这个接口直接调用部门公共库的,感觉也不会太大的问题!仔细分析一下

在使用strncat函数拼接数据时,使用了一个大小为1024的缓冲区 p,但是在计算当前数据长度 len 时,使用了 strlen 函数。strlen 函数是计算字符串长度的,它会遍历整个字符串直到遇到 \0 结束符。然而,在开始拼接数据之前,p 中可能不是以 \0 结束的字符串,这样使用 strlen 得到的 len 值可能是不准确的,导致拼接的位置错误,从而截断部分数据。使用一个变量来跟踪当前数据长度,而不仅仅依赖于字符串的长度。而且,每次回调函数被调用时,d 新接收的数据追加到缓冲区 p 的末尾。然而,如果 p 中已经包含了之前接收的数据,那么新的数据可能会覆盖之前的数据,导致数据丢失。应该使用一个变量来跟踪当前已经拼接的位置,并确保新接收的数据从正确的位置开始拼接。

简单来说,上面的代码的问题1,1024字节限制,2 ,使用strlen 测量不准(遇到\0的就完蛋了)

可是问题怎么解决呢,经过多方面尝试(百度哈哈哈哈),使用curl官网推荐的还是比较好的。https://curl.se/libcurl/c/CURLOPT_WRITEFUNCTION.html

经过修改完后的代码如下:

static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
  size_t realsize = size * nmemb;
  struct MemoryStruct *mem = (struct MemoryStruct *)userp;
 
 // 注意这里根据每次被调用获得的数据重新动态分配缓存区的大小
  char *ptr = realloc(mem->memory, mem->size + realsize + 1); 
  if(ptr == NULL) 
  {
    /* out of memory! */ 
    Gat1400Log_Error("not enough memory (realloc returned NULL)\n");
    return 0;
  }
 
  mem->memory = ptr;
  memcpy(&(mem->memory[mem->size]), contents, realsize);
  mem->size += realsize;
  mem->memory[mem->size] = 0;
 
  return realsize;
}

经过一天的老化,发现确实解决了接收一半数据的现象了

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值