1. 程式人生 > >基於MFC的網路瀏覽器Demo

基於MFC的網路瀏覽器Demo

最近在接觸C++的HTTP程式設計,做了一個網路瀏覽器,僅僅是一個demo版本的,呵呵。下面先介紹一下HTTP的工作原理

HTTP

在介紹HTTP原理之前,不得不提及一位有關Internet的大師級人物,英國電腦科學家蒂姆·伯納斯·李(Tim Berners-Lee),他發明了web瀏覽器,使得Internet的應用變得非常廣泛,Internet的發展也就進入了全球資訊網時代。全球資訊網(World Wide Web,WWW或3W)是基於http協議的一種網路應用,其主要組成有兩部分:一是組成全球資訊網的超連結文件(HTML文件);二是超連結文件的傳輸協議,即HTTP(Hypertext Transfer Protocol)。在Internet中工作的主機,當要訪問全球資訊網的某個網頁時,大致經歷以下幾個步驟(該過程對使用者是透明的):

  1. 使用者首先要確定網頁檔案所在的URL(統一資源定位符),由URL唯一確定使用者要訪問的檔案在Internet上的位置;
  2. 瀏覽器向DNS(域名伺服器)發出請求,要求把相應的域名轉化為IP地址;
  3. DNS進行查詢後,向瀏覽器發出應答,回覆相應的IP地址;
  4. 在查詢得到該網頁所在的伺服器IP後,就進入HTTP的工作階段。瀏覽器向該IP地址的主機發出與埠80建立一條TCP連線的請求(埠80是伺服器提供web服務的預設埠);
  5. 連線建立成功後,瀏覽器發出一條請求傳輸網頁的HTTP命令。格式為GET/待訪問的網頁檔案;
  6. 當改域名的伺服器收到請求後,向瀏覽器傳送相應的待訪問的網頁檔案;
  7. 傳送完成後,由伺服器主動關閉TCP連線,至此,HTTP的工作過程結束;
  8. 瀏覽器顯示收到的相應網頁檔案;若改網頁檔案中包含圖片,則還要與伺服器再次建立一個TCP連線以下載圖片。

在上述的工作步驟中,對瀏覽器來說最關鍵的問題是如何把HTML文件下載到本地的主機上,該任務是由HTTP來完成的,可以認為,HTTP是Web服務的基礎。
HTTP即超文字傳輸協議,1990年提出,目前全球資訊網上使用的主要版本是HTTP/1.0和HTTP/1.1。HTTP工作於客戶端-伺服器模式(C-S模式),瀏覽器是客戶端,接收連線並對請求返回資訊的應用程式是Web伺服器。在實際工作時,瀏覽器相當於一個使用者代理(User Agent),使用者要求完成的各種操作均由它向Web伺服器提出,並處理又伺服器返回給客戶端的響應。
下面介紹一下另外一個概念:URL

URL

URL即統一資源定位符(Uniform Resource Locator,URL),是用來表示從Internet上得到資源位置的訪問這些資源的方法。URL給資源的位置提供一種抽象的識別方法,並用這種方法給資源定位。只要能夠對資源定位,系統就可以對資源進行各種操作,如存取、更新、替換等URL相當於一個檔名在網路範圍的擴充套件,可以認為是與Internet相連的機器上的任何可訪問物件的一個指標,其組成有如下四部分:

<協議>://<主機>:<埠>/<路徑>

呵呵,在進入開發之前,先介紹一下MFC對瀏覽器開發提供的技術支援。

MFC提供的技術支援

瀏覽器(Browser)是全球資訊網的客戶端瀏覽程式,可以向Web伺服器傳送各種請求,並對伺服器返回的超文字資訊和各種媒體資料格式進行解析、顯示和播放。目前,PC上常用的瀏覽器有IE、Mozilla的Firefox、360安全瀏覽器、騰訊TT瀏覽器等。從軟體開發的角度來看,可以認為瀏覽器軟體的構成有如下兩部分:Socket程式和HTTP協議
MFC(Microsoft Foundation Classes,微軟基礎類庫,一種應用框架)在Windows API的基礎上封裝了一組C++類,以C++類庫的形式構建了面向物件的框架。自然對於瀏覽器的開發,簡單地呼叫WinSock API即可,呵呵O(∩_∩)O~
從組成上看,網路瀏覽器一般包括以下幾個部分:HTML直譯器、HTML執行器和應用程式介面控制。MFC中提供的CHtmlView類能夠很好地實現對HTML文件的解釋和顯示。對於瀏覽器,除了訪問web站點,還可以瀏覽本地和網路檔案系統、維護歷史記錄等,以上功能均能通過CHtmlView類來實現。
此外,為了方便Internet應用程式,MFC提供了WinInet的封裝,該類是一些類和全域性函式的集合,包括對HTTP、FTP、Gopher等協議的實現。這樣即使不理解TCP/IP協議和套接字程式設計,也能開發出Internet應用程式。在WinInet提供的類中,主要有以下三種類型:

  • 處理Internet會話的類
  • 處理Internet連線的類
  • 處理檔案的類

