Managed C++設計新郵件檢查器

發表于:2007-05-25來源:作者:點擊數: 標簽:設計managed新郵件C++郵件
一.Managed C++簡介: Managed C++是微軟Visual Studio.Net的一部分,它是從標準C++發展而來的,所以和標準C++幾乎是一樣的。不過因為它是建立在.Net架構之上的,經編譯器編譯后生成的是微軟的中間語言(Microsoft Intermediate Language,MSIL),用它來編

  一.Managed C++簡介:

  Managed C++是微軟Visual Studio.Net的一部分,它是從標準C++發展而來的,所以和標準C++幾乎是一樣的。不過因為它是建立在.Net架構之上的,經編譯器編譯后生成的是微軟的中間語言(Microsoft Intermediate Language,MSIL),用它來編寫的代碼是托管的C++代碼,所以相對標準C++它又多了幾分新異。

  二.新郵件檢查原理簡介:

  首先,我想有必要向大家介紹一下通過POP3協議完成新郵件檢查的基本原理。在了解的其基本原理的基礎上完成整個程序也就變得相對容易了。

  POP3協議工作的基本原理如下:

  一開始便是客戶端與服務器的連接。不過,在客戶端連接到服務器之前,注意把端口設為POP3協議默認的110號。

  客戶端連接服務器成功后,服務器會返回以下信息:

  +OK……

  字符+OK是POP3協議的返回信息。它的回應信息不像SMTP協議那樣用豐富多變的數字表示,只有兩個:+OK或者-ERR。其中,+OK表示連接成功,而-ERR則表示連接失敗。

  接下來,客戶端輸入USER <用戶名>

  該命令告訴服務器你的用戶名。注意,有些服務器會區分大小寫字母的。

  服務器返回+OK后,客戶端輸入PASS <口令>

  服務器返回+OK后,還返回一些郵箱的統計信息,比如:+OK 1 message(s) [1304 byte(s)]

  不同的服務器返回的信息格式不太一樣,所以我們可以用STAT命令來查看郵箱的情況。STAT命令的回應中有兩個數字,分別表示郵件的數量和郵件的大小。

  如果信箱里有信,就可以用RETR命令來獲取郵件的正文。RETR命令的格式為:

   RETR <郵件編號>

  如果返回結果第一行是+OK信息,則表示成功。第二行起便是郵件的正文。最后一行和SMTP協議一樣,是一個單獨的英文句號,表示郵件的結尾部分。

  把郵件存儲起來后要用DELE命令刪除郵箱中的郵件,否則原有的郵件會繼續保留在服務器上,一旦郵件一多,你的郵箱就爆了。DELE命令的格式為:

   DELE <郵件編號>

  如果刪錯了,可以用RSET命令來恢復所有已被刪除的郵件。條件是你還沒有退出,一旦退出,那就一切Bye Bye了。全部完成以后,輸入QUIT命令就可以退出POP3服務器了。

  以上我簡要地向大家介紹了POP3協議工作的基本原理,不過我們程序的任務是完成新郵件檢查,所以以上收取郵件和刪除服務器備份的部分就不需要了。我們要完成的只是從STAT命令的服務器回復中分離出新郵件的數目并向用戶報告。

  三 .程序的實現:

  在介紹完新郵件檢查的基本原理后,我們就不妨著手我們的程序了。首先,打開Visual Studio.Net,新建一個項目,在項目類型里選擇"Visual C++ 項目",在模板中選擇"MC++AppWiz",項目的名稱不妨為"MailChecker",圖示如下:


  在新建完項目后,VS.Net會為我們生成一個框架和一些代碼文件,其中有一個名為"MailChecker.cpp"的文件就是程序的主文件了,我們要做的僅是對它完成編碼工作。

  另外需要注意的是,用Managed C++向導生成的程序是基于控制臺的,所以程序的界面不是傳統的Windows界面,因此會不利于和用戶進行交互,所以在這個程序中我運用了Windows Forms的編程方法編寫出了一個傳統的Windows窗體界面。Windows Forms也是.Net中的一項新概念,它能大大簡化Windows窗體和相關控件的編程,有關Windows Forms的更多知識請讀者參考相關的資料。在這個程序中,我只是運用了Windows Forms的編程方法用純編碼的方式寫出了一個Windows窗體界面,對于一些細節,這不是本文介紹的重點所以也就不多作介紹了,望讀者能理解。

  首先我們得添加對Windows Forms名字空間(namespace)的引用,如此我們才能享受Windows Forms給我們帶來的方便和快捷。方法是在文件開始處添加:

#using WINDOWS.FORMS.DLL>
using namespace System::Windows::Forms;

  同時,我們還要用到一些其他的名字空間的引用,具體這里就不給出了,請讀者參考文后所附的源代碼文件。

  程序的主界面是一個從Form繼承過來的類-MainForm,它的聲明如下:  

