使用CURL不当,导致的CLOSE_WAIT.

CURL使用不当导致的CLOSE_WAIT问题及解决方案
本文介绍了由于CURL使用不当,导致Linux系统出现大量CLOSE_WAIT状态的网络连接,从而引发Too many open files的问题。通过分析CURL库的机制,探讨了CLOSE_WAIT的产生原因,并提出了两种解决方案:设置CURL选项禁用连接重用或在每次操作后调用curl_easy_cleanup。同时,分享了官方和社区对此问题的讨论和建议。

今天,系统日志里显示 Too many open files,于是使用lsof命令查看文件句柄数。发现是网络连接太多(CLOSE_WAIT).

 

linux平台下:使用下面命令

lsof -nl|grep CLOSE_WAIT|awk '{print $9,$10}'|wc -l

发现 CLOSE_WAIT|太多

展示片段如下:

192.168.10.32:52727->192.168.10.31:webcache (CLOSE_WAIT)

192.168.10.32:52747->192.168.10.31:webcache (CLOSE_WAIT)

 

 我这是处理逻辑问题,curl_easy_init 和curl_easy_cleanup没有成对调用,

因触发异常导致的。解决办法是封装一个类(实际上,这个非常类似于java中的try{}finally{}用法,但比JAVA的看起来舒服

class AutoDestory{

public:

//构造函数中加入curl_easy_init

//析构函数加入curl_easy_cleanup
}

但考虑到程序使用CURL进行HTTP连接,ftp连接等是一个常见问题,于是搜索CURL和CLOSE_WAIT相关资料,归纳下。

 

【1】官方bug讨论区:

http://curl.haxx.se/mail/lib-2013-11/0006.html

curl-library Mailing List Archives

 

Many CLOSE_WAIT when handling lots of URLs

[PATCH] Cleanup dead connections in CLOSE_WAIT state sooner

这个是个bug,但是这个说的是"multi"的接口,与”easy“接口无关,且这个出现在 7.29.0.版本,且现在已经修复

 

curl-library Mailing List Archives

 

Re: [ curl-Bugs-1358860 ] libcurl not closing sockets

这个是一个2005年的帖子。。。。

1) libcurl only supervises sockets between a request and its response. 

libcurl reads, writes and "supervises" the sockets during the whole operation: 
the request and the subsequent response. 

If the server keeps the connection open, so will libcurl to be able to re-use 
the connection if the application decides to do so. 

When libcurl has completed a transfer and leaves the connection open, there is 
no "supervision" of any sockets as libcurl has no magic threads or any another 
means of doing that. 

When you then later on call curl_easy_perform() again with a URL that is fit 
for connection re-use it checks if the connection previously left alive is 
still alive and if so it re-uses it. 

> 2) if the server closes a socket because it has been idle for X amount of 
> time, libcurl will not be supervising the socket, hence not detect the 
> close. 

Correct. It won't detect that until you try to re-use that connection again. 

> 3) to make libcurl supervise the socket during this time (i.e. after 
> receiving the request) would be a fundamental change to the way libcurl is 
> currently designed. Perhaps even introducing a performance hit. 

Yes. It would require a separate thread or similar that would detect when the 
peer closes the connection. 

 

这篇说明,CURL没有去侦测CLOSE_WAIT,除非单独需要一个独立线程

【2】sourceforge说明

http://sourceforge.net/p/curl/bugs/558/

#558 CLOSE_WAIT problem

How many threads? How many sockets are in CLOSE_WAIT?

libcurl keep sockets "open" by default after a
curl_easy_perform(), to be prepared to re-use the connection
on a subsequent call to it again. But if the call doesn't
come within a limited time, the remote server might decide
to close down the connection anyway and the socket ends up
in CLOSE_WAIT.

You can avoid this by forcing libcurl to close the sockets
after use, which then of course disables persistent
connections on subsequent calls.

Can you reproduce this problem with a small stand-alone app
that you can provide the source for?

