InternetOpen/InternetOpenUrl/InternetReadFile 等相關Win32 網路API 使用詳細說明

來源:互聯網
上載者:User
摘要這篇技術性文章討論了如何利用Microsoft Win32網路函數建立一個網路瀏覽器。這篇文章的宗旨是讓讀者瞭解一些Win32網路函數的作用、能力和使用範圍,而不是為這些功能給出一個詳細的文檔。這篇文章所配合的SurfBear樣本應用程式使用Win32網路函數從網路伺服器上讀取HTML檔案,並把它們顯示成原始的、沒有經過格式化的文本。介紹不通過網路,你就無法瞭解我的一個朋友。電腦雜誌已經在internet上設定了電子期刊,而本地的報紙也已經把整個段落都放到了網路上。事實上,許多報紙都在聯機。每個人都有一個首頁,甚至一些無家可歸的人都有一個首頁。雖然有許多關於網路的訊息難免言過其實,但網路正在變成電腦整體的一部分已經是無庸置疑的了。Microsoft 已經介紹了Microsoft Win32網路函數來協助開發人員把網路變成他們的應用程式的整體部分。這些新的功能簡化了使用FTP(檔案傳輸通訊協定)、和HTTP(超文字傳輸通訊協定 (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。下面我們依次對這些函數進行分析。InternetOpenInternetOpen初始化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 頁都支援得到頁尺寸。(例如:www.toystory.com和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 www.microsoft.com.
HINTERNET hConnect = ::InternetConnect(hSession,
                                    "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
          "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。第二個參數(設定成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將為這個參數接收一個null 指標。
    第五個參數lpszReferer是一個網點的地址。在這個網點上我們發現了我們現在想要看見的URL(統一資源定位)。換而言之,如果你在www.home.com上而且單擊了跳到www.microsoft.com的一個串連,第五個參數就是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編程有關的大多數煩悶工作中解脫出來

聯繫我們

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