Win32 網絡API使用詳細說明

說明:項目中要用到HTTP代理,網上找了些資料,發現此文不錯,轉之以備用

本文轉自:http://www.cnblogs.com/EricYang/archive/2010/09/26/1836365.html

HTTP Sessions

MSDN

-------------------------------------------

摘要
這篇技術性文章討論瞭如何利用Microsoft Win32網絡函數創建一個網絡瀏覽器。這篇文章的宗旨是讓讀者瞭解一些Win32網絡函數的作用、能力和使用範圍,而不是爲這些功能給出一個詳細的文檔。這篇文章所配合的SurfBear樣本應用程序使用Win32網絡函數從網絡服務器上讀取HTML文件,並把它們顯示成原始的、沒有經過格式化的文本。
介紹
不通過網絡,你就無法瞭解我的一個朋友。計算機雜誌已經在internet上設置了電子期刊,而本地的報紙也已經把整個段落都放到了網絡上。事實上,許多報紙都在聯機。每個人都有一個主頁,甚至一些無家可歸的人都有一個主頁。雖然有許多關於網絡的消息難免言過其實,但網絡正在變成計算機整體的一部分已經是無庸置疑的了。
Microsoft 已經介紹了Microsoft Win32網絡函數來協助開發者把網絡變成他們的應用程序的整體部分。這些新的功能簡化了使用FTP(文件傳輸協議)、和HTTP(超文本傳輸協議)訪問網絡。使用Win32網絡函數的開發者不需要對TCP/IP或Windows 配件。對於一些最普通的操作,開發者不需要知道他們正在使用的某個協議的細節。
最終,Win32網絡函數將成爲Win32應用程序接口的一部分並且與基於Windows的不同的平臺一起發佈。最初,Win32網絡函數將安裝在一個叫做WININET.DLL的再分佈式動態鏈接庫裏。
網絡函數
最好的探討Win32網絡函數的方法是直接進入代碼。下面的代碼是樣本的代碼,爲了方便閱讀,錯誤處理部分已經被刪除掉了。
HINTERNET hNet = ::InternetOpen("MSDN SurfBear",
PRE_CONFIG_INTERNET_ACCESS,
NULL,
INTERNET_INVALID_PORT_NUMBER,
0) ;
HINTERNET hUrlFile = ::InternetOpenUrl(hNet,
"http://www.microsoft.com/",
NULL,
0,
INTERNET_FLAG_RELOAD,
0) ;
char buffer[10*1024] ;
DWORD dwBytesRead = 0;
BOOL bRead = ::InternetReadFile(hUrlFile,
buffer,
sizeof(buffer),
&dwBytesRead);
::InternetCloseHandle(hUrlFile) ;
::InternetCloseHandle(hNet) ;
上面列舉的代碼包括四個網絡函數:InternetOpen、InternetOpenOrl、InternetReadFile和InternetCloseHandle。下面我們依次對這些函數進行分析。
InternetOpen
InternetOpen初始化WININET.DLL。它在其他的Win32網絡函數之前被調用。
HINTERNET hNet = ::InternetOpen(
"MSDN SurfBear", // 1 LPCTSTR lpszCallerName
PRE_CONFIG_INTERNET_ACCESS, // 2 DWORD dwAccessType
"", // 3 LPCTSTR lpszProxyName
INTERNET_INVALID_PORT_NUMBER, // 4 INTERNET_PORT nProxyPort
0 // 5 DWORD dwFlags
) ;
InternetOpen返回一個類型爲HINTERNET的句柄。其他的Win32網絡函數把這個句柄當作一個參數。現在你不能把一個HINTERNET句柄用在類似於ReadFile之類的其他Win32函數中。但是隨着Microsoft Windows和Microsoft Windows NT網絡支持的成熟,這一點在將來不是不可能實現的。
當你已經結束使用Wein32網絡函數時,你應該調用InternetCloseHandle釋放InternetOpen分配的資源。使用Microsoft基礎類(MFC)的應用程序將從文件的構造程序裏象徵性地調用InternetOpen。絕大多數應用程序都將在每一進程裏調用InternetOpen。
InternetOpen 的第一個參數lpszCallerName指定正在使用網絡函數的應用程序。當HTTP協議使用時,這個名字將變成用戶代理。
第二個參數dwAccessType指定訪問類型。在上面的例子裏,PRE_CONFIG_INTERNET_ACCESS訪問類型指示Win32網絡函數使用登記信息去發現一個服務器。使用PRE_CONFIG_INTERNET_ACCESS需要正確設定登記信息。這裏我耍了一個小花招並讓網絡開發者替我登記註冊。
在登記註冊中,把AccessType設置爲1,則意味着“直接入網”,把AccessType 設置爲2,意味着“使用網關”。把DisableServiceLocation設置爲1,將讓它使用一個已經命名的服務器;否則將找到一個使用註冊信息和名字決議(RNR)應用程序接口的服務器,它是Windows接口的一部分。
其他的訪問類型包括以下幾種:
LOCAL_INTERNET_ACCESS只連接到當地Internet網站。例如,如果我使用SurfBear標誌,我就只能訪問Microsoft整體的Internet網站。
CERN_PROXY_INTERNET_ACCESS使用一個CERN代理去訪問web。CERN代理是一個充當網關的web服務器並且能向要使用代理的服務器發送HTTP請求。
GATEWAY_INTERNET_ACCESS允許連接到World Wide Web。我可以用這個訪問類型去訪問web上的任何站點。
GATEWAY_PROXY_INTERNET_ACCESS和CERN_PROXY_ACCESS訪問類型要求第三個參數給InternetOpen:服務器名(lpszProxyName)。PRE_CONFIG_INTERNET_ACCESS不要求服務器名,因爲他可以爲服務器搜索寄存信息。
NProxyPort參數用在CERN_PROXY_INTERNET_ACCESS中用來指定使用的端口數。使用INTERNET_INVALID_PORT_NUMBER相當於提供卻省的端口數。
最後一個參數棗dwFlags,設置額外的選擇。你可以使用 INTERNET_FLAG_ASYNC標誌去指示使用返回句句柄的將來的Internet函數將爲回調函數發送狀態信息,使用InternetSetStatusCallback進行此項設置。
 
