ServerSocket和ClientSocket控件通信的實例

在網絡編程中,WinSocket   API編程是最基本,也是最麻煩的地方(說句不怕影響形象的話,我對此就是隻知其一;不知其二)。可是,若是你是使用C++Builder做爲編程平臺,你就偷着樂吧,有了BCB,菜鳥變高手!:-) 


在BCB中,TServerSocket和TClientSocket涵蓋了基本的WinSocket編程,其中TServerSocket做爲服務器方使用,TClientSocket做爲客戶端使用,這兩個組件自己並不提供Socket鏈接,可是他們都有一個Socket屬性,這個屬性才提供了Socket鏈接。下面就先向你們介紹一下這兩個組件經常使用的方法屬性,而後在經過一個例子來看看這兩個組件的使用。 
1)TServerSocket 


名稱             類型                           說明 
Socket           TServerWinSocket               最重要的屬性,提供Socket鏈接,事實上發送/接收數據都要靠這個屬性. 
Port             int                            要監聽的端口,若是在Service屬性中指定了服務類型,此屬性將被忽略. 
Service          AnsiString                     提供的服務,如HTTP、FTP等,若是在這裏指定了服務類型, 
                                                Port將被忽略,由於各類服務都有特定的端口,如FTP:2一、HTTP:80 
ServerType       TServerType                    設置與客戶鏈接的方式,取值爲兩個枚舉常量stNonBlocking和 
                                                stThreadBlocking,stNonBlocking表示用非阻塞方式鏈接每個客戶 
                                                每一個鏈接都在一個單獨的線程中處理。並用OnClientRead()和 
                                                OnClientWrite()通知服務器端的Socker進行讀寫。stThreadBlocking 
                                                表示以阻塞方式鏈接客戶,即以主動查詢的方式可客戶鏈接。 
Active           bool                           激活服務,至關於調用Open()方法。 
OnAccept事件當有客戶請求鏈接時觸發 
OnClientRead事件通知服務器去讀取有關信息。OnClientWrite與此相似。 




2)TClientSocket 
名稱              類型                          說明 
Socket            TClientWinSocket              最重要的屬性,提供Socket鏈接,事實上發送/接收數據都要靠這個屬性. 
Active            bool                          激活服務,至關於調用Open()方法。 
Address           AnsiString                    服務器的IP地址,如202.98.35.14 
ClientType        TClientType                   與服務器鏈接方式,取值爲兩個枚舉常量ctNonBlocking,tBlocking。 
                                                ctNonBlocking表示非阻塞方式,ctBlocking表示阻塞方式,詳見上例。 
Host              AnsiString                    要鏈接的主機名,如www.cpcw.com 
Port              int                           要監聽的端口,TClientSocket,此屬性將被忽略. 
Service           AnsiString                    提供的服務,如HTTP、FTP等,若是在這裏指定了服務類型, 
OnConnect事件當鏈接時發生,OnConnecting、OnDisConnect與此相似 
OnRead事件通知客戶機去讀取有關信息。OnWrite與此相似。 


TServerSocket和TClientSocket只提供基本的服務器/客戶機的鏈接,真正提供數據傳輸的是它們都有的屬性Socket,它的類型分別是TServerWinSocket和TClientWinSocket,而TServerWinSocket和TClientWinSocket的父類都是TCustomWinSocket,下面咱們就來看看TServerWinSocket和TClientWinSocket經常使用的屬性和方法。   


共同的屬性方法(來源於TCustomWinSocket) 
名稱                類型                   說明 
Connected           bool                   檢查是否鏈接成功 
LocalAddress        AnsiString             本地IP地址,與此相似LocalHost:本機域名,LocalPort:本機端口 
RemoteAddress       AnsiString             另外一端的IP地址,與此相似RemoteHost:另外一端域名, RemotePort:另外一端端口
SocketHandle        int                    只讀,返回Socket對象的Windows句柄,調用WinSocket   API函數會用到它。 
Handle              HWND                   Socket可以接受到的異步事件都是以Windows消息的形式發送給此句柄的。 


