NO IMAGE

Delphi,網路通訊,TserverSocket,TclientSocket

現在將本人總結出來的TServerSocket和TClientSocket兩個元件的基本用法寫出來,希望與您分享。

ClientSocket元件為客戶端元件。它是通訊的請求方,也就是說,它是主動地與伺服器端建立連線。

ServerSocket元件為伺服器端元件。它是通訊的響應方,也就是說,它的動作是監聽以及被動接受客戶端的連線請
求,並對請求進行回覆。

ServerSocket元件可以同時接受一個或多個ClientSocket元件的連線請求,並與每個ClientSocket元件建立單獨的
連線,進行單獨的通訊。因此,一個伺服器端可以為多個客戶端服務。

設計思路
本例包括一個伺服器端程式和一個客戶端程式。客戶端程式可以放到多個計算機上執行,同時與伺服器端進行連線
通訊。
本例的重點,

一是演示客戶端與伺服器端如何通訊;
二是當有多個客戶端同時連線到伺服器端時,伺服器端如何識別每個客戶端,並對請求給出相應的回覆。為了保證一個客戶端斷開連線時不影響其它客戶端與伺服器端的通訊,
同時保證伺服器端能夠正確回覆客戶端的請求,在本例中宣告瞭一個記錄型別:
type
client_record=record
CHandle: integer; //客戶端套接字控制代碼
CSocket:TCustomWinSocket; //客戶端套接字
CName:string; //客戶端計算機名稱
CAddress:string; //客戶端計算機IP地址
CUsed: boolean; //客戶端聯機標誌
end;
利用這個記錄型別資料儲存客戶端的資訊,同時儲存當前客戶端的連線狀態。其中,
CHandle儲存客戶端套接字控制代碼,以便準確定位每個與伺服器端保持連線的客戶端;
Csocket儲存客戶端套接字,通過它可以對客戶端進行回覆。

Cused記錄當前客戶端是否與伺服器端保持連線。

下面對元件ServerSocket和ClientSocket的屬性設定簡單說明。

ServerSocket的屬性:

· Port,是通訊的埠,必須設定。在本例中設定為1025;

· ServerTypt,伺服器端讀寫資訊型別,設定為stNonBlocking表示非同步讀寫資訊,本例中採用這種方式。

· ThreadCacheSize,客戶端的最大連線數,就是伺服器端最多允許多少客戶端同時連線。本例採用預設值10。

其它屬性採用預設設定即可。

ClientSocket的屬性:

· Port,是通訊的埠,必須與伺服器端的設定相同。在本例中設定為1025;

· ClientType,客戶端讀寫資訊型別,應該與伺服器端的設定相同,為stNonBlocking表示非同步讀寫資訊。

· Host,客戶端要連線的伺服器的IP地址。必須設定,當然也可以在程式碼中動態設定。

其它屬性採用預設設定即可。

程式原始碼:

· 伺服器端原始碼(uServerMain.pas):

