線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2541
推到 Plurk!
推到 Facebook!

[推薦] 用WinSock控件編寫網絡聊天器

 
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-07-25 10:09:29 IP:61.218.xxx.xxx 未訂閱
用WinSock控件編寫網絡聊天器    資料來源: http://go5.163.com/yarrows/tips/cbc_48.htm 一.認識C Builder中的WinSock控件及其相關類 WinSock是一組用C語言寫的API,用於通過Internet進行數據傳輸。通過WinSock編程可以獲得更大的靈活性。編寫WinSock應用程序本來是很麻煩的,不過,在C Builder 5.0中,您並不需要直接與WinSock中的API打交道,因為C Builder 5.0新增加了TClientSocket控件和TserverSocket控件,這兩個控件封裝了Windows的有關API,使得對WinSock的訪問大大簡化。用Socket 建立的連接是建立在TCP/IP協議基礎上的,同時也支持其它相關的協議,如XNS、DECnet以及 IPX/SPX等。Socket的連接必須要建立有一個服務器端(Server)和一個客戶端(Client)。在C Builder 5.0中分別用TClientSocket控件和TServerSocket控件來操縱客戶端Socket與服務器端Socket的 連接和通信。這兩個控件用於管理服務器和客戶的連接,它們本身並不是Socket對象,操縱 Socket對象的是TCustomWinSocket及其派生類,如TClientWinSocket、TserverWinSocket . TServerClientWinSocket等。 Socket之間的連接可以分為三種類型:客戶端連接、監聽連接以及 服務器端連接,所謂客戶端連接,是指由客戶端的Socket提出連接請求,要連接的目標是服務 器端的Socket。為此,客戶端的Socket必須首先描述它要連接的服務器端Socket(主要是指服務器 端Socket的地址和端口號),然後再定位所要連接的服務器端Socket,找到以後,就向服務器端 Socket請求連接。當然,服務器端的Socket此時未必正好處於準備好狀態,不過,服務器端的 Socket會自動維護客戶請求連接的隊列,然後在它認為合適的時候向客戶端Socket發出“允許連接” (Accept)的信號,這時客戶端Socket與服務器端Socket的連接就建立了。所謂監聽連接,服務器端 Socket並不定位具體的客戶端Socket,而是處於等待連接的狀態。當服務器端Socket監聽到或者說 接收到客戶端Socket的連接請求,它就響應客戶端Socket的請求建立一個新的Socket句柄並與客戶 端連接,而服務器端Socket繼續處於監聽狀態,還可以接收其它客戶端Socket的連接請求。所謂服 務器端連接,是指當服務器端Socket接收到客戶端Socket的連接請求後,就把服務器端Socket的描述 發給客戶端,一旦客戶端確認了此描述,連接就建立了。在本文中的聊天程序用的就是監聽連接, 即服務器設置連接個數後進行監聽,客戶端進行對服務器端的連接,這樣就可以進行相互通信了。 二.TServerSocket和TClientSocket控件的屬性 1.ServerSocket的控件屬性 threadcachsize:創建服務器線程的最在數目。 port:確定服務器的監視端口。 service:客戶通過此屬性來識別服務器端口。 2.ClientSocket的控件屬性 Socket:此屬性參數是應用程序之間通信的端點。 Address:此屬性參數為字符串類型,客戶端確定服務器端的IP地址。 Host:服務器端的主機名稱。 Post:服務器端的監視端口。 Servce:用來識別服務器端口。 Active:確定Socket是否可用(true表示可用)。 ClientType:指定客戶機採用哪一種方式(異步/同步)來通信。 三.ServerSocket和ClientSocket控件的事件 1.ServerSocket的事件 onclientconnect:客戶與服務器連接且服務器接收申請後,產生此事件。 onclientdisconnect:當和服務器連接的某一個客戶機關閉連接後產生此事件。 onGetSocket:一個服務器可以接收多個客戶Socket的連接申請。 onGetThread:當ClientType屬性值設為StrThreadBlocking時,服務器會產生一個單獨的線程來與客戶的連接。 onAccept:服務器接收客戶的連接申請後,產生此事件。 onClientRead:客戶機發送數據到服務器時產生的事件。 2.ClentSocket事件 onConnect:當客戶端與服務器端連接上後,產生此事件。 onConnecing:當客戶端與服務器端進行連接操作時,產生此事件。 onDisconnect:當客戶端關閉操作後產生此事件。 onError:在客戶與服務器在建立和通信過程中,如果產生錯誤時,產生此事件。 onLookup:當客戶在計算機網絡中尋找服務器時,產生此事件。 onRead:數據到達時產生此事件。 四.ServerSocket和ClientSocket的方法 1.Open方法 此方法適用於ServerSocket和CilentSocket進行建立連接,原型如下: void-Fastcall open(void); 2.Close方法 此方法適用於ServerSocket和CilentSocket進行關閉連接,原型如下: void-Fastcall close(void); 五.編寫聊天程序 打開C Builder 5.0新建一個工程,新建一個Form1窗體,在Form1窗體中添加以下控件: ClientSocket控件: 1個 ServerSocket控件: 1 個 Button控件: 4個 Label控件: 2個 Memo控件: 1個 Edit控件: 2個 TreeView控件: 1個 StatusBar控件: 1個 添加控件 各控件屬設置如下: Form1窗體:Caption="網絡聊天器". ServerSocket: Name=ServerSocket1;port=10000;ServerType=stNonBlocking;ThreadCacheSize=10. ClientSocket: Name=ClientSocket1;port=10000;ClientType=stNonBlocking. Mome:Name=Mome1;ScrollBars=ssVertical. TreeView:Name=TreeView1; Button: 第一個:Name=Btnlisten;Caption="監聽"; 第二個:Name=Btnconnect;Caption="連接"; 第三個:Name=Btndisconnect;Caption="斷開"; 第一個:Name=BtnExit;Caption="退出"; Label: 第一個:Name=Label1;Caption="發送"; 第二個: Name=Label2;Caption="在線客戶". Edit: 第一個:Name=Edit1; 第二個: Name=Edit2; StatusBar:Name=StatusBar1; 設置好以上屬性值,就可以進行代碼的編寫了,源程序代碼如下:
    //-------------------------- //"Unit1.h"的源程序 //-------------------
