明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

用C++ Builder創(chuàng)建基于Internet的點(diǎn)對(duì)點(diǎn)Chat

[摘要]北京市白石橋路 周新棟---- 創(chuàng)建基于Internet的應(yīng)用程序,你也許會(huì)想到復(fù)雜的WinSock編程。不過(guò),C++ Builder3提供了新的WebBroker的Internet套件,其中的TClientSocket和TServerSocket組件封裝了Windows的有關(guān)API,大大簡(jiǎn)化了...
北京市白石橋路  周新棟

---- 創(chuàng)建基于Internet的應(yīng)用程序,你也許會(huì)想到復(fù)雜的WinSock編程。不過(guò),C++ Builder3提供了新的WebBroker的Internet套件,其中的TClientSocket和TServerSocket組件封裝了Windows的有關(guān)API,大大簡(jiǎn)化了WinSock編程。要通過(guò)Internet傳輸數(shù)據(jù),至少需要一對(duì)Socket,一個(gè)Socket在客戶端,另一個(gè)Socket在服務(wù)器端。其實(shí)TClientSocket、TServerSocket組件并不是Socket對(duì)象,其屬性Socket將返回各自的Socket對(duì)象。TClientSocket用來(lái)處理客戶端到服務(wù)器端之間的socket連接,TServerSocket用來(lái)處理由客戶端發(fā)來(lái)的socket連接,一旦客戶端和服務(wù)器端都接通了socket,客戶端和服務(wù)器端就可以相互通信了。

---- 建立一新項(xiàng)目,創(chuàng)建應(yīng)用程序的用戶界面:

---- 1.將組件頁(yè)切換到Internet頁(yè),放一個(gè)TServerSocket組件和一個(gè)TClientSocket組件到窗體上,這樣應(yīng)用程序既可以是TCP/IP服務(wù)器,也可以是TCP/IP客戶。將Port屬性都設(shè)為同一個(gè)值(如1000),確定Socket之間的連接類型為NonBlocking(非阻塞方式)。

---- 2.放兩個(gè)TMemo組件到窗體上,用來(lái)分別顯示雙方的談話內(nèi)容,將Memo2的ReadOnly屬性設(shè)為True。

---- 3.在窗體的頂部放上一個(gè)Panel組件,在其上放三個(gè)按鈕:監(jiān)聽(btnlisten)、連接(btnconnect)、斷開(btndisconnect),用來(lái)啟動(dòng)相應(yīng)的操作。

---- 4.在窗體底部放一個(gè)StatusBar組件,將其SimplePanel屬性設(shè)為True,在相應(yīng)的事件處理程序中改變狀態(tài)條信息,讓用戶隨時(shí)了解連接狀態(tài)。

---- 打開頭文件,在窗體類的Private段添加兩個(gè)私有成員: bool IsServer;String Server。雙方通信時(shí)需同時(shí)運(yùn)行Chat程序,IsServer用來(lái)確定哪個(gè)Chat程序處于服務(wù)器端,Server用來(lái)存放服務(wù)器的主機(jī)名。建立窗體類的構(gòu)造器如下:

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    IsServer=false;
    Server="localhost";
}


---- 這里Server被缺省設(shè)為localhost,這樣程序可以在沒有連入Internet的單機(jī)上進(jìn)行調(diào)試。在Windows子目錄下你可以找到hosts.sam文件中,在該文件中已經(jīng)將本機(jī)IP地址127.0.0.1定義了主機(jī)名:localhost。
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    btndisconnect- >Enabled=false;
}

---- 程序運(yùn)行后,如果用戶按下"監(jiān)聽"鈕,則將該程序設(shè)為服務(wù)器端,這時(shí)應(yīng)將TServerSocket的Active屬性設(shè)為True,使服務(wù)器自動(dòng)進(jìn)入監(jiān)聽狀態(tài)。
void __fastcall TForm1::btnlistenClick(TObject *Sender)
{
    ClientSocket1- >Active=false;
    ServerSocket1- >Active=true;
    StatusBar1- >SimpleText="正在監(jiān)聽...";
    btnlisten- >Enabled=false;
    btnconnect- >Enabled=false;
}

---- 當(dāng)用戶按下"連接"鈕后,程序會(huì)彈出一個(gè)詢問(wèn)框,要求用戶輸入要連接的服務(wù)器的主機(jī)名,然后建立連接。
void __fastcall TForm1::btnconnectClick(TObject *Sender)
{
    if(InputQuery("連接到服務(wù)器","輸入服務(wù)器地址:",Server)){
        if(Server.Length() >0){
            ClientSocket1- >Host=Server;
            ClientSocket1- >Active=true;
            btnlisten- >Enabled=false;
            btnconnect- >Enabled=false;
            btndisconnect- >Enabled=true;
        }
    }
}