InternetOpenUrl
一旦你把Win32網絡函數初始化了,你就可以使用其他網絡函數。下一個要調用的Internet 函數是InternetOpenUrl。這個函數連接到一個網絡服務器上並且最被從服務器上讀取數據。InternetOpenUrl能對FTP,Gopher或HTTP協議起作用。在這篇文章中,我們只涉及HTTP協議。
HINTERNET hUrlFile = ::InternetOpenUrl(
hNet, // 1 HINTERNET hInternetSession
"http://www.microsoft.com/", // 2 LPCTSTR lpszUrl
NULL, // 3 LPCTSTR lpszHeaders
0, // 4 DWORD dwHeadersLength
INTERNET_FLAG_RELOAD, // 5 DWORD dwFlags
0 // 6 DWORD dwContext
) ;
InternetOpenUrl也返回一個HINTERNET,它被傳遞給在這個URL(統一資源定位)上操作的函數。你應該使用InternetClose來關閉這個句柄的處理。
InternetOpenUrl的第一個參數hInternetSession是從InternetOpen返回的句柄。第二個參數lpszUrl是我們需要的資源的URL(統一資源定位)。在上面的例子中,我們想得到一個Microsoft的web主頁。下面兩個參數lpszHeaders和HeaderLength用來向服務器傳送額外的信息。使用這些參數要求具有正在使用的特定協議的知識。
DwFlag是一個可以用幾種方式修改InternetOpenUrl行爲的標誌,InternetOpenUrl的行爲包括關閉、隱藏,使原始數據可用和用存在的連接取代開闢一個新的連接。
最後一個參數dwContext是一個 DWORD上下文值。如果有一個值已經被指定,它將被送到狀態回調函數。如果這個值是0,信息將不會被送到狀態回調函數。
InternetReadFile
你打開一個文件後,就要讀它,所以下一個函數是InternetReadFile是符合邏輯的:
char buffer[10*1024] ;
DWORD dwBytesRead = 0;
BOOL bRead = ::InternetReadFile(
hUrlFile, // 1 HINTERNET hFile
buffer, // 2 LPVOID lpBuffer
sizeof(buffer), // 3 DWORD dwNumberOfBytesToRead
&dwBytesRead // 4 LPDWORD lpdwNumberOfBytesRead
);
buffer[dwBytesRead] = 0 ;
pEditCtrl->SetWindowText(buffer) ;
InternetReadFile接收InternetOpenUrl返回的句柄。它也對其他Win32網絡函數,例如FtpOpenFile,FopherOpenFile和HttpOpenRequest返回的句柄有影響。
剩下的InternetReadFile的三個參數也非常的明白直接。Inbuffer是指向保留數據的緩衝區的一個無返回值指針,dwNumberOfByteToRead以字節爲單位指定緩衝區的尺寸。最後一個參數,lpdwNumberOfBytesRead是一個指向包含讀入緩衝區字節數的變量的指針。如果返回值是TRUE,而且lpdwNumberOfBytesRead指向0,則文件已經讀到了文件的末尾。這個行爲與Win32 Re3adFile的函數的行爲是一致的。一個真正的web瀏覽器將在InternetReadFile上循環 ,不停地從Internet上讀入數據塊。
爲了顯示緩衝區,向緩衝區添加一個0並把它送到編輯器控制。
這樣,InternetOpen、InternetOpenUrl和InternetReadFile一起創建了Internet瀏覽器的基礎。他們使從Internet上讀取文件就象從你的本地硬盤驅動器上讀取文件一樣容易。
 