因此,開發個人版網路瀏覽器的思路很清晰,利用CHtmlView類的功能,配合使用WinInet提供的介面即可
在介紹開發瀏覽器之前,先介紹一下MFC的“文件/檢視結構”,呵呵,進入正題如此艱難。

文件/檢視結構

文件/檢視結構是MFC提供的一種通用的windows程式框架,大多數windows程式採用的都是這種標準框架。其中,文件是應用程式資料基本元素的集合,它構成應用程式鎖使用的資料單元,另外還對資料進行管理和維護,通常將資料儲存在文件類的成員變數中檢視是資料的使用者視窗,為使用者提供了文件的可視顯示,把文件的部分或者全部內容在視窗中顯示出來,檢視還提供使用者與文件中的資料進行互動的介面,把使用者的輸入轉化為對文件中資料的操作
常用的文件/檢視結構的程式主要有兩種:單文件介面(SDI)多文件介面(MDI)應用程式
文件/檢視結構的提出大大簡化了應用程式的設計開發過程,其優點如下:

  • 將資料操作和資料顯示、使用者介面分離開。
    體現了一種“分而治之”的思想,使得模組劃分更加合理、獨立性更強,同時也簡化了資料操作、顯示和使用者介面工作。文件只負責使用者管理,不涉及使用者介面;檢視只負責資料輸出與使用者介面的互動,可以不考慮應用程式的資料是如何組織的,甚至文件中的資料結構發生變化時也不必改動檢視的程式碼;

  • MFC在文件/檢視結構上集成了很多標準操作介面,包括新建、開啟、儲存等,減少了開發人員的工作量;

  • 支援列印預覽和電子郵件傳送功能。

下面進入正題。開發個人版本的網路瀏覽器

開發步驟

1.建立文件/檢視工程,選擇單個文件,具體設定如下:

這裡寫圖片描述
這裡寫圖片描述
在高階功能中無需勾選Windows套接字,因為在CHtmlView類中已經封裝了IE核心,已經包含Socket功能,不需要單獨去實現。最後一步生成的檢視類的基類選擇CHtmlView,必須使檢視類繼承自CHtmlView類。
這裡寫圖片描述

2.新增位址列

設定在資源檢視中的Dialog中設計位址列如下:
這裡寫圖片描述
為GO按鈕新增事件處理程式如下:

CString sWebAddress;
    //獲取編輯框使用者輸入的web地址m_wndDlgBar.GetDlgItem(IDC_EDIT_ADDRESS)->GetWindowText(sWebAddress);
    //瀏覽相應的網頁
((CHtmlView *)GetActiveView())->Navigate(sWebAddress);

其中,Navigate方法是CHtmlView類的常用方法之一,用於獲取指定網址的頁面,並將其返回給檢視。
一般情況下,使用者在位址列輸入網址後,並不一定要點選“GO”按鈕,大多數情況下會選擇按回車鍵。因此可以考慮新增識別回車的事件,這要用到windows程式內建的訊息對映機制。具體實現如下:
在MainFrm.h中宣告訊息對映函式
afx_msg void OnInputAddress();
在MainFrm.cpp中新增訊息對映
ON_COMMAND(IDOK,OnInputAddress)
具體位置如下:
這裡寫圖片描述

3.設計主選單

一般的瀏覽器都有“前進”、“後退”、“停止”、“重新整理”、“轉到主頁”等網頁導航功能,這些在CHtmlView類中均有相應的實現函式,直接呼叫即可。
選單設計如下:
這裡寫圖片描述
可以為每個選單選項的Prompt屬性新增相應的內容,實現滑鼠懸停提示功能,如:對於“後退”選單,對其新增Prompt屬性:轉到上一頁\n後退
這裡寫圖片描述
其中,Prompt屬性“\n”之前的文字用於指定選定選單項時出現在狀態列的文字,“\n”之後的文字則是滑鼠放在工具欄對應功能按鈕上時出現的提示文字。
為“後退”子選單新增事件處理程式如下:

