一、curl_multi_setopt
原型:CURLMcode curl_multi_setopt(CURLM* multi_handle, CURLMoption option, param);
功能: 用于设置multi handle的选项。
可用版本库:7.15.4版本及以后。
- CURLMOPT_PIPELINING
启用HTTP管道和多路复用,值类型为:long
。
用于设置multi handle是否启用HTTP的管道还是HTTP/2多路复用。
启用后,libcurl将在对相同主机发起并行请求时使用这些协议特性。
管道:意味着对于后续请求可以使用之前已经存在的连接,后续的请求将在同一个连接上进行“管道传输”(等待前一个请求完成),而不是并行执行。
多路复用:意味着后续请求可以复用现有已经存在的连接,即在其他传输已经在使用该连接的情况下,可以多路复用发送新的请求。
在7.43.0版本之前,该选项可以设置为1和0,用来启用和禁用HTTP/1.1的管道。
从7.43.0版本开始,可以设置管道和多路复用。
CURLPIPE_NOTHING (0)
默认值,表示即不使用管道,也不使用多路复用。
CURLPIPE_HTTP1 (1)
如果设置为该值,libcurl将尝试把HTTP/1.1请求通过管道传输到已经建立并正在使用连接的主机。
该选项将被删除,7.62.0版本以后无效。
CURLPIPE_MULTIPLEX (2)
如果设置为该值,libcurl将尝试在现有连接上进行多路传输。需要HTTP/2。7.62.0版本以后,该值为默认值。
适用的协议:HTTP(S)。
可用库版本:7.16.0版本及以后。 - CURLMOPT_MAX_PIPELINE_LENGTH
管道中请求的最大数量,值类型为:long
。
用于设置HTTP/1.1管道连接中未完成的请求的最大数量。此选择只用于HTTP/1.1管道,不适用于HTTP/2多路复用。
当达到限制值时,libcurl将使用另一个连接到同一个主机的另一个连接。或者将请求排队,直到主机的一个管道准备好接受请求为止。
因此,当前可以处理的请求总数是:CURLMOPT_MAX_HOST_CONNECTIONS * CURLMOPT_MAX_PIPELINE_LENGTH
。
默认值为5。
适用的协议:HTTP(S)。
可用库版本:7.30.0版本及以后。 - CURLMOPT_MAX_TOTAL_CONNECTIONS
最大同时打开连接数,值类型为:long
。
用于设置multi handle可同时打开的最大连接总数。对于每个新会话,libcurl将打开一个新的连接,上限值由该值设置。
当达到上限值时,会话将会挂起,直到有可用的连接为止。如果启用了CURLMOPT_PIPELINING
,则libcurl将会尝试使用管道或多路复用。
默认值为0,表示没有限制。
适用的协议:所有。
可用库版本:7.30.0版本及以后。 - CURLMOPT_MAXCONNECTS
设置连接缓存的大小,值类型为:long
。
用于设置在multi handle使用结束后,libcurl可以在连接缓存中保留的同时打开的最大连接数。默认情况下,libcurl将会增大该值,使其4倍于已添加的easy handle数量。
通过设置该选项,可以防止缓存大小增加超出我们所设置的限制。当缓存满了时候,curl将关闭缓存中最老的一个连接,防止增加打开的连接数量。
适用的协议:所有。
可用库版本:7.16.3版本及以后。 - CURLMOPT_MAX_HOST_CONNECTIONS
设置到单个主机的最大连接数,值类型为:long
。
用于设置同时连接到某个主机(主机由主机名+端口确定)的最大连接数。
对于主机的每个新会话,libcurl将会打开一个新连接,可打开的连接数上限值受到该值的限制。当达到上限值时,会话将会挂起,直到有可用的连接为止。
如果启用了CURLMOPT_PIPELINING
,libcurl将会尝试使用管道。
默认值为0,表示没有限制。但是,为了向后兼容,当CURLMOPT_PIPELINING
被设置为1时,该值设置为0将不会被视为无限制。
相反地,它将只打开一个连接,并尝试在该连接上进行管道操作。
该值的限制也用于代理连接,代理将被视为该限制计数的主机。
适用的协议:HTTP(S)。
可用库版本:7.30.0版本及以后。
二、curl_multi_perform
原型: CURLMcode curl_multi_perform(CURLM* multi_handle, int* running_handles);
功能: 从每个easy handle读取/写入有效数据。
说明: 此函数用于处理所有添加到multi handle上的需要以非阻塞方式处理的传输。
当程序发现multi handle有可用数据时,或者超时已过,程序应该调用此函数用于读/写当前需要读或写的数据等。此函数在读/写完后立即返回。此函数不需要有实际的数据可读或者可写,只要有需要,它都可以被调用。参数running_handles
用于存储当前仍在传输数据的easy handle数量。如果running_handles
的数量与前一次调用相比发生了变化(或者小于添加到multi handle中easy handle的数量),那么可以知道有一个或者多个传输已经完成。然后可以调用curl_multi_info_read
获取每个完成传输的消息,返回的消息包含CURLcode
等信息。
如果添加的easy handle很快就失败,那么它可能永远不会被视作runnable_handle。当running_handles
在调用后被设置为0时,表示已经没有任何正在进行的传输。
三、curl_multi_wait
原型: CURLMcode curl_multi_wait(CURLM* multi_handle, struct curl_waitfd extra_fds[], unsigned int extra_nfds, int timeout_ms, int* numfds);
功能: 在multi handle中轮询所有的easy handle。
说明: 用于轮询指定的multi handle中所有easy handle所使用的文件描述符。它将阻塞,直到在至少一个easy handle上检测到活动,或者timeout_ms
超时已过。
另外,如果multi handle有一个内部的等待超时,它的时间如果比timeout_ms
短,那么将会使用更短的内部等待超时,这是为了确保合理的保持超时准确性。可以传入额外的参数extra_fds
,它是curl_waitfd
结构体数组,类似poll
的pollfd
结构体,用于在同个调用中等待。完成时,如果numfds
是非NULL,那么它将填充发生感兴趣事件的文件描述符总数。这个数字包括了libcurl内部描述符和extra_nfds
所提供的描述符。
如果没有提供额外的文件描述符,并且libcurl中也没有等待的文件描述符,那么调用此函数将立即返回。在使用multi接口时,鼓励使用该函数用以替代select
,这样可以使程序更容易规避最大文件描述符1024个的常见问题。
示例:
CURL* easy_handle;
CURLM* multi_handle;
curl_multi_add_handle(multi_handle, easy_handle);
CURLMcode mc;
int still_running;
int numfds;
do {
mc = curl_multi_perform(multi_handle, &still_running);
if (CURLM_OK == mc) {
/* wait for activity, timeout or "nothing" */
mc = curl_multi_wait(multi_handle, NULL, 0, 1000, &numfds);
}
if (CURLM_OK != mc) {
fprintf(stderr, "curl_multi failed, code %d.\n", mc);
break;
}
*/* 'numfds' being zero means either a timeout or no file descriptors to wait for. Try timeout on first occurrence, then assume no file descriptors and no file descriptors to wait for means wait for 100 milliseconds. */*
if (!numfds) {
repeats++; /* count number of repeated zero numfds */
if (repeats > 1) {
WAITMS(100); /* sleep 100 milliseconds */
}
} else {
repeats = 0;
}
} while(still_running);
curl_multi_remove_handle(multi_handle, easy_handle);
四、curl_multi_info_read
原型: CURLMsg* curl_multi_info_read( CURLM* multi_handle, int* msgs_in_queue);
功能: 读取multi stack信息。
说明: 询问multi handle是否有任务消息/信息可以从传输中获取。消息可能包含例如传输错误代码或者传输完成相关的信息。
重复调用该函数每次都会返回一个新的结构体,直到返回一个NULL表示此时不需要再获取的信号。msgs_in_queue
指向的int指针用于存放该函数此次调用结束后剩余的消息数量。
当调用该函数获取消息时,它将从内部队列中删除,因此再次调用次函数将不会再次返回相同的消息。相反地,它将在每次新调用时返回新消息,直到队列被清空。
示例:
struct CURLMsg* m;
int msgq = 0;
do {
m = curl_multi_info_read(multi_handle, &msgq);
if (m && (CURLMSG_DONE == m->msg)) {
CURL* e = m->easy_handle;
curl_multi_remove_handle(multi_handle, e);
curl_easy_cleanup(e);
}
} while (m);