1. 程式人生 > >curl原始碼分析(二)協議註冊與使用過程

curl原始碼分析(二)協議註冊與使用過程

在curl.c函式裡面可以找到下面的這個結構體陣列.這個陣列就是註冊所有協議的地方.

每種協議通過實現Curl_handler這個結構體裡面的部分函式,再把它放入到這個結構體數組裡面,這種協議就可以使用了.

static const struct Curl_handler * const protocols[] = {
#ifndef CURL_DISABLE_HTTP
    &Curl_handler_http,
#endif

#ifndef CURL_DISABLE_FTP
    &Curl_handler_ftp,
#endif

#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
    &Curl_handler_ftps,
#endif

#ifndef CURL_DISABLE_TELNET
    &Curl_handler_telnet,
#endif

#ifndef CURL_DISABLE_FILE
    &Curl_handler_file,
#endif

#ifndef CURL_DISABLE_TFTP
    &Curl_handler_tftp,
#endif

    (struct Curl_handler *) NULL
};
協議呼叫過程:
curl_multi_perform
->multi_runsingle
->Curl_connect
->setup_conn初始化連線
->parseurlandfillconn找到當前傳入地址所使用的協議
->findprotocol把當前使用的協議與支援的協議數組裡面的協議進行比較看是否相同,這樣我們就找到了連線所用的協議

例如在webkit中curl的使用,下面是我在閱讀webkit程式碼時的一點記錄:

writeCallback/headerCallback是怎麼完成的:
Webkit使用lite註冊了一個定時器,在使用main_loop的時候會執行這個定時器的回撥函式.最後會調到curl_multi_perform,看下這次請求是否有資料需要讀寫。如果有的話由curl來控制不斷傳回資料直到結束。也就是說整個過程都是同步的,在這裡會阻塞。當然阻塞是在curl裡面的。
在ResourceHandleManager::downloadTimerCallback()中呼叫的curl_multi_perform:
while (curl_multi_perform(m_curlMultiHandle, &runningHandles) == CURLM_CALL_MULTI_PERFORM) { }
而這句話是錯誤的,我的意思是根本沒有必要這麼寫。寫成curl_multi_perform(m_curlMultiHandle, &runningHandles);就夠了,沒有必要要while因為這裡的返回值絕對不會是CURLM_CALL_MULTI_PERFORM, 不相信我就看下這個函式的原始碼。

CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
{
    struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
    struct Curl_one_easy *easy;
    CURLMcode returncode=CURLM_OK;
    struct Curl_tree *t;

    if(!GOOD_MULTI_HANDLE(multi))
        return CURLM_BAD_HANDLE;

    easy=multi->easy.next;
    while(easy != &multi->easy) {
        CURLMcode result;
        struct WildcardData *wc = &easy->easy_handle->wildcard;

        if(easy->easy_handle->set.wildcardmatch) {
            if(!wc->filelist) {
                CURLcode ret = Curl_wildcard_init(wc); /* init wildcard structures */
                if(ret)
                    return CURLM_OUT_OF_MEMORY;
            }
        }

        do
            result = multi_runsingle(multi, easy);
        while (CURLM_CALL_MULTI_PERFORM == result);//它會在這裡形成迴圈判斷,所以不可能出現這個值,我的理解對嗎?

        if(easy->easy_handle->set.wildcardmatch) {
            if(wc->state == CURLWC_DONE || result)
                Curl_wildcard_dtor(wc);
        }

        if(result)
            returncode = result;

        easy = easy->next; /* operate on next handle */
    }
    do {
        struct timeval now = Curl_tvnow();

        multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
        if(t) {
            struct SessionHandle *d = t->payload;
            struct timeval* tv = &d->state.expiretime;

            tv->tv_sec = 0;
            tv->tv_usec = 0;
        }

    } while(t);

    *running_handles = multi->num_alive;

    if( CURLM_OK >= returncode )
        update_timer(multi);

    return returncode;
}