---- 當(dāng)用戶提出連接請(qǐng)求后,客戶端會(huì)觸發(fā)OnCreate事件,程序先在狀態(tài)條中顯示連接信息,然后將顯示對(duì)方談話內(nèi)容的Memo2清空,準(zhǔn)備開始交談。
void __fastcall TForm1::ClientSocket1Connect(TObject *Sender,
      TCustomWinSocket *Socket)
{
    StatusBar1- >SimpleText="連接到:"+Server;
    Memo2- >Lines- >Clear();
}


---- 在服務(wù)器接受了客戶的請(qǐng)求后會(huì)觸發(fā)OnAccept事件,在這個(gè)事件處理程序中將標(biāo)志服務(wù)器端的變量IsServer設(shè)為True,并準(zhǔn)備開始交談。
void __fastcall TForm1::ServerSocket1Accept(
TObject *Sender,
      TCustomWinSocket *Socket)
{
    Memo2- >Lines- >Clear();
    IsServer=true;
    StatusBar1- >SimpleText="連接到:"
+Socket- >RemoteAddress;
}


---- 在建立連接后,雙方就可以在Memo1中輸入談話內(nèi)容開始進(jìn)行交談了,按下Enter鍵后,將所在行的文本發(fā)送出去。服務(wù)器端的Socket的Connections屬性返回一個(gè)數(shù)組,該數(shù)組由服務(wù)器當(dāng)前活動(dòng)的連接組成。
void __fastcall TForm1::Memo1KeyDown(
TObject *Sender, WORD &Key,
      TShiftState Shift)
{
    if(Key==VK_RETURN){
        if(IsServer)
            ServerSocket1- >Socket- >Connections[0]- >SendText(
Memo1- >Lines- >Strings[Memo1- >Lines- >Count-1]);
        else
            ClientSocket1- >Socket- >SendText(
Memo1- >Lines- >Strings[Memo1- >Lines- >Count-1]);
    }
}


---- 在本例中我們采用非阻塞傳輸方式,當(dāng)其中的一方進(jìn)行寫操作時(shí),另一方會(huì)觸發(fā)OnRead事件(客戶端)或OnClientRead事件(服務(wù)器端),這兩個(gè)事件的處理程序只是將接收到的內(nèi)容添加到Memo2的后面。
    Memo2- >Lines- >Add(Socket- >ReceiveText());

---- 如果在用戶建立連接后單擊"斷開"鈕,將斷開客戶端與服務(wù)器的連接,服務(wù)器端將觸發(fā)OnClientDisconnect事件,而客戶端則會(huì)觸發(fā)OnDisconnect事件,這時(shí)服務(wù)器端應(yīng)回到監(jiān)聽狀態(tài),等待用戶的連接;而客戶端將返回到連接前的狀態(tài),等待用戶再次建立連接,如果有不止一個(gè)服務(wù)器的話,可以選擇連接到其他的服務(wù)器上。
void __fastcall TForm1::btndisconnectClick(
TObject *Sender)
{
    ClientSocket1- >Close();
}
void __fastcall TForm1::ServerSocket1ClientDisconnect(
TObject *Sender,
      TCustomWinSocket *Socket)
{
    StatusBar1- >SimpleText="正在監(jiān)聽...";
}
void __fastcall TForm1::ClientSocket1Disconnect(
TObject *Sender, TCustomWinSocket *Socket)
{
    btnlisten- >Enabled=true;
    btnconnect- >Enabled=true;
    btndisconnect- >Enabled=false;
    StatusBar1- >SimpleText="";
}


---- 此外在客戶端還應(yīng)該增加錯(cuò)誤捕獲機(jī)制,當(dāng)用戶輸入無(wú)效的服務(wù)器名或服務(wù)器端沒有處于監(jiān)聽狀態(tài)時(shí)能夠及時(shí)給用戶反饋信息。
void __fastcall TForm1::ClientSocke
t1Error(TObject *Sender,
      TCustomWinSocket *Socket,
TErrorEvent ErrorEvent, int &ErrorCode)
{
StatusBar1- >SimpleText="無(wú)法連接到:
"+Socket- >RemoteHost;
    ErrorCode=0;
}

---- 以上代碼在C++ Builder3 C/S版中編譯、運(yùn)行通過(guò)。