HTTP函數
在一些例子中,InternetOpenUrl太普通了,所以你可能需要其他的Win32網絡函數。InternetOpenUrl相當與不同的FTP,GOPHER和HTTP函數的封皮。當使用HTTP時,InternetOpenUrl調用InternetConnect,HttpOpenRequest以及HttpSendRequest,比如說我們想要在下載一個HTML頁之前得到它的尺寸以便於我們在緩衝區中爲其分配適當的尺寸,HttpQueryInfo將得到web頁的大小。
警告:不是所有web 頁都支持得到頁尺寸。(例如:http://www.toystory.com/和http://www.movielink.com/不支持這個功能)另外,TCP/IP能傳遞的數據也比要求的要少。所以,你的應用程序應該處理着兩種情況並且圍繞InternetReadFile循環直到結果爲TRUE同時*lpdwNumberOfBytesRead爲0。
// Open Internet session.
HINTERNET hSession = ::InternetOpen("MSDN SurfBear",
PRE_CONFIG_INTERNET_ACCESS,
NULL,
INTERNET_INVALID_PORT_NUMBER,
0) ;
// Connect to http://www.microsoft.com/.
HINTERNET hConnect = ::InternetConnect(hSession,
"http://www.microsoft.com/",
INTERNET_INVALID_PORT_NUMBER,
"",
"",
INTERNET_SERVICE_HTTP,
0,
0) ;
// Request the file /MSDN/MSDNINFO/ from the server.
HINTERNET hHttpFile = ::HttpOpenRequest(hConnect,
"GET",
"/MSDN/MSDNINFO/",
HTTP_VERSION,
NULL,
0,
INTERNET_FLAG_DONT_CACHE,
0) ;
// Send the request.
BOOL bSendRequest = ::HttpSendRequest(hHttpFile, NULL, 0, 0, 0);
// Get the length of the file.
char bufQuery[32] ;
DWORD dwLengthBufQuery = sizeof(bufQuery);
BOOL bQuery = ::HttpQueryInfo(hHttpFile,
HTTP_QUERY_CONTENT_LENGTH,
bufQuery,
&dwLengthBufQuery) ;
// Convert length from ASCII string to a DWORD.
DWORD dwFileSize = (DWORD)atol(bufQuery) ;
// Allocate a buffer for the file.
char* buffer = new char[dwFileSize+1] ;
// Read the file into the buffer.
DWORD dwBytesRead ;
BOOL bRead = ::InternetReadFile(hHttpFile,
buffer,
dwFileSize+1,
&dwBytesRead);
// Put a zero on the end of the buffer.
buffer[dwBytesRead] = 0 ;
// Close all of the Internet handles.
::InternetCloseHandle(hHttpFile);
::InternetCloseHandle(hConnect) ;
::InternetCloseHandle(hSession) ;
// Display the file in an edit control.
pEditCtrl->SetWindowText(buffer) ;
InternetConnect
InternetConnet函數連接到一個HTTP,FTP或Gopher服務器:
HINTERNET hConnect = ::InternetConnect(
hSession, //1 HINTERNET hInternetSession
"http://www.microsoft.com/", //2 LPCTSTR lpszServerName
INTERNET_INVALID_PORT_NUMBER, //3 INTERNET_PORT nServerPort
"", //4 LPCTSTR lpszUsername
"", //5 LPCTSTR lpszPassword
INTERNET_SERVICE_HTTP, //6 DWORD dwService
0, //7 DWORD dwFlags
O //8 DWORD dwContext
) ;
第六個參數dwService決定服務類型(HTTP,FTP或Gopher)。在上面的例子中,InternetConnect連接到一個HTTP服務器上,因爲dwService被設置成INTERNET_SERVICE_HTTP。第二個參數(設置成http://www.microsoft.com/)提供了服務器的地址。注意,HTTP地址必須爲服務器名作語法分析,InternetOpenUrl爲我們作語法分析。第一個參數hInternetSession是從InternetOpen返回的句柄。第四個、第五個參數提供一個用戶姓名和密碼 。這七個參數沒有控制任何標誌影響HTTP操作。最後一個參數爲狀態回調函數提供前後關係的信息。
HttpOpenRequest
一旦和服務器的連接已經建立,我們打開了想要的文件。HttpOpenRequest和HttpSenRequest一起工作打開文件。HttpOpenRequest去創建一個請求句柄並且把參數存儲在句柄中。HttpOpenRequest把請求參數送到HTTP服務器。
HINTERNET hHttpFile = ::HttpOpenRequest(
hConnect, // 1 HINTERNET hHttpSession
"GET", // 2 LPCTSTR lpszVerb
"/MSDN/MSDNINFO/", // 3 LPCTSTR lpszObjectName
HTTP_VERSION, // 4 LPCTSTR lpszVersion
NULL, // 5 LPCTSTR lpszReferer
0, // 6 LPCTSTR FAR * lplpszAcceptTypes
INTERNET_FLAG_DONT_CACHE, // 7 DWORD dwFlags
0 // 8 DWORD dwContext
) ;
到現在爲止,網絡函數的許多參數看起來都類似。HttpOpenResult的第一個參數是由InternetConnet返回的 HINTERNET。HttpOpenRequest的第七和第八個參數執行與InternetConnect中有相同名字的參數一樣的功能。
第二個參數(“GET”)指定我們想要得到由第三個參數(“/MSDN/MSDNINFO/”)命名的對象。HTTP版已經傳遞第四個參數;現在,它肯定是HTTP棗VERSION。因爲“GET”是最流行的動詞類型,HttpOpenRequest將爲這個參數接收一個空指針。
第五個參數lpszReferer是一個網點的地址。在這個網點上我們發現了我們現在想要看見的URL(統一資源定位)。換而言之,如果你在http://www.home.com/上而且單擊了跳到http://www.microsoft.com/的一個連接,第五個參數就是http://www.home.com/。因爲它使你指向了目標URL(統一資源定位)。這個值可以爲空。第六個參數執行一個我們的程序接收的文件類型列表。把空值傳遞給HttpOpenRequest即通知了服務器只有文本文件可以被接收。
 
HttpSendRequest
除了傳送請求外,HttpSendRequest允許你傳送額外的HTTP標題給服務器。關於HTTP標題的信息可以在http://www.w3.org/ 上的最新的說明上找到。在這個例子中,HttpSendRequest的所有參數都被傳遞爲缺省值。
BOOL bSendRequest = ::HttpSendRequest(
hHttpFile, // 1 HINTERNET hHttpRequest
NULL, // 2 LPCTSTR lpszHeaders
0, // 3 DWORD dwHeadersLength
0, // 4 LPVOID lpOptional
0 // 5 DWORD dwOptionalLength
);
HttpQueryInfo
爲了得到關於文件的信息,在調用HttpSendRequest後使用HttpQueryInfo函數:
BOOL bQuery = ::HttpQueryInfo(
hHttpFile, // 1 HINTERNET hHttpRequest
HTTP_QUERY_CONTENT_LENGTH, // 2 DWORD dwInfoLevel
bufQuery, // 3 LPVOID lpvBuffer
&dwLengthBufQuery // 4 LPDWORD lpdwBufferLength
) ;
查詢的結構是字符串或lpvBuffer中的字符串列表。HTTP_QUERY_CONTENT_LENGTH查詢得到文件的長度。你可以使用HttpQueryInfo查詢大範圍的信息。

總結
Win32網絡函數使從FTP,Gopher和HTTP服務器上讀取信息就想從你的硬盤驅動器上讀取信息一樣容易。僅僅使用4個函數棗InternetOpen,InternetOpenUrl,InternetReadFile和InternetCloseHandle和很少的HTTP知識,你就可以寫一個簡單的網絡瀏覽器。
把這個簡單的瀏覽器變成一個工業性質的瀏覽器將要花費很多工作,包括 一些對HTTP的瞭解,對如何顯示HTML文件的瞭解和以及使用多線程方式的能力。Win32網絡函數將開發者從與TCP/IP,Windows Sockets和HTTP編程有關的大多數煩悶工作中解脫出來

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章