美文网首页
解决一个libcurl使用POST以后卡死的问题

解决一个libcurl使用POST以后卡死的问题

作者: 叶迎宪 | 来源:发表于2018-11-24 12:14 被阅读0次

有一段调用libcurl去访问POST接口的代码

    curl_easy_setopt(curl_handle, CURLOPT_URL, url);
    curl_easy_setopt(curl_handle, CURLOPT_POST, 1L);
    curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);

    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);

    /* complete within 20 seconds */
    curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 20L);

    res = curl_easy_perform(curl_handle);

在win32窗口程序下使用是正常的。但是把同样的代码挪到控制台程序就不正常了。打开libcurl的日志,发现

  • STATE: DO => DO_DONE handle 0xe73570; line 1695 (connection #0)
  • STATE: DO_DONE => WAITPERFORM handle 0xe73570; line 1822 (connection #0)
  • STATE: WAITPERFORM => PERFORM handle 0xe73570; line 1837 (connection #0)
  • HTTP 1.1 or later with persistent connection, pipelining supported
    < HTTP/1.1 100 Continue

在这段日志之后程序就卡死不动了。在调试状态下把程序break掉,发现卡在libcurl的代码 lib/transfer.c Curl_fillreadbuffer()

  nread = (int)data->state.fread_func(data->req.upload_fromhere, 1,
                                      buffersize, data->state.in);

一开始没细看,以为这是在从网络层读取数据,数据读不出来以为是服务器的问题,在这里饶了很大的弯路也没定位出来。后来又认真看了下代码,这个data->state.fread_func是指向c库里面的一段代码,说明就是系统的api了。认真阅读了libcurl的源码,fread_func的赋值发送在

/* Curl_init_CONNECT() gets called each time the handle switches to CONNECT
   which means this gets called once for each subsequent redirect etc */
void Curl_init_CONNECT(struct Curl_easy *data)
{
  data->state.fread_func = data->set.fread_func_set;
  data->state.in = data->set.in_set;
}

而这些fread_func_set、in_set的值,在另外一个文件 lib/url.c Curl_init_userdefined()中被设置为默认值

  set->in_set = stdin;  /* default input from stdin */
  set->err  = stderr;  /* default stderr to stderr */

  /* use fwrite as default function to store output */
  set->fwrite_func = (curl_write_callback)fwrite;

  /* use fread as default function to read input */
  set->fread_func_set = (curl_read_callback)fread;

换而言之,卡住的这段代码,实际上就是通过fread从stdin读取输入。对于win32窗体程序,从stdin读取数据会立即返回0,因此不会卡住。而对于控制台程序,stdin就要等待键盘输入了,而且libcurl里面读取的缓冲区又特别长,有16384字节,因此会卡住一直等键盘输入填满缓冲区。

归根结底,其实是libcurl调用POST访问接口用得不正确。因为没有指明POST什么数据,导致libcurl会从stdin读取输入。需要改成

    curl_easy_setopt(curl_handle, CURLOPT_URL, url);
    curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, "");
    curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);

    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);

    /* complete within 20 seconds */
    curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 20L);

    res = curl_easy_perform(curl_handle);

相关文章

网友评论

      本文标题:解决一个libcurl使用POST以后卡死的问题

      本文链接:https://www.haomeiwen.com/subject/tageqqtx.html