Close()方法做爲服務器,關閉全部鏈接;做爲客戶機,關閉本身與服務器的鏈接 
SendText(AnsiString)方法發送一個字符串, 
SendBuf(void*   buff,int   count)發送緩衝區buff中的count個字節,返回實際發送的字節數 
SendStream(TStream*   AStream)發送一個流到Socket中。 
ReceiveText()從Socket中讀取並返回一個字符串。 
ReceiveLength()從Socket讀取數據需多少字節的緩衝區。 
ReceiveBuf(void*   buff,int   count)從Socket中讀取count字節的數據到buff。 


TClientWinSocket 
TClientWinSocket只增長了一個ClientType屬性, 
用於決定與服務器的鏈接類型(參見TClientSocket-> ClientType)。 


TServerWinSocket 
名稱                     類型說明 
ServerType             服務類型,參見TServerSocket-> ServerType。 
ActiveConnection         int只讀,返回當前活動的鏈接數。 
Connection               TCustomWinSocket數組,索引n表示第n+1個鏈接,如Connection[0]表示第一個鏈接。


有了這些知識,咱們就能夠完成一些基本的WinSocket編程了,下面就結合一個簡單的閒聊程序來看看具體的應用。 
首先在窗體上放置如下VCL組件,並修改相應屬性: 
類型                  Name                   屬性                 Caption/Text 
TCheckBox             ckListen               監聽當選取時,本程序做爲服務器 
TCheckBox             ckConnect              鏈接當選取時,本程序做爲客戶機 
TEdit                 edName                 無名氏閒聊時所用的名字。 
TBitBtn               bbtSave&S              保存單擊時保存談話內容 
TBitBtn               bbtClose&C             關閉單擊時關閉此窗口(設置Kind=bkClose) 
TEdit                 edTalk              在此輸入談話內容 
TMemo                 mmTalk              在此顯示談話內容 
TServerSocket         ServerSocket1        做服務器時使用(設置Port=2222) 
TClientSocket         ClientSocket1        做爲客戶時使用(設置Port=2222) 
TSaveDialog           sdTalk               保存文件時的選項(設置DefaultExt= "*.txt ",Filter=文本文件(*.TXT) |*.txt|全部文件(*.*)|*.*)。
TStatusBar            StatusBar1          用於顯示一些提示信息,只要在屬性 "Pannels "中加一欄便可 


程序做爲服務器的設置: 
當單擊 "監聽 "時,若是沒有監聽則開始監聽,在提示欄中顯示 "監聽 ",並把 "鏈接 "這個複選框無效。若是已經監聽,則取消監聽,並使 "鏈接 "這個複選框有效。因此,在ckListen的OnClick事件中加入如下代碼: 
if(ServerSocket1-> Active) 
{   
        ServerSocket1-> Active=false; 
        ckListen-> Checked=false;   
        StatusBar1-> Panels-> Items[0]-> Text= " "; 
}   
else   

        ServerSocket1-> Active=true;   
        ckListen-> Checked=true; 
        ClientSocket1-> Active=false; 
        StatusBar1-> Panels-> Items[0]-> Text= "監聽... "   ; 
}   
ckConnect-> Enabled=!(ckListen-> Checked); 


當有客戶加入時,向全部的客戶發出通知:並在自已的mmTalk加入此消息:因此在ServerSocket1的OnAccept事件中加入以下代碼: 


int   i; 
AnsiString   str1= "服務器消息: "+Socket-> RemoteHost+ "加入 "; 
for(i=0;i <ServerSocket1-> Socket-> ActiveConnections;i++) 
ServerSocket1-> Socket-> Connections[i]-> SendText( "服務器消息: "+Socket-> RemoteHost+ "加入 "); 
StatusBar1-> Panels-> Items[0]-> Text=str1; 
mmTalk-> Lines-> Add(str1); 


當客戶機通知服務器讀信息時,首先讀出字符串,而後把讀到的字符串發送到每一臺鏈接的客戶,並在自已的mmTalk中加入客戶發送來的字符串。因此,在TServerSocket的OnClientRead事件中加入如下代碼: 


