最近需要用 curl 来发送 http 请求, 遇到了不少问题, 查了不少资料, 都是零零散散的, 现在总结下.
1, 移植编译
1 ./configure --prefix=$(PWD)/build --host=ARM-XXX-Linux;make ;make install
这步基本都没有问题, 生成的动态链接库 libcurl.a, 可以直接给应用程序去使用.
2,API 使用
1)全局初始化 curl_global_init(CURL_GLOBAL_ALL);
2)通过 curl_easy_init 得到一个 CURL 指针 m_pCurl
3)通过 curl_formadd 封装参数
通过 curl_easy_setopt 设置各种选项
通过 curl_easy_perform 执行 curl 的各种操作
4)curl_easy_getinfo 获得 http 返回的状态码
5)curl_easy_cleanup 释放 CURL 指针
6)curl_global_cleanup 释放全局对象
3,http 的响应内容获取
先通过 curl_easy_setopt 设置 CURLOPT_WRITEFUNCTION,CURLOPT_WRITEDATA 选项
- size_t ReviceData(char *buffer, size_t size, size_t nmemb, std::stringstream & stream)
- {
- size_t total = size * nmemb;
- std::string str = "";
- if (total)
- {
- str.append(buffer, total);
- }
- stream << str.c_str();
- return total;
- }
- std::stringstream out;
- curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, ReviceData);
- curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, &out);
当有响应回来的时候, 会触发 ReviceData 函数, 在这个回调函数, 会把响应的内容, 赋值给 out 变量, 这样响应就取得了.
4, 遇到的一些问题
- curl_easy_setopt(m_pCurl, CURLOPT_CONNECTTIMEOUT, 4L);
- curl_easy_setopt(m_pCurl, CURLOPT_TIMEOUT, 25L);
设置了超时时间后 (一个是等待连接的时间, 一个是等待接收响应的时间) 一旦域名解析失败, 程序会莫名的挂掉, 而且每次挂掉的地方都不一样. 当时也是通过一点一点注释代码, 才定位到这两行代码.
coredump 的原因是因为 curl 的 DNS 解析超时控制是使用 SIGALARM 实现的.
这样导致发现 SIGALARM 会出现多线程修改同一个全局变量, 由此产生了 COREDUMP.
问题发生的前提是设置了 CURLOPT_TIMEOUT 或 CURLOPT_CONNECTTIMEOUT, 并且值不为 0.
解决办法:
1) 设置 CURLOPT_NOSIGNAL 的值为 1
curl_easy_setopt(m_pCurl, CURLOPT_NOSIGNAL, 1);
设置之后, 发现的确不会 coredump 了, 但是设置的超时时间没有用了, 需要等很久, 才能出结果.
2) 使用 c-ares(configure 时指定参数 --enable-ares)
使用这个方法比较好, 不会 coredump, 而且超时时间设置后生效.
下面介绍下这个方法:
a, 下载 cares 的源码, 进行编译移植
https://c-ares.haxx.se/
编译方法和 curl 的编译方法类似, 都是通过 configure, 最终生成 libcares.a
b, 修改 curl 源码里的 configure 文件
找到下面的代码, 添加 embedded_ares="yes", 箭头所指的地方, 不然 check
的时候, 会报 c-ares library defective or too old
c, 重新编译 curl
./configure --enable-ares=$(PWD)/depends --prefix=$(PWD)/build --host=ARM-XXX-Linux;make ;make install
这里指定了 enable-ares 使用的 libares 所在的目录. depends 目录下需要再建立一个子目录 lib, 在子目录下放入 libcares.a 即可.
还要把 libcares 的头文件都拷贝到 curl 主目录里的 lib 目录里, 这样编译就不会出错了.
来源: https://www.cnblogs.com/ahcc08/p/11656395.html