使用InternetOpenUrl掛起的一個解決方案

來源:互聯網
上載者:User

 

 

在某個同事留下的網路作業碼中,如果使用者試圖從網路開啟一個實際並不存在的URL, 走到InternetOpenUrl這步,應用程式就一命嗚呼了。這個API並沒有按照文檔上說的那樣返回一個NULL給檔案HANDLE,而是完全停止回應。他嘗試使用InternetSetOption來設定逾時的時限,代碼裡這樣寫

DWORD n = 10000;
InternetSetOption(p->Internet, INTERNET_OPTION_CONNECT_TIMEOUT, &n, sizeof(n));

但沒有實際效果。從後文可以猜測,InternetOpenUrl再去調用了網路的IO處理,在IO處理中被卡死,罪過似乎並不在InternetOpenUrl和wininet.dll這層上.

於是他在前面某次工作記錄裡說已經解決了這個問題,然後又被測試組罵回來說沒效果. 我搜到了開原始碼裡一個很好的演算法, 自己測試了下,的確有效。讓我們來看下它的演算法,確實很精妙. 整個演算法的核心是用非同步方式來處理wininet.dll提供的那些函數

 

具體實現代碼如下:

(1) 首先, 在InternetOpen時修改了參數
   它用的是  InternetOpen(T("MyApp"), p->AccessType, NULL,NULL, INTERNET_FLAG_ASYNC);  
   而會卡死的情況下用的是 InternetOpen(T("AmoiPlayer"),INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
   前面幾個參數不是影響該效能的關鍵,關鍵點在最後一個參數上: INTERNET_FLAG_ASYNC. 在文檔裡對這個參數的解釋是 Makes only asynchronous requests on handles descended from the handle returned from this function.  寫得有些晦澀. 實際效果就是如果在InternetOpen中設定為INTERNET_FLAG_ASYNC, 那麼在InternetOpenUrl時就會立刻返回,  如果為NULL就必須有具體的傳回值才肯RETRUN.

(2) 註冊一個CALLBACK函數  InternetSetStatusCallback(p->Internet, InternetCallback)
      因為我們OpenURL操作會立刻返回了,那麼什麼時候能得到有效或無效的HANDLE呢? 這就需要一個CALLBACK來做這件事情.  這裡當然有必要看下這個CALLBACK函數裡做了什麼

static void CALLBACK InternetCallback(HINTERNET hInternet,
                               DWORD dwContext,
                               DWORD dwInternetStatus,
                               LPVOID lpvStatusInformation,
                               DWORD dwStatusInformationLength)
{
    if (dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE)
    {
        INTERNET_ASYNC_RESULT *Result = (INTERNET_ASYNC_RESULT*)lpvStatusInformation;
        http *p = (http*)dwContext;
        p->CompleteResult = Result->dwResult;
        SetEvent(p->Complete);
    }
}
當等到INTERNET_STATUS_REQUEST_COMPLETE通知的時候, 把RESULT擷取下來放在p->CompleteResult裡面,然後SetEvent. 也就是說系統CALLBACK線程和其他什麼線程進行通訊了

(3) 在InternetOpenUrl的時候代碼如下:

Result = (DWORD)InternetOpenUrl(p->Internet, URL, s, (DWORD)-1, INTERNET_FLAG_NO_CACHE_WRITE|Secure, (DWORD)p);

p->Handle = (HANDLE)Pending(p, Result , 30);

if (Result || GetLastError() != ERROR_IO_PENDING)
{
  p->Handle = Result;
}
else
{
  p->Pending = 1;
  if ( WaitForSingleObject(p->Complete,300000) == WAIT_OBJECT_0 )
  {
    p->Pending =0;
    p->Handle  = p->CompleteResult;
  }
  else
  {
    p->Handle = NULL;
  }
}

代碼中把流程圖中的左邊線程, 從調用API觸發CALLBACK開始, 到底端取得HANDEL這塊演算法封裝為一個函數, 可以被其他對wininet.dll介面函數的操作共用, 如InternetReadFile等.

 

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/li_guotao/archive/2009/02/20/3915102.aspx

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.