設計思路
本例包括一個伺服器端程式和一個客戶端程式。客戶端程式可以放到多個計算機上執行,同時與伺服器端進行連線通訊。
本例的重點,一是演示客戶端與伺服器端如何通訊;二是當有多個客戶端同時連線到伺服器端時,伺服器端如何識別每個客戶端,並對請求給出相應的回覆。為了保證一個客戶端斷開連線時不影響其它客戶端與伺服器端的通訊,同時保證伺服器端能夠正確回覆客戶端的請求,在本例中聲明瞭一個記錄型別:
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):
unituServerMain;
interface
uses
Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs,
ScktComp,ToolWin,ComCtrls,ExtCtrls,StdCtrls,Buttons;
const
CMax=10;//客戶端最大連線數
TfrmServerMain=class(TForm)
ServerSocket:TServerSocket;
ControlBar1:TControlBar;
ToolBar1:TToolBar;
tbConnect:TToolButton;
tbClose:TToolButton;
tbDisconnected:TToolButton;
Edit1:TEdit;
Memo1:TMemo;
StatusBar:TStatusBar;
proceduretbConnectClick(Sender:TObject);
proceduretbDisconnectedClick(Sender:TObject);
procedureServerSocketClientRead(Sender:TObject;Socket:TCustomWinSocket);
procedureServerSocketListen(Sender:TObject;Socket:TCustomWinSocket);
procedureServerSocketClientConnect(Sender:TObject;Socket:TCustomWinSocket);
procedureServerSocketClientDisconnect(Sender:TObject;Socket:TCustomWinSocket);
proceduretbCloseClick(Sender:TObject);
procedureFormCreate(Sender:TObject);
procedureFormClose(Sender:TObject;varAction:TCloseAction);
procedureServerSocketGetSocket(Sender:TObject;Socket:Integer;
varClientSocket:TServerClientWinSocket);
procedureServerSocketClientError(Sender:TObject;
Socket:TCustomWinSocket;ErrorEvent:TErrorEvent;
varErrorCode:Integer);
private
{
Privatedeclarations
}
public
Publicdeclarations
session:array[0..CMax]ofclient_record;//客戶端連線陣列
Sessions:integer;//客戶端連線數
var
frmServerMain:TfrmServerMain;
implementation
{$R*.DFM}
//開啟套接字連線,並使套接字進入監聽狀態
procedureTfrmServerMain.tbConnectClick(Sender:TObject);
begin
ServerSocket.Open;
//關閉套接字連線,不再監聽客戶端的請求
procedureTfrmServerMain.tbDisconnectedClick(Sender:TObject);
ServerSocket.Close;
StatusBar.Panels[0].Text:="伺服器套接字連線已經關閉,無法接受客戶端的連線請求.";
//從客戶端讀取資訊
procedureTfrmServerMain.ServerSocketClientRead(Sender:TObject;Socket:TCustomWinSocket);
i:integer;
//將從客戶端讀取的資訊新增到Memo1中
Memo1.Lines.Add(Socket.ReceiveText);
fori:=0tosessionsdo
//取得匹配的客戶端
ifsession[i].CHandle=Socket.SocketHandlethen
session[i].CSocket.SendText("回覆客戶端"+session[i].CAddress+"==>"+Edit1.Text);
//伺服器端套接字進入監聽狀態,以便監聽客戶端的連線
procedureTfrmServerMain.ServerSocketListen(Sender:TObject;Socket:TCustomWinSocket);
StatusBar.Panels[0].Text:="等待客戶端連線...";
//當客戶端連線到伺服器端以後
procedureTfrmServerMain.ServerSocketClientConnect(Sender:TObject;
Socket:TCustomWinSocket);
i,j:integer;
j:=-1;
//在原有的客戶端連線陣列中有中斷的客戶端連線
ifnotsession[i].CUsedthen
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;
j:=i;
ifj=sessionsthen
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;
StatusBar.Panels[0].Text:="客戶端"+Socket.RemoteHost+"已經連線";
//當客戶端斷開連線時
procedureTfrmServerMain.ServerSocketClientDisconnect(Sender:TObject;
session[i].CHandle:=0;
session[i].CUsed:=False;
StatusBar.Panels[0].Text:="客戶端"+Socket.RemoteHost+"已經斷開";
//關閉視窗
procedureTfrmServerMain.tbCloseClick(Sender:TObject);
Close;
procedureTfrmServerMain.FormCreate(Sender:TObject);
sessions:=0;
procedureTfrmServerMain.FormClose(Sender:TObject;varAction:TCloseAction);
//當客戶端正在與伺服器端連線時
procedureTfrmServerMain.ServerSocketGetSocket(Sender:TObject;
Socket:Integer;varClientSocket:TServerClientWinSocket);
StatusBar.Panels[0].Text:="客戶端正在連線...";
//客戶端發生錯誤
procedureTfrmServerMain.ServerSocketClientError(Sender:TObject;
StatusBar.Panels[0].Text:="客戶端"+Socket.RemoteHost+"發生錯誤!";
ErrorCode:=0;
end.
設計思路
本例包括一個伺服器端程式和一個客戶端程式。客戶端程式可以放到多個計算機上執行,同時與伺服器端進行連線通訊。
本例的重點,一是演示客戶端與伺服器端如何通訊;二是當有多個客戶端同時連線到伺服器端時,伺服器端如何識別每個客戶端,並對請求給出相應的回覆。為了保證一個客戶端斷開連線時不影響其它客戶端與伺服器端的通訊,同時保證伺服器端能夠正確回覆客戶端的請求,在本例中聲明瞭一個記錄型別:
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):
unituServerMain;
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;
proceduretbConnectClick(Sender:TObject);
proceduretbDisconnectedClick(Sender:TObject);
procedureServerSocketClientRead(Sender:TObject;Socket:TCustomWinSocket);
procedureServerSocketListen(Sender:TObject;Socket:TCustomWinSocket);
procedureServerSocketClientConnect(Sender:TObject;Socket:TCustomWinSocket);
procedureServerSocketClientDisconnect(Sender:TObject;Socket:TCustomWinSocket);
proceduretbCloseClick(Sender:TObject);
procedureFormCreate(Sender:TObject);
procedureFormClose(Sender:TObject;varAction:TCloseAction);
procedureServerSocketGetSocket(Sender:TObject;Socket:Integer;
varClientSocket:TServerClientWinSocket);
procedureServerSocketClientError(Sender:TObject;
Socket:TCustomWinSocket;ErrorEvent:TErrorEvent;
varErrorCode:Integer);
private
{
Privatedeclarations
}
public
{
Publicdeclarations
}
session:array[0..CMax]ofclient_record;//客戶端連線陣列
Sessions:integer;//客戶端連線數
end;
var
frmServerMain:TfrmServerMain;
implementation
{$R*.DFM}
//開啟套接字連線,並使套接字進入監聽狀態
procedureTfrmServerMain.tbConnectClick(Sender:TObject);
begin
ServerSocket.Open;
end;
//關閉套接字連線,不再監聽客戶端的請求
procedureTfrmServerMain.tbDisconnectedClick(Sender:TObject);
begin
ServerSocket.Close;
StatusBar.Panels[0].Text:="伺服器套接字連線已經關閉,無法接受客戶端的連線請求.";
end;
//從客戶端讀取資訊
procedureTfrmServerMain.ServerSocketClientRead(Sender:TObject;Socket:TCustomWinSocket);
var
i:integer;
begin
//將從客戶端讀取的資訊新增到Memo1中
Memo1.Lines.Add(Socket.ReceiveText);
fori:=0tosessionsdo
begin
//取得匹配的客戶端
ifsession[i].CHandle=Socket.SocketHandlethen
begin
session[i].CSocket.SendText("回覆客戶端"+session[i].CAddress+"==>"+Edit1.Text);
end;
end;
end;
//伺服器端套接字進入監聽狀態,以便監聽客戶端的連線
procedureTfrmServerMain.ServerSocketListen(Sender:TObject;Socket:TCustomWinSocket);
begin
StatusBar.Panels[0].Text:="等待客戶端連線...";
end;
//當客戶端連線到伺服器端以後
procedureTfrmServerMain.ServerSocketClientConnect(Sender:TObject;
Socket:TCustomWinSocket);
var
i,j:integer;
begin
j:=-1;
fori:=0tosessionsdo
begin
//在原有的客戶端連線陣列中有中斷的客戶端連線
ifnotsession[i].CUsedthen
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;
ifj=sessionsthen
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;
//當客戶端斷開連線時
procedureTfrmServerMain.ServerSocketClientDisconnect(Sender:TObject;
Socket:TCustomWinSocket);
var
i:integer;
begin
fori:=0tosessionsdo
begin
ifsession[i].CHandle=Socket.SocketHandlethen
begin
session[i].CHandle:=0;
session[i].CUsed:=False;
Break;
end;
end;
StatusBar.Panels[0].Text:="客戶端"+Socket.RemoteHost+"已經斷開";
end;
//關閉視窗
procedureTfrmServerMain.tbCloseClick(Sender:TObject);
begin
Close;
end;
procedureTfrmServerMain.FormCreate(Sender:TObject);
begin
sessions:=0;
end;
procedureTfrmServerMain.FormClose(Sender:TObject;varAction:TCloseAction);
begin
ServerSocket.Close;
end;
//當客戶端正在與伺服器端連線時
procedureTfrmServerMain.ServerSocketGetSocket(Sender:TObject;
Socket:Integer;varClientSocket:TServerClientWinSocket);
begin
StatusBar.Panels[0].Text:="客戶端正在連線...";
end;
//客戶端發生錯誤
procedureTfrmServerMain.ServerSocketClientError(Sender:TObject;
Socket:TCustomWinSocket;ErrorEvent:TErrorEvent;
varErrorCode:Integer);
begin
StatusBar.Panels[0].Text:="客戶端"+Socket.RemoteHost+"發生錯誤!";
ErrorCode:=0;
end;
end.