Windows Mobile下WinInet的非同步使用方法

來源:互聯網
上載者:User

codeproject上有一篇老美寫的關於HTTP非同步文章:http://www.codeproject.com/KB/IP/asyncwininet.aspx。

我做HTTP非同步時候,也是參考了這篇文章,受益匪淺。今天特地翻譯出來,與大家共饗。

WinInet HTTP的非同步方式使用

緒論

如果你曾經深入MSDN研究過WinInet API,你會注意到可使用非同步方式且該方式是被推崇的。

當你決定使用該方式時,你卻找不到如何使用非同步說明。網上也沒有任何例子。研究了很長時間,也做了很多實驗,我最終決定著手來填補一份(非官方)空缺的文檔。

為什麼非同步方式是最好的?因為它能夠正確的處理逾時。而在IE5.5下WinInet缺少此功能。

如果你試圖使用TerminateThread或CloseHandle函數來處理逾時(這些函數在MSDN文檔中有介紹),你將落入各種各樣的陷阱中。

以下條件中非同步測試成功:單一處理器和多處理器的WinNT4系統下的IE4.01SP3, IE5.0, IE5.01, IE5.5SP1,壓力環境(12小時不間斷地在多處理器NT伺服器下運行15個並發執行個體)。

原理
使用WinInet函數的非同步方式,你必須按照正確的順序:
1.使用INTERNET_FLAG_ASYNC開啟任務。
2.使用InternetSetStatusCallback設定回調。
3.使用InternetOpenUrl開啟串連。
4.如果InternetOpenUrl返回NULL且GetLastError的值是ERROR_IO_PENDING:
  1)等待回呼函數返回INTERNET_STATUS_HANDLE_CREATED通知,儲存串連控制代碼;
  2)等待回呼函數返回INTERNET_STATUS_REQUEST_COMPLETE通知。
5.解析header裡的vontent-length欄位,建立一個INTERNET_BUFFERS結構:
  1)dwStructSize = sizeof(INTERNET_BUFFERS);
  2)lpvBuffer = 你申請的緩衝;
  3)dwBufferLength = 緩衝長度。
6.使用InternetReadFileEx函數,參數為IRF_ASYNC,非同步讀取剩餘的資料。不要使用InternetReadFile,因為它是同步的。
7.如果InternetReadFileEx返回FALSE且GetLastError的值為ERROR_IO_PENDING:等待回到函數返回INTERNET_STATUS_REQUEST_COMPLETE 通知。
  警告:INTERNET_BUFFERS結果的成員是會被修改的(dwBufferLength和緩衝區)。
8.如果dwBufferLength不為0,移動lpvBuffer的指標dwBufferLength個長度,重複第6步。
9.使用InternetCloseHandle關閉串連,等待INTERNET_STATUS_HANDLE_CLOSING和特定的INTERNET_STATUS_REQUEST_COMPLETE通知。

之後,你可以開始一個新的串連過程或者關閉任務控制代碼。但是在關閉之前,你應該卸載回呼函數。

細節
在原理中,讓我們看看關鍵點的一些代碼:

1&2:使用INTERNET_FLAG_ASYNC開啟任務,設定回調
m_Session = InternetOpen(AGENT_NAME, INTERNET_OPEN_TYPE_PRECONFIG,
                          NULL, NULL, INTERNET_FLAG_ASYNC);
InternetSetStatusCallback( m_Session,
      (INTERNET_STATUS_CALLBACK)InternetCallbackFunc );

3&4:使用InternetOpenUrl開啟串連,等待INTERNET_STATUS_REQUEST_COMPLETE通知
使用lParam發送一個任務表示到你的回調。我總是用this指標來傳遞我的class。這裡假設你知道如何處理回調。
InternetOpenUrl( m_Session, uurl, NULL, 0,
      INTERNET_FLAG_RELOAD | INTERNET_FLAG_PRAGMA_NOCACHE |
      INTERNET_FLAG_NO_CACHE_WRITE, (LPARAM)this );

回調會收到一堆的訊息。這是收到的dwInternetStatus值的順序:
[openUrl] InternetStatus: 60 INTERNET_STATUS_HANDLE_CREATED
**此時你應該儲存HINTERNET控制代碼,如下代碼:
INTERNET_ASYNC_RESULT* res = (INTERNET_ASYNC_RESULT*)lpvStatusInformation;
m_hHttpFile = (HINTERNET)(res->dwResult);

[openUrl] InternetStatus: 10
[openUrl] InternetStatus: 11
[openUrl] InternetStatus: 20
[openUrl] InternetStatus: 21
[openUrl] InternetStatus: 30
[openUrl] InternetStatus: 31
[openUrl] InternetStatus: 40
[openUrl] InternetStatus: 41
[openUrl] InternetStatus: 100 INTERNET_STATUS_REQUEST_COMPLETE

5:解析content-length,建立INTERNET_BUFFERS結構
一旦你得到了控制代碼,調用HttpQueryInfo(使用HTTP_QUERY_CONTENT_LENGTH標記)得到接收資料的大小。如果HTTP頭裡沒有content-length參數,函數會失敗。
建立INTERNET_BUFFERS結構。
INTERNET_BUFFERS ib = { sizeof(INTERNET_BUFFERS) };
ib.lpvBuffer = 你申請的緩衝
ib.dwBufferLength = 緩衝長度
dwBufferTotal供你自己使用,永遠不會被WinInet該變(據我所知)。我用它來儲存收到資料的總長度。

6&7&8:迴圈讀取剩餘資料
調用InternetReadFileEx(使用IRF_ASYNC標記)非同步讀取剩餘資料。不要使用InternetReadFile,因為它是同步函數。

你必須迴圈調用InternetReadFileEx,直到ib.dwBufferLength為0。在每次迴圈前你必須調整lpvBuffer指標位置,重設ib.dwBufferLength。
BOOL bOk = InternetReadFileEx( m_hHttpFile, &ib, IRF_ASYNC, (LPARAM)this );
if(!bOk && GetLastError()==ERROR_IO_PENDING)
  等待...

while( bOk && ib.dwBufferLength!=0 )
{
  (調整ib值)
  bOk = InternetReadFileEx( m_hHttpFile, &ib, IRF_ASYNC, (LPARAM)this );
  if(!bOk && GetLastError()==ERROR_IO_PENDING)
    等待...
}

你的回呼函數會收到這些訊息:
[connect] InternetStatus: 40 (receiving response)
[connect] InternetStatus: 41 (response received)
[connect] InternetStatus: 50
[connect] InternetStatus: 51
還可能
[connect] InternetStatus: 100 INTERNET_STATUS_REQUEST_COMPLETE

最後一個只有在GetLastError值為ERROR_IO_PENDING才會得到。如果你用dwBufferTotal儲存了資料總大小(按位元組),把你的字元緩衝最後一位置置為0(如果是字元的話)。
buf[ib.dwBufferTotal] = 0;

9:關閉串連控制代碼
InternetCloseHandle( m_httpFile );
關閉時,回調會收到這個訊息:
[connect] InternetStatus: 70 INTERNET_STATUS_HANDLE_CLOSING

大多數錯誤例子中,串連都會出乎意料的關閉。此時,你會收到70在100(INTERNET_STATUS_REQUEST_COMPLETE)之後。

此情形在整個過程都可能會發生。

10:關閉m_Session控制代碼前
你應該卸載回調:
InternetSetStatusCallback( m_Session, NULL );

以上將協助那些使用WinInet非同步方式的人。(之後是老美希望大家購買他的代碼,略過...)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.