Libcurl предлагает вызовы CURLOPT_HEADERFUNCTION и CURLOPT_WRITEFUNCTION. Это здорово, пока вы не используете конвейерную обработку и мультистак. Как вы соотносите заголовок с телом? Допустим, тон запросов и множество простых ручек заставляют libcurl устанавливать несколько подключений к серверу. Предположим, что получен первый заголовок ответа, и есть задержка в получении тела. Между тем второй заголовок появляется вместе с телом. Does libcurl гарантирует, что второй заголовок не будет доставлен в приложение до завершения первого ответа? Это важно, потому что заголовок должен быть связан с телом. Я в том же затруднительном положении, даже когда я не использую HEADERFUNCTION. Даже если я использую только WRITEFUNCTION, он может получать ответы не по порядку в смешанном режиме. Поэтому возникает вопрос: ли libcurl гарантирует, что ответы будут переданы в целом? Если это одно соединение, мы можем быть уверены, что заказ ответа будет следовать порядку запроса. Но Я вижу libcurl, делающий несколько соединений, когда я использую pipeling и multistack. Предположим, что 5 соединений сделаны на том же сервере, потому что мы говорим о конвейеризации здесь. Заголовок ответа для Conn1 прибывает. Прежде чем мы получим тело из Conn1, мы получим ResponseHeader из Conn2. Does LibCurl гарантирует, что Conn2ResponseHeader не будет доставлен в приложение до BodyFromConn1? В противном случае следующий код сломается.Libcurl и HTTP Pipelining
class CEasyHandle
{
CURL* m_pCurl;
bool m_bInUse;
};
class CMultiStack
{
public:
CURLM* m_pCurlMulti;
deque<CEasyHandle*>& m_listEasyHandles;
static CEasyHandle* gpCurrentlyReceivingEasyHandle;
CEasyHandle* GetAvailableEasyHandle()
{
// Iterate through m_listEasyHandles and find one that is currently not added to multistack (m_bInUse)
// if none free, return NULL
}
bool MakeRequest(const char* pUrl)
{
CEasyHandle* pEasyHandle = GetAvailableEasyHandle();
if(!pEasyHandle) pEasyHandle = CreateNewEasyHandleAndAddToList();
curl_easy_setopt(pEasyHandle->m_pCurl, CURLOPT_HEADERFUNCTION, header_callback);
curl_easy_setopt(pEasyHandle->m_pCurl, CURLOPT_HEADERDATA, pEasyHandle); // header gets the EasyHandle
curl_easy_setopt(pEasyHandle->m_pCurl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(pEasyHandle->m_pCurl, CURLOPT_WRITEDATA, this); // body gets MultiStack
// set options, add to multistack, pEasyHandle->m_bInUse = true;
}
static size_t header_callback(char *buffer, size_t size, size_t nmemb, void *userdata)
{
gpCurrentlyReceivingEasyHandle = (CEasyHandle*)userdata;
// if no data expected, of course set gpCurrentlyReceivingEasyHandle->m_bInUse = false;
}
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
CMultiStack* pThisObj = (CMultiStack*)userdata;
pThisObj->PerformSomeWork();
// once complete, gpCurrentlyReceivingEasyHandle->m_bInUse = false;
}
};