AnsiString   str1=Socket-> ReceiveText(); 
mmTalk-> Lines-> Add(str1); 
int   i; 
for(i=0;i <ServerSocket1-> Socket-> ActiveConnections;i++) 
ServerSocket1-> Socket-> Connections[i]-> SendText(str1); 


程序做爲客戶機的設置: 
當單擊 "鏈接 "時,若是還未鏈接,則詢問要鏈接的主機,而後鏈接之,屏蔽 "監聽 ";若是已經鏈接,則斷開鏈接。 "監聽 "使能。因此,在ckConnect的OnClick事件中加入如下代碼: 


if(ClientSocket1-> Active) 

    ClientSocket1-> Active=false; 
    ckConnect-> Checked   =false; 

else 

    AnsiString   Server= "localhost "; 
    if(InputQuery( "鏈接 ", "請輸入要鏈接的主機地址: ",Server)) 
    { 
        ClientSocket1-> Host=Server; 
        ClientSocket1-> Active=true; 
        ckConnect-> Checked   =true; 
    } 

    ckListen-> Enabled=   !(ckConnect-> Checked); 


當鏈接服務器成功時,在狀態欄中顯示此信息,因此,在ClientSocket1的ClientSocket1Connect中加入: 


StatusBar1-> Panels-> Items[0]-> Text   = "鏈接到主機: "+Socket-> RemoteHost; 
當服務器發送字符串來時,把它加入mmTalk中,但若是本字符串就是自已發送的(由於服務器會把收到的消息發給每一客戶),爲條信息就是重複的,因此,要比較mmTalk中最後兩條信息是否相同,若是相同,則刪除重複信息。代碼以下: 


mmTalk-> Lines-> Add(Socket-> ReceiveText()); 
int   i=mmTalk-> Lines-> Count-1; 
if(mmTalk-> Lines-> Strings[i]==mmTalk-> Lines-> Strings[i-1]) 
mmTalk-> Lines-> Delete(i); 






公用部分   
當在edTalk輸入交談內容,按回車鍵表示輸入完成,此時把交談內容發送出去並清除edTalk的內容。在發送信息時,要看本程序是做爲服務器仍是客戶機,若是是服務器則把信息發送到每個客戶;若是是做爲客戶則把信息發送到服務器。代碼以下: 


if(Key==13) 

    mmTalk-> Lines-> Add(edName-> Text+ ": "+edTalk-> Text); 
    if(ckListen-> Enabled&&ckConnect-> Enabled==false) 
        // "監聽 "有效, "鏈接 "無效。表示是服務器 
    { 
        int   i; 
        for(i=0;i <ServerSocket1-> Socket-> ActiveConnections;i++) 
        ServerSocket1-> Socket-> Connections[i]-> SendText(edName-> Text+ ": "+edTalk-> Text); 
    } 
    else 
    { 
        ClientSocket1-> Socket-> SendText(edName-> Text+ ": "+edTalk-> Text); 
    } 
    edTalk-> Text= " "; 



mmTalk的內容不可能永遠增長,因此當它有100行時就清空它,在mmTalk的OnChange事件中檢查: 


        if(mmTalk-> Lines-> Count> =100)mmTalk-> Lines-> Clear(); 
        
固然你也能夠雙擊mmTalk來清空它,在mmTalk的OnDblClick事件中加入: 


        mmTalk-> Lines-> Clear(); 
當你以爲談話的內容頗有意思,你能夠單擊bbtSave打開保存對話框設置保存特性,因此在bbtSave的onClick中加入代碼: 


        if(sdTalk-> Execute()) 
                mmTalk-> Lines-> SaveToFile(sdTalk-> FileName); 


OK,咱們的閒聊程序就完成了,在局域網中試試吧?若是你只有一臺機器,客戶程序在鏈接時服務器時輸入localhost或你機器的名字就能夠了
相關文章
相關標籤/搜索