public __gc class MainForm : public Form
{
private:
Label *label1;
Label *label2;
Label *label3;
TextBox *ServerAdd;
TextBox *Username;
TextBox *Password;
Button *btnChecker;
CPOP3Client *pPOP3Client;

void btn_Click( Object *sender, System::EventArgs *e );
int MailChecker();

public:
MainForm();
};

  其中包含了一些必要的窗體控件和一個CPOP3Client類的對象pPOP3Client,該類是我們程序的主體,它完成了新郵件檢查的基本工作,我將在后面介紹。

  MainForm類的構造函數MainForm()完成窗體控件的初始化工作,下面的代碼是完全手工編寫的而沒有借助窗體設計器的幫助。不過在Visual C#中我們就可以運用窗體設計器來大大簡化我們的工作,不過自己動手編寫代碼的好處就是能使我們更加深入的了解Windows Forms編程的機理。

  設計好的窗體示意圖如下:




  MainForm類中的按鈕btnChecker的消息響應函數的實現如下:

void MainForm::btn_Click( Object *sender, System::EventArgs *e )
{
 if( sender->Equals( this->btnChecker ) )
 { 
  if( this->ServerAdd->Text != ""
    && this->Username->Text != ""
    && this->Password->Text != "" )
  {
   int number = this->MailChecker();

   if( number > 0 )
   {
    String *info = new String( "你有" );
    info->Concat( number.ToString() );
    info->Concat( S"封新郵件!" );

    MessageBox::Show( info->ToString(), "InfoBox",
    MessageBoxButtons::OK, MessageBoxIcon::Information );
   }
   else if( number == 0 )
   {
    MessageBox::Show( "不好意思,你暫時還沒有新郵件。", "InfoBox",
    MessageBoxButtons::OK, MessageBoxIcon::Information );
   }
  }
}

  該函數完成了按鈕的點擊事件的消息響應,其中調用了本類的一個MailChecker()成員函數,這個方法完成了新郵件檢查的基本工作。只要你的郵箱中有新郵件,程序就會以MessageBox的方式向你報告新郵件的數目。下面是MailChecker()的具體實現方法:

int MainForm::MailChecker()
{
 int numberOfMails;

 // 創建一個POP3Client對象
 pPOP3Client = new CPOP3Client();

 // 設置各項屬性
 pPOP3Client->POP3HostName = this->ServerAdd->Text->ToString();
 pPOP3Client->UserName = this->Username->Text->ToString();
 pPOP3Client->Password = this->Password->Text->ToString();

 // 獲得新郵件數目
 numberOfMails = pPOP3Client->NumberOfMessages;

 if( numberOfMails < 0 )
  MessageBox::Show( "發生錯誤?。?!", "InfoBox",MessageBoxButtons::OK, MessageBoxIcon::Error );

 return numberOfMails;
}

  首先,程序new一個CPOP3Client類的對象pPOP3Client,然后根據用戶的輸入設置該對象的各項必須屬性。接著,程序通過讀取pPOP3Client對象的NumberOfMessages屬性取得新郵件的數目。如果新郵件的數目小于零,那么說明在連接服務器的過程中發生了錯誤并向用戶發出警告。最后程序返回新郵件的數目。


  到此,程序的主界面的類已經完成,接下來我們就開始設計我們的核心類-CPOP3Client類。我們為該類設計了一些必要的方法和屬性,其中方法包括連接服務器的方法-ConnectToServer(),向服務器發送命令的方法-SendCommand()和斷開與服務器連接的方法-DisconnectFromServer()。各個方法的功能是顯而易見的,這里就不贅述。下面給出各個方法的具體實現方法:

//**********************************************************
// 連接到POP3服務器
file://
// 返回值:成功為true,失敗為false
file://**********************************************************
bool ConnectToServer()
{
 String *strReadBuffer;
 StreamReader *streamRead;

 // 關閉已存在的連接
 Close();

 // 和服務器建立一個連接
 m_Client = new TcpClient(m_strPOP3HostName, 110);

 // 創建一個讀取流
 streamRead = new StreamReader(m_Client->GetStream(), Encoding::ASCII );

 strReadBuffer = streamRead->ReadLine();

 // 忽略buffer中的多余部分
 streamRead->DiscardBufferedData();

 // 回復是否以+OK開頭,是則成功,否則失敗.
 if(strReadBuffer->StartsWith("+OK"))
  return true;
 else
 {
  Close();
  return false;
 }
}

  該方法首先創建一個TcpClient類的對象,根據這個對象獲取一個網絡讀取流,通過這個流,我們就可以和服務器實現通訊。根據從服務器讀取的信息,我們決定是否已成功的和服務器取得連接,即若服務器返回的信息以"+OK"開頭則表示成功,否則則是失敗了。

//**********************************************************
// 將命令發送到服務器,并從服務器獲得相應的回復
file://
// 參數:strCommand - 發送到服務器的命令,pstrOutput - 從服務器獲得的回復
file://
// 返回值:成功為true,失敗為false
file://**********************************************************
bool SendCommand(String *strCommand, String** pstrOutput)
{
 Byte outbuffer __gc[];

 StreamReader *streamRead;
 NetworkStream *streamWrite;
 String *strRequest;

 if (m_Client == NULL)
  return false;

 // 給每個命令添加結束符
 strRequest = String::Concat(strCommand, S"\r\n");

 // 創建一個從套接字讀寫數據的流
 streamWrite = m_Client->GetStream();
 streamRead = new StreamReader(streamWrite, Encoding::ASCII);

 // 將字符串轉化為字節流并將它寫入套接字中
 outbuffer = Encoding::ASCII->GetBytes(strRequest);
 streamWrite->Write(outbuffer, 0, outbuffer->Length);

 // 從套接字讀取回復
 *pstrOutput = streamRead->ReadLine();

 // 忽略buffer中的多余部分
 streamRead->DiscardBufferedData();

 return (*pstrOutput)->StartsWith(S"+OK") ? true : false;
}

  該方法中我們首先獲取網絡讀寫流,根據該流和服務器進行通訊:首先將字符串轉化為字節流并將它寫入套接字中,然后讀取服務器的回復,如果返回信息以"+OK"開頭,該方法則返回true,否則則返回false。

//**********************************************************
// 斷開與POP3服務器的連接
file://**********************************************************
void DisconnectFromServer()
{
 String *strResponse = String::Empty;

 SendCommand("QUIT", &strResponse);

 Close();
}

  該方法向服務器發送QUIT命令表示和服務器斷開連接。以上的方法大量運用了.Net網絡編程和輸入輸出流操作的方法,所以要用到有關網絡編程和輸入輸出流的名字空間,因此務必不要忘了在文件開始處添加如下一些語句:

using namespace System::Net::Sockets;
using namespace System::IO;
using namespace System::Text;

  到此,我們設計好了該類的基本方法,剩下的就是完成對各項屬性的設計了。在一個郵件客戶端程序中,我想以下一些屬性是必須的:服務器地址,端口號(此處已預設為110,所以不必考慮),用戶名,密碼,狀態和新郵件數目。其中狀態和新郵件數目都是從服務器獲得的信息,所以只能是只讀的。以下就是對這些屬性的設計:

// POP3服務器地址
__property String* get_POP3HostName()
{
return m_strPOP3HostName;
}

__property void set_POP3HostName(String* strPOP3HostName)
{
m_strPOP3HostName = strPOP3HostName;
}

// 用戶名
__property String* get_UserName()
{
return m_strUserName;
}

__property void set_UserName(String *strUserName)
{
m_strUserName = strUserName;
}

// 密碼
__property String* get_Password()
{
return m_strPassword;
}

__property void set_Password(String *strPassword)
{
m_strPassword = strPassword;
}

// 狀態
__property String* get_Status()
{
return m_strStatus;
}

// 新郵件數目
__property int get_NumberOfMessages()
{
String *strResponse = String::Empty;
String *strNrOfMessages;

Char separator __gc[] = new Char __gc[1];
separator[0] = ' ';

try
{
if(!ConnectToServer())
return -1;

if(!SendCommand(String::Concat(S"USER ", m_strUserName),
&strResponse))
{
return -1;
}


if(!SendCommand(String::Concat(S"PASS ", m_strPassword),
&strResponse))
{
return -1;
}

if(!SendCommand(S"STAT", &strResponse))
{
return -1;
}


// 從回復信息中獲得新郵件的數目
strNrOfMessages = strResponse->Split(separator)[1];

return Convert::ToInt32(strNrOfMessages);
}
catch(Exception* e)
{
m_strStatus = String::Concat(S"Error: ", e->Message);
return -1;
}
__finally
{
DisconnectFromServer();
}
}


  所有的屬性中新郵件數目屬性是最重要的一個,它調用了本類的各個方法,完成了連接服務器,向服務器發送各種命令并取得有關新郵件數目的信息,最后斷開與服務器的連接。同時還處理了一些異常情況。這樣,在程序的主界面類中我們只要讀取該類的對象的新郵件數目屬性就可以獲取郵箱中的新郵件數目,而不必去考慮如何實現服務器的連接、通訊和斷開連接等操作了,這正體現出了面向對象設計的優勢所在。

  這樣我們就完成了整個程序的設計和編碼工作,接下來讓我們測試一下自己的成果吧。運行程序如下:


  在設置好相關參數后,點擊"Check Mail!"按鈕,不久程序就會彈出一個MessageBox來向用戶報告其郵箱中的新郵件數目,圖示如下:


  四.全文小結:

  本文向讀者介紹了如何運用Managed C++創建一個新郵件檢查器,其中大量運用了Windows Forms編程和.Net框架下的網絡編程的原理。通過本文,希望能使讀者對.Net中的Managed C++有一個感性的認識,同時對Windows Forms編程和其中的網絡編程也有個大致的了解。最后,希望各位能盡快掌握.Net中的各種新技術并付諸于實踐應用中。

原文轉自:http://www.anti-gravitydesign.com

評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)
国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97