#ifndef Unit1H
#define Unit1H
//--------------------------------------------------------------------
#include 
#include 
#include 
#include <Forms.hpp>
#include 
#include 
#include 
#include 
#include 
//---------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TClientSocket *ClientSocket1;
TServerSocket *ServerSocket1;
TMemo *Memo1;
TStatusBar *StatusBar1;
TEdit *Edit1;
TLabel *Label1;
TTreeView *TreeView1;
TLabel *Label2;
TEdit *Edit2;
TButton *Btnlisten;
TButton *Btnconnect;
TButton *Btndisconnect;
TButton *BtnExit;
void __fastcall FormCreate(TObject *Sender);
void __fastcall ClientSocket1Connect(TObject *Sender,
TCustomWinSocket *Socket);
void __fastcall ServerSocket1Accept(TObject *Sender,
TCustomWinSocket *Socket);
void __fastcall ServerSocket1ClientDisconnect(TObject *Sender,
TCustomWinSocket *Socket);
void __fastcall ClientSocket1Disconnect(TObject *Sender,
TCustomWinSocket *Socket);
void __fastcall ClientSocket1Error(TObject *Sender,
TCustomWinSocket *Socket, TErrorEvent ErrorEvent,
int &ErrorCode);
void __fastcall ClientSocket1Read(TObject *Sender,
TCustomWinSocket *Socket);
void __fastcall ServerSocket1ClientRead(TObject *Sender,
TCustomWinSocket *Socket);
void __fastcall Edit1KeyDown(TObject *Sender, WORD &Key,
TShiftState Shift);
void __fastcall ClientSocket1Lookup(TObject *Sender,
TCustomWinSocket *Socket);
void __fastcall TreeView1Change(TObject *Sender, TTreeNode *Node);
void __fastcall BtnlistenClick(TObject *Sender);
void __fastcall BtnconnectClick(TObject *Sender);
void __fastcall BtndisconnectClick(TObject *Sender);
void __fastcall BtnExitClick(TObject *Sender);
private:
bool IsServer;
String Server;
// User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//-------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//-------------------------------------------------------------------------
#endif //"Unit1.cpp"源程序 //-----------------------------------------------
#include 
#include 
#pragma hdrstop #include "Unit1.h"
//--------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//--------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
IsServer=false;
Server="";
}
//--------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Btndisconnect->Enabled=false;
} //------------------------------------------------------------------------    //當用戶提出連接請求後,客戶端會觸發OnCreate事件
void __fastcall TForm1::ClientSocket1Connect(TObject *Sender,
TCustomWinSocket *Socket)
{
StatusBar1->SimpleText="連接到:" Server;
TreeView1->Items->Add(TreeView1->Selected ,Server);
Memo1->Lines->Clear();
//定義mouse的類型
Form1->Cursor=crDefault ;
Edit1->Cursor=crDefault;
Memo1->Cursor=crDefault;
//產生一個新的監聽 }
//-------------------------------------------------------------------------
//在服務器接受了客戶的請求後會觸發OnAccept事件
void __fastcall TForm1::ServerSocket1Accept(TObject *Sender,
TCustomWinSocket *Socket)
{ Memo1->Lines->Clear();
IsServer=true;
StatusBar1->SimpleText="連接到:" Socket->LocalHost;
TreeView1->Items->Add(TreeView1->Selected ,Socket->LocalHost);
}
//-------------------------------------------------------------------------
//斷開後繼續監聽
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::ClientSocket1Error(TObject *Sender,
TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
ShowMessage("錯誤!!! 無法連接到服務器");
ErrorCode=0;
Btnlisten->Enabled=true;
Btnconnect->Enabled=true;
Btndisconnect->Enabled=false;
StatusBar1->SimpleText="";
//定義mouse的類型
Form1->Cursor=crDefault ;
Edit1->Cursor=crDefault;
Memo1->Cursor=crDefault;
Form1->Caption ="網絡聊天器";
}
//-------------------------------------------------------------------------
//客戶端接收數據
void __fastcall TForm1::ClientSocket1Read(TObject *Sender,
TCustomWinSocket *Socket)
{
Memo1->Lines->Add(Socket->ReceiveText());
}
//---------------------------------------------------------------------------
//服務器端接收數據
void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
TCustomWinSocket *Socket)
{
Memo1->Lines->Add(Socket->ReceiveText());
}
//-------------------------------------------------------------------------    //在建立連接後,雙方就可以在Edit1中輸入談話內容開始進
//行交談了,按下Enter鍵後,將所在行的文本發送出去
void __fastcall TForm1::Edit1KeyDown(TObject *Sender, WORD &Key,
TShiftState Shift)
{
AnsiString Data;
if(Key==VK_RETURN)
{if (Edit2->Text!="") //在沒有選擇發送的主機名時不能進行發送操作
{if(IsServer) //服務器端發出的數據
{Data= "[" TimeToStr(Now()) "]:(" ServerSocket1->Socket->LocalHost ")對" "(" Edit2->Text ")" "說:" Edit1->Text;
ServerSocket1->Socket->Connections[TreeView1->Selected->Index]->SendText(Data);
Memo1->Lines->Add(Data);
Edit1->Text="";}
else //客戶端發出的數據
{ Data="[" TimeToStr(Now()) "]:(" ClientSocket1->Socket->LocalHost ")對" "(" Edit2->Text
 ")" "說:" Edit1->Text;
ClientSocket1->Socket->SendText(Data);
Memo1->Lines->Add(Data);
Edit1->Text="";}
}
else
ShowMessage("錯誤!!! 沒有選擇發送的主機名");
}
}
//---------------------------------------------------------------------------
//在網絡中搜索服務器端時產生的事件
void __fastcall TForm1::ClientSocket1Lookup(TObject *Sender,
TCustomWinSocket *Socket)
{ //定義mouse的類型
Form1->Cursor=crHourGlass ;
Edit1->Cursor=crHourGlass;
Memo1->Cursor=crHourGlass;
}
//選擇發向數據的主機名
void __fastcall TForm1::TreeView1Change(TObject *Sender, TTreeNode *Node)
{
Edit2->Text=TreeView1->Selected->TreeView->Selected->Text;
StatusBar1->SimpleText="連接到:" TreeView1->Selected->TreeView->Selected->Text;
} //監聽
void __fastcall TForm1::BtnlistenClick(TObject *Sender)
{
ClientSocket1->Active=false;
ServerSocket1->Active=true;
StatusBar1->SimpleText="正在監聽...";
Form1->Caption =Form1->Caption "--服務器端";
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;
Form1->Caption =Form1->Caption "--客戶端";}
}
}
//斷開
void __fastcall TForm1::BtndisconnectClick(TObject *Sender)
{
//按下斷開
ClientSocket1->Close();
}
//---------------------------------------------------------------------------
//退出
void __fastcall TForm1::BtnExitClick(TObject *Sender)
{
ClientSocket1->Close();
ServerSocket1->Close();
Form1->Close();
}
//編寫完程序代碼後,就要對源程序進行編譯了,編譯方法如下: 1.在菜單 project \ options 下,選擇Packages 頁,去掉Build with runtime packages 項的勾, 然後選擇Linker 頁,去掉 Use dynamic RTL 的勾,然後按“確定”按鈕。 2.在菜單 project \ options 下,選擇 Compiler 頁,按下 Release 按鈕,然後按“確定”按鈕。 3.在菜單 Run \ Run (或F9) 進行編譯就行。 用這種方法編譯的可執行文件容量比較小, 而且可以在沒有安裝C 的系統中運行。在運行時 可單機也可多機操作,但必須要有一個主機打開程序的“監聽”,其它客戶機進行連接就行了。 快快來下載,編寫自己的聊天程序吧! 時間就是金錢---[ 發問前請先找找舊文章] 發表人 - axsoft 於 2002/07/25 10:12:18
系統時間:2024-04-20 2:08:20
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!