<span style="font-size:18px;">unit uServerMain;  
interface  
uses  
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,  
ScktComp, ToolWin, ComCtrls, ExtCtrls, StdCtrls, Buttons;  
const  
CMax=10; //客戶端最大連線數  
type  
client_record=record  
CHandle: integer; //客戶端套接字控制代碼  
CSocket:TCustomWinSocket; //客戶端套接字  
CName:string; //客戶端計算機名稱  
CAddress:string; //客戶端計算機IP地址  
CUsed: boolean; //客戶端聯機標誌  
end;  
type  
TfrmServerMain = class(TForm)  
ServerSocket: TServerSocket;  
ControlBar1: TControlBar;  
ToolBar1: TToolBar;  
tbConnect: TToolButton;  
tbClose: TToolButton;  
tbDisconnected: TToolButton;  
Edit1: TEdit;  
Memo1: TMemo;  
StatusBar: TStatusBar;  
procedure tbConnectClick(Sender: TObject);  
procedure tbDisconnectedClick(Sender: TObject);  
procedure ServerSocketClientRead(Sender: TObject;  
Socket: TCustomWinSocket);  
procedure ServerSocketListen(Sender: TObject;  
Socket: TCustomWinSocket);  
procedure ServerSocketClientConnect(Sender: TObject;  
Socket: TCustomWinSocket);  
procedure ServerSocketClientDisconnect(Sender: TObject;  
Socket: TCustomWinSocket);  
procedure tbCloseClick(Sender: TObject);  
procedure FormCreate(Sender: TObject);  
procedure FormClose(Sender: TObject; var Action: TCloseAction);  
procedure ServerSocketGetSocket(Sender: TObject; Socket: Integer;  
var ClientSocket: TServerClientWinSocket);  
procedure ServerSocketClientError(Sender: TObject;  
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;  
var ErrorCode: Integer);  
private  
{ Private declarations }  
public  
{ Public declarations }  
session: array[0..CMax] of client_record; //客戶端連線陣列  
Sessions: integer; //客戶端連線數  
end;  
var  
frmServerMain: TfrmServerMain;  
implementation  
{$R *.DFM}  
//開啟套接字連線,並使套接字進入監聽狀態  
procedure TfrmServerMain.tbConnectClick(Sender: TObject);  
begin  
ServerSocket.Open ;  
end;  
//關閉套接字連線,不再監聽客戶端的請求  
procedure TfrmServerMain.tbDisconnectedClick(Sender: TObject);  
begin  
ServerSocket.Close;  
StatusBar.Panels[0].Text :=伺服器套接字連線已經關閉,無法接受客戶端的連線請求.;  
end;  
//從客戶端讀取資訊  
procedure TfrmServerMain.ServerSocketClientRead(Sender: TObject;  
Socket: TCustomWinSocket);  
var  
i:integer;  
begin  
//將從客戶端讀取的資訊新增到Memo1中  
Memo1.Lines.Add(Socket.ReceiveText);  
for i:=0 to sessions do  
begin  
//取得匹配的客戶端  
if session[i].CHandle = Socket.SocketHandle then  
begin  
session[i].CSocket.SendText(回覆客戶端 session[i].CAddress  ==>  Edit1.Text);  
end;  
end;  
end;  
//伺服器端套接字進入監聽狀態,以便監聽客戶端的連線  
procedure TfrmServerMain.ServerSocketListen(Sender: TObject;  
Socket: TCustomWinSocket);  
begin  
StatusBar.Panels[0].Text :=等待客戶端連線...;  
end;  
//當客戶端連線到伺服器端以後  
procedure TfrmServerMain.ServerSocketClientConnect(Sender: TObject;  
Socket: TCustomWinSocket);  
var  
i,j:integer;  
begin  
j:=-1;  
for i:=0 to sessions do  
begin  
//在原有的客戶端連線陣列中有中斷的客戶端連線  
if not session[i].CUsed then  
begin  
session[i].CHandle := Socket.SocketHandle ;//客戶端套接字控制代碼  
session[i].CSocket := Socket; //客戶端套接字  
session[i].CName := Socket.RemoteHost ; //客戶端計算機名稱  
session[i].CAddress := Socket.RemoteAddress ;//客戶端計算機IP  
session[i].CUsed := True; //連線陣列當前位置已經佔用  
Break;  
end;  
j:=i;  
end;  
if j=sessions then  
begin  
inc(sessions);  
session[j].CHandle := Socket.SocketHandle ;  
session[j].CSocket := Socket;  
session[j].CName := Socket.RemoteHost ;  
session[j].CAddress := Socket.RemoteAddress ;  
session[j].CUsed := True;  
end;  
StatusBar.Panels[0].Text := 客戶端  Socket.RemoteHost   已經連線;  
end;  
//當客戶端斷開連線時  
procedure TfrmServerMain.ServerSocketClientDisconnect(Sender: TObject;  
Socket: TCustomWinSocket);  
var  
i:integer;  
begin  
for i:=0 to sessions do  
begin  
if session[i].CHandle =Socket.SocketHandle then  
begin  
session[i].CHandle :=0;  
session[i].CUsed := False;  
Break;  
end;  
end;  
StatusBar.Panels[0].Text :=客戶端  Socket.RemoteHost   已經斷開;  
end;  
//關閉視窗  
procedure TfrmServerMain.tbCloseClick(Sender: TObject);  
begin  
Close;  
end;  
procedure TfrmServerMain.FormCreate(Sender: TObject);  
begin  
sessions := 0;  
end;  
procedure TfrmServerMain.FormClose(Sender: TObject;  
var Action: TCloseAction);  
begin  
ServerSocket.Close ;  
end;  
//當客戶端正在與伺服器端連線時  
procedure TfrmServerMain.ServerSocketGetSocket(Sender: TObject;  
Socket: Integer; var ClientSocket: TServerClientWinSocket);  
begin  
StatusBar.Panels[0].Text :=客戶端正在連線...;  
end;  
//客戶端發生錯誤  
procedure TfrmServerMain.ServerSocketClientError(Sender: TObject;  
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;  
var ErrorCode: Integer);  
begin  
StatusBar.Panels[0].Text :=客戶端 Socket.RemoteHost  發生錯誤!;  
ErrorCode := 0;  
end;  
end.</span> 