CSelfBrowserView::GoBack();//後退

這裡寫圖片描述
這裡寫圖片描述
在CHtmlView類的方法列表中已經實現了GoBack、GoForward、GoHome等這些瀏覽器通用的基本功能,直接呼叫即可。為其他選單分別新增事件處理程式如下:

void CSelfBrowserView::OnForward()
{
    // TODO: 在此新增命令處理程式程式碼
    CSelfBrowserView::GoForward();//前進
}

void CSelfBrowserView::OnHome()
{
    // TODO: 在此新增命令處理程式程式碼
    CSelfBrowserView::GoHome();//主頁
}

void CSelfBrowserView::OnStop()
{
    // TODO: 在此新增命令處理程式程式碼
    CSelfBrowserView::Stop();//停止
}

void CSelfBrowserView::OnRefresh()
{
    // TODO: 在此新增命令處理程式程式碼
    CSelfBrowserView::Refresh();//重新整理
}

4.自定義工具欄

設計工具欄如下:
這裡寫圖片描述
設計工具欄時,相應的圖示ID選擇為上述對應選單的ID。
為了實現位址列的同步更新功能,可以為檢視類新增OnDocumentComplete方法,瀏覽器接收到伺服器發來的新頁面內容時就執行這個方法,新增如下程式碼:

// 每次當前頁面改變,更新位址列的內容和視窗的標題
    ((CMainFrame *)GetParentFrame())->SetURL(lpszURL);
    GetDocument()->SetTitle(lpszURL);

這裡呼叫SetURL()自定義的函式,在檢視類的實現檔案中新增標頭檔案宣告:

#include "MainFrm.h"

在MainFrm.h中宣告該方法。
在MainFrm.cpp中實現SetURL()方法如下:

void CMainFrame::SetURL(LPCTSTR lpszURL)
{
    m_wndDlgBar.GetDlgItem(IDC_EDIT_ADDRESS)->SetWindowText(lpszURL);
}

5.拓展功能

除了基本功能外,一般瀏覽器還有很多拓展功能。用WinInet類可以實現很多拓展功能,下面實現一個“檢視網頁原始碼”的功能。
新設計一個對話方塊如下:
這裡寫圖片描述
新建一個MFC類,命名為CHtmlCodeViewDlg,對話方塊類選擇剛剛設計的對話方塊的ID,實現新新增的類與設計的對話方塊關聯起來。
為選單“原始檔”選單項新增事件處理程式如下:
這裡寫圖片描述

void CSelfBrowserView::OnCode()
{
    // TODO: 在此新增命令處理程式程式碼
    CHtmlCodeViewDlg dlg;
    dlg.DoModal();//生成顯示網頁HTML原始碼的對話方塊
}

OnCode函式過程的程式碼只是生成了用於顯示網頁原始碼的對話方塊窗體物件,而顯示原始碼的過程需要對話方塊自身去實現,該實現過程要放在初始化程式碼中,因此需要為CHtmlCodeViewDlg類新增初始化過程如下:
這裡寫圖片描述
其初始化,新增程式碼如下:

// TODO:  在此新增額外的初始化
    CWaitCursor wait;                       //等待
    CInternetSession session("Self Net");   //新建會話
    CStdioFile *pFile=NULL;                
    CString sWebAddress;
    //從位址列獲取URL
    (((CMainFrame *)GetParentFrame())->m_wndDlgBar).GetDlgItem(IDC_EDIT_ADDRESS)->GetWindowTextA(sWebAddress);
    pFile = session.OpenURL(sWebAddress);   //開啟URL
    if(pFile != NULL)
    {
        CString str,allText,crlf="\r\n";    //回車換行
        while(pFile->ReadString(str))       //讀入頁面內容
        {
            allText+=crlf + str;    
        }
        this->m_htmlCode = allText;
        UpdateData(false);                  //在對話方塊中顯示網頁原始碼

        pFile->Close();                     //關閉檔案
    }
    session.Close();                        //關閉會話

至此,該Demo版本的網路瀏覽器開發已經結束。
執行效果如下:
這裡寫圖片描述
這裡寫圖片描述
工程原始碼
下載