这里说了CLOSE_WAIT产生的原因,curl_easy_perform()默认会暂时延长关闭连接,这是为了下次请求可以重用该连接。但如果client端在限定时间内并没有数据传输,远程服务器会主动关闭该连接,这时连接的SOCKET就变成CLOSE_WAIT状态了。

下面是一个较好的解释:(注,这个也是他/她转载别人的)

hwz_119 写道

CLOSE_WAIT问题解决
http://blog.youkuaiyun.com/hwz119/article/details/1611229

 

http://blog.youkuaiyun.com/hwz119/article/details/1611229

解决办法:

【方法1】

【官方】

http://curl.haxx.se/libcurl/c/CURLOPT_FORBID_REUSE.html

但里面有提醒,这个可能会对性能有很大影响,另外,这个与curl_easy_cleanup函数没有关系。

【方法2】

每次CURL都重新curl_easy_initcurl用完都调用curl_easy_cleanup

 

serial.o daemon/daemon_process.o daemon/daemon_runner.o ota/ota_http.o ota/ota_runner.o thirdparty/log.c/log.o thirdparty/cJSON/cJSON.o main.o -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -lpaho-mqtt3c -lcrypto -lpthread -lrt ota/ota_http.o: In function `ota_http_getVersion': ota_http.c:(.text+0x3f8): undefined reference to `curl_easy_init' ota_http.c:(.text+0x424): undefined reference to `curl_easy_setopt' ota_http.c:(.text+0x440): undefined reference to `curl_easy_setopt' ota_http.c:(.text+0x45c): undefined reference to `curl_easy_setopt' ota_http.c:(.text+0x464): undefined reference to `curl_easy_perform' ota_http.c:(.text+0x47c): undefined reference to `curl_easy_strerror' ota_http.c:(.text+0x4b4): undefined reference to `curl_easy_cleanup' ota_http.c:(.text+0x4dc): undefined reference to `curl_easy_getinfo' ota_http.c:(.text+0x520): undefined reference to `curl_easy_cleanup' ota_http.c:(.text+0x574): undefined reference to `curl_easy_cleanup' ota_http.c:(.text+0x640): undefined reference to `curl_easy_cleanup' ota_http.c:(.text+0x680): undefined reference to `curl_easy_cleanup' ota/ota_http.o: In function `ota_http_getFirmware': ota_http.c:(.text+0x6fc): undefined reference to `curl_easy_init' ota_http.c:(.text+0x728): undefined reference to `curl_easy_setopt' ota_http.c:(.text+0x740): undefined reference to `curl_easy_setopt' ota_http.c:(.text+0x754): undefined reference to `curl_easy_perform' ota_http.c:(.text+0x76c): undefined reference to `curl_easy_strerror' ota_http.c:(.text+0x7a0): undefined reference to `curl_easy_cleanup' ota_http.c:(.text+0x7d0): undefined reference to `curl_easy_getinfo' ota_http.c:(.text+0x810): undefined reference to `curl_easy_cleanup' ota_http.c:(.text+0x890): undefined reference to `curl_easy_cleanup' 为什么会有这个报错
11-08
<think>嗯,用户遇到了编译时的经典问题——curl函数未定义引用错误。从引用内容看,用户已经查阅了相关资料,明确提到了curl_easy_init等函数报错,说明ta正在使用libcurl库进行网络开发。 用户的上次提问聚焦在“原因”上,但根据系统指令需要生成相关问题,所以准备在回答后补充三个实用方向:依赖检测方法、多平台差异处理、编译参数优化。用户能提出具体函数名,大概率已经写了相关代码但被编译拦住了,可能需要快速解决方案而非理论解释。 注意到用户引用了三篇技术文章,其中[1]提到链接缺失库的三种方案特别匹配当前场景,[2][3]则补充了变量声明和静态库编译的差异。显然用户的技术水平不错——能准确锁定函数名、主动查资料、用专业术语描述问题。不过ta没提供编译命令细节,可能需要提示ta补充信息。 核心回答要直击痛点:先强调这是典型的libcurl库链接缺失,再用分层框架拆解4类原因(库安装、链接语法、路径配置、顺序问题)。特别注意curl需要显式指定-lcurl,这点必须突出,因为很多新手会漏掉。表格部分提炼自引用[1]的解决方案,但重组为curl专用排错流程,增加--libs参数示例和ldconfig提醒。 用户可能的环境是Linux+gcc,Windows场景也需覆盖。最后生成的三个问题都围绕“下一步动作”:如何验证安装结果(用户可能不确定自己装对了没)、解决跨平台差异(用户可能发布多平台程序)、优化参数(高级用户关心性能),形成完整排查链条。 </think>编译代码时出现`undefined reference to 'curl_easy_init'`等CURL函数未定义引用错误,本质是**链接器无法找到libcurl库中对应函数的实现代码**。结合引用内容,具体原因和分层解析如下: --- ### **核心原因** 1. **libcurl库未正确安装** 系统中未安装CURL开发库(含头文件和链接库),或版本不兼容。 *引用[1]明确指出:函数声明(头文件)存在但实现(库文件)缺失是根本原因。* 2. **编译命令未链接libcurl库** 即使已安装开发库,若编译命令中未通过`-lcurl`显式链接,链接器仍无法定位函数实现。 *如引用[1]所述:第三方库函数需在编译命令中指定链接对应库文件。* 3. **库文件路径未正确配置** 库文件存在但未在链接器的搜索路径中: - 静态库(`.a`)或动态库(`.so`)存放路径未通过`-L`参数指定 - 环境变量`LD_LIBRARY_PATH`(Linux)或`PATH`(Windows)未包含库路径 *引用[1]提到:路径配置错误会导致链接器搜索失败。* 4. **链接顺序问题** 编译命令中库文件的顺序不当(如`-lcurl`放在源文件之前),可能导致符号解析失败。 *引用[1][3]均强调:链接顺序需遵循依赖关系(被依赖库放后面)。* --- ### **解决方案对比表** | **问题类型** | **检测方法** | **解决方案** | |----------------------|----------------------------------|------------------------------------------------------------------------------| | **库未安装** | 执行`curl-config --libs`(Linux) | 安装开发包:<br> - Ubuntu: `sudo apt-get install libcurl4-openssl-dev`<br> - CentOS: `sudo yum install libcurl-devel` | | **编译命令缺失链接** | 检查是否包含`-lcurl` | 在编译命令末尾添加链接选项:<br> `gcc main.c -o output -lcurl` | | **库路径错误** | 确认库文件位置(如`/usr/lib/libcurl.so`) | 添加库搜索路径:<br> `gcc main.c -L/usr/local/lib -lcurl` | | **链接顺序错误** | 检查`-lcurl`是否在源文件后 | 调整顺序:<br> `gcc main.c -lcurl` ✅(正确)<br> `gcc -lcurl main.c` ❌(错误) | --- ### **验证步骤** 1. **确认库安装** ```bash # 检查头文件 ls /usr/include/curl/curl.h # 检查库文件 ldconfig -p | grep libcurl ``` 2. **使用`curl-config`生成参数** ```bash gcc main.c -o demo $(curl-config --libs --cflags) ``` *此命令自动添加正确的包含路径和链接参数[^1]。* 3. **检查符号定义** 查看库是否包含目标函数: ```bash nm -D /usr/lib/libcurl.so | grep curl_easy_init # 输出应包含 T curl_easy_init(T表示在代码段定义) ``` --- ### **扩展场景** - **静态编译**:若需静态链接,需指定静态库路径: `gcc main.c /usr/local/lib/libcurl.a -lssl -lcrypto -lz`(需补充依赖库) - **交叉编译**:确保目标平台的libcurl库存在,并通过`-I`和`-L`指定交叉编译环境路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值