程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> BCB創建基於Internet的點對點Chat

BCB創建基於Internet的點對點Chat

編輯:關於C++

創建基於Internet的應用程序,你也許會想到復雜的WinSock編程。不過,C++ Builder3提供了新的WebBroker的Internet套件,其中的TClientSocket和TServerSocket組件封裝了Windows的有關API,大大簡化了WinSock編程。要通過Internet傳輸數據,至少需要一對Socket,一個Socket在客戶端,另一個Socket在服務器端。其實TClientSocket、TServerSocket組件並不是Socket對象,其屬性Socket將返回各自的Socket對象。TClientSocket用來處理客戶端到服務器端之間的socket連接,TServerSocket用來處理由客戶端發來的socket連接,一旦客戶端和服務器端都接通了socket,客戶端和服務器端就可以相互通信了。

建立一新項目,創建應用程序的用戶界面:

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

2.放兩個TMemo組件到窗體上,用來分別顯示雙方的談話內容,將Memo2的ReadOnly屬性設為True。

3.在窗體的頂部放上一個Panel組件,在其上放三個按鈕:監聽(btnlisten)、連接(btnconnect)、斷開(btndisconnect),用來啟動相應的操作。

4.在窗體底部放一個StatusBar組件,將其SimplePanel屬性設為True,在相應的事件處理程序中改變狀態條信息,讓用戶隨時了解連接狀態。

打開頭文件,在窗體類的Private段添加兩個私有成員: bool IsServer;String Server。雙方通信時需同時運行Chat程序,IsServer用來確定哪個Chat程序處於服務器端,Server用來存放服務器的主機名。建立窗體類的構造器如下:

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

這裡Server被缺省設為localhost,這樣程序可以在沒有連入Internet的單機上進行調試。在Windows子目錄下你可以找到hosts.sam文件中,在該文件中已經將本機IP地址127.0.0.1定義了主機名:localhost。

void __fastcall TForm1::FormCreate(TObject *Sender)
{
btndisconnect- >Enabled=false;
}

程序運行後,如果用戶按下"監聽"鈕,則將該程序設為服務器端,這時應將TServerSocket的Active屬性設為True,使服務器自動進入監聽狀態。

void __fastcall TForm1::btnlistenClick(TObject *Sender)
{
ClientSocket1- >Active=false;
ServerSocket1- >Active=true;
StatusBar1- >SimpleText="正在監聽...";
btnlisten- >Enabled=false;
btnconnect- >Enabled=false;
}

當用戶按下"連接"鈕後,程序會彈出一個詢問框,要求用戶輸入要連接的服務器的主機名,然後建立連接。

void __fastcall TForm1::btnconnectClick(TObject *Sender)
{
if(InputQuery("連接到服務器","輸入服務器地址:",Server)){
if(Server.Length() >0){
ClientSocket1- >Host=Server;
ClientSocket1- >Active=true;
btnlisten- >Enabled=false;
btnconnect- >Enabled=false;
btndisconnect- >Enabled=true;
}
}
}

當用戶提出連接請求後,客戶端會觸發OnCreate事件,程序先在狀態條中顯示連接信息,然後將顯示對方談話內容的Memo2清空,准備開始交談。

void __fastcall TForm1::ClientSocket1Connect(TObject *Sender,
TCustomWinSocket *Socket)
{
StatusBar1- >SimpleText="連接到:"+Server;
Memo2- >Lines- >Clear();
}

在服務器接受了客戶的請求後會觸發OnAccept事件,在這個事件處理程序中將標志服務器端的變量IsServer設為True,並准備開始交談。

void __fastcall TForm1::ServerSocket1Accept(
TObject *Sender,
TCustomWinSocket *Socket)
{
Memo2- >Lines- >Clear();
IsServer=true;
StatusBar1- >SimpleText="連接到:"
+Socket- >RemoteAddress;
}

在建立連接後,雙方就可以在Memo1中輸入談話內容開始進行交談了,按下Enter鍵後,將所在行的文本發送出去。服務器端的Socket的Connections屬性返回一個數組,該數組由服務器當前活動的連接組成。

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]);
}
}

在本例中我們采用非阻塞傳輸方式,當其中的一方進行寫操作時,另一方會觸發OnRead事件(客戶端)或OnClientRead事件(服務器端),這兩個事件的處理程序只是將接收到的內容添加到Memo2的後面。

Memo2- >Lines- >Add(Socket- >ReceiveText());

如果在用戶建立連接後單擊"斷開"鈕,將斷開客戶端與服務器的連接,服務器端將觸發OnClientDisconnect事件,而客戶端則會觸發OnDisconnect事件,這時服務器端應回到監聽狀態,等待用戶的連接;而客戶端將返回到連接前的狀態,等待用戶再次建立連接,如果有不止一個服務器的話,可以選擇連接到其他的服務器上。

void __fastcall TForm1::btndisconnectClick(
TObject *Sender)
{
ClientSocket1- >Close();
}
void __fastcall TForm1::ServerSocket1ClientDisconnect(
TObject *Sender,
TCustomWinSocket *Socket)
{
StatusBar1- >SimpleText="正在監聽...";
}
void __fastcall TForm1::ClientSocket1Disconnect(
TObject *Sender, TCustomWinSocket *Socket)
{
btnlisten- >Enabled=true;
btnconnect- >Enabled=true;
btndisconnect- >Enabled=false;
StatusBar1- >SimpleText="";
}

此外在客戶端還應該增加錯誤捕獲機制,當用戶輸入無效的服務器名或服務器端沒有處於監聽狀態時能夠及時給用戶反饋信息。

void __fastcall TForm1::ClientSocke
t1Error(TObject *Sender,
TCustomWinSocket *Socket,
TErrorEvent ErrorEvent, int &ErrorCode)
{
StatusBar1- >SimpleText="無法連接到:
"+Socket- >RemoteHost;
ErrorCode=0;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved