利用Delphi編寫Socket通信程序2

 筆者在工作中遇到對局域網中各工作站與服務器之間進行Socket通信的問題。現在將本人總結出來的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):
  
  
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. 

  
· 客戶端源碼(uClientMain.pas):
   
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.

  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章