· 客戶端原始碼(uClientMain.pas):

<span style="font-size:12px;color:#000000;"><span style="font-size:18px;">unit uClientMain;  
interface  
uses  
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,  
ScktComp, ComCtrls, ToolWin, ExtCtrls, StdCtrls, Buttons;  
const  
SocketHost = 172.16.1.6; //伺服器端地址  
type  
TfrmClientMain = class(TForm)  
ControlBar1: TControlBar;  
ToolBar1: TToolBar;  
tbConnected: TToolButton;  
tbSend: TToolButton;  
tbClose: TToolButton;  
tbDisconnected: TToolButton;  
ClientSocket: TClientSocket;  
Edit1: TEdit;  
Memo1: TMemo;  
StatusBar: TStatusBar;  
btnSend: TBitBtn;  
procedure tbConnectedClick(Sender: TObject);  
procedure tbDisconnectedClick(Sender: TObject);  
procedure ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);  
procedure tbSendClick(Sender: TObject);  
procedure tbCloseClick(Sender: TObject);  
procedure FormShow(Sender: TObject);  
procedure ClientSocketConnect(Sender: TObject;  
Socket: TCustomWinSocket);  
procedure ClientSocketConnecting(Sender: TObject;  
Socket: TCustomWinSocket);  
procedure ClientSocketDisconnect(Sender: TObject;  
Socket: TCustomWinSocket);  
procedure FormClose(Sender: TObject; var Action: TCloseAction);  
procedure ClientSocketError(Sender: TObject; Socket: TCustomWinSocket;  
ErrorEvent: TErrorEvent; var ErrorCode: Integer);  
private  
{ Private declarations }  
public  
{ Public declarations }  
end;  
var  
frmClientMain: TfrmClientMain;  
implementation  
{$R *.DFM}  
//開啟套接字連線  
procedure TfrmClientMain.tbConnectedClick(Sender: TObject);  
begin  
ClientSocket.Open ;  
end;  
//關閉套接字連線  
procedure TfrmClientMain.tbDisconnectedClick(Sender: TObject);  
begin  
ClientSocket.Close;  
end;  
//接受伺服器端的回覆  
procedure TfrmClientMain.ClientSocketRead(Sender: TObject;  
Socket: TCustomWinSocket);  
begin  
Memo1.Lines.Add(Socket.ReceiveText);  
end;  
//傳送資訊到伺服器端  
procedure TfrmClientMain.tbSendClick(Sender: TObject);  
begin  
ClientSocket.Socket.SendText(Edit1.Text);   
end;  
procedure TfrmClientMain.tbCloseClick(Sender: TObject);  
begin  
Close;  
end;  
//設定要連線的伺服器端地址  
procedure TfrmClientMain.FormShow(Sender: TObject);  
begin  
ClientSocket.Host := SocketHost;  
end;  
//已經連線到伺服器端  
procedure TfrmClientMain.ClientSocketConnect(Sender: TObject;  
Socket: TCustomWinSocket);  
begin  
tbSend.Enabled := True;  
tbDisconnected.Enabled :=True;  
btnSend.Enabled := True;  
StatusBar.Panels[0].Text := 已經連線到   Socket.RemoteHost ;  
end;  
//正在連線到伺服器端  
procedure TfrmClientMain.ClientSocketConnecting(Sender: TObject;  
Socket: TCustomWinSocket);  
begin  
StatusBar.Panels[0].Text := 正在連線到伺服器... ;  
end;  
//當斷開與伺服器端的連線時發生  
procedure TfrmClientMain.ClientSocketDisconnect(Sender: TObject;  
Socket: TCustomWinSocket);  
begin  
tbSend.Enabled := False;  
btnSend.Enabled := False;  
tbDisconnected.Enabled := False;  
StatusBar.Panels[0].Text := 已經斷開與   Socket.RemoteHost   的連線;  
end;  
procedure TfrmClientMain.FormClose(Sender: TObject;  
var Action: TCloseAction);  
begin  
ClientSocket.Close ;  
end;  
//當與伺服器端的連線發生錯誤時  
procedure TfrmClientMain.ClientSocketError(Sender: TObject;  
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;  
var ErrorCode: Integer);  
begin  
StatusBar.Panels[0].Text := 與伺服器端的連線發生錯誤;  
ErrorCode := 0;  
end;  
end.   </span>

小結

上述方法是比較簡單的實現方法,同時也是相對較容易理解的方法。

通過這個方法,筆者成功實現了區域網內多個
客戶端與伺服器端進行Socket通訊的功能,同時可以保證一個客戶端的連線、通訊或是斷開都不影響其它客戶端的
正常通訊。