笔者在工作中遇到对局域网中各工作站与服务器之间进行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的属性设置简单说明
1ServerSocket的属性
· Port是通信的端口必须设置在本例中设置为
· ServerTypt服务器端读写信息类型设置为stNonBlocking表示异步读写信息本例中采用这种方式
· ThreadCacheSize客户端的最大连接数就是服务器端最多允许多少客户端同时连接本例采用默认值
其它属性采用默认设置即可
2ClientSocket的属性
· Port是通信的端口必须与服务器端的设置相同在本例中设置为
· ClientType客户端读写信息类型应该与服务器端的设置相同为stNonBlocking表示异步读写信息
· Host客户端要连接的服务器的IP地址必须设置当然也可以在代码中动态设置
其它属性采用默认设置即可
三程序源代码
1服务器端源码(uServerMainpas)
unit uServerMain;
interface
uses
Windows Messages SysUtils Classes Graphics Controls Forms Dialogs
ScktComp ToolWin ComCtrls ExtCtrls StdCtrls Buttons;
const
CMax=; //客户端最大连接数
type
client_record=record
CHandle: integer; //客户端套接字句柄
CSocket:TCustomWinSocket; //客户端套接字
CName:string; //客户端计算机名称
CAddress:string; //客户端计算机IP地址
CUsed: boolean; //客户端联机标志
end;
type
TfrmServerMain = class(TForm)
ServerSocket: TServerSocket;
ControlBar: TControlBar;
ToolBar: TToolBar;
tbConnect: TToolButton;
tbClose: TToolButton;
tbDisconnected: TToolButton;
Edit: TEdit;
Memo: 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[CMax] of client_record; //客户端连接数组
Sessions: integer; //客户端连接数
end;
var
frmServerMain: TfrmServerMain;
implementation
{$R *DFM}
//打开套接字连接并使套接字进入监听状态
procedure TfrmServerMaintbConnectClick(Sender: TObject);
begin
ServerSocketOpen ;
end;
//关闭套接字连接不再监听客户端的请求
procedure TfrmServerMaintbDisconnectedClick(Sender: TObject);
begin
ServerSocketClose;
StatusBarPanels[]Text :=服务器套接字连接已经关闭无法接受客户端的连接请求;
end;
//从客户端读取信息
procedure TfrmServerMainServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
i:integer;
begin
//将从客户端读取的信息添加到Memo中
MemoLinesAdd(SocketReceiveText);
for i:= to sessions do
begin
//取得匹配的客户端
if session[i]CHandle = SocketSocketHandle then
begin
session[i]CSocketSendText(回复客户端+session[i]CAddress+ ==> +EditText);
end;
end;
end;
//服务器端套接字进入监听状态以便监听客户端的连接
procedure TfrmServerMainServerSocketListen(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBarPanels[]Text :=等待客户端连接;
end;
//当客户端连接到服务器端以后
procedure TfrmServerMainServerSocketClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
var
ij:integer;
begin
j:=;
for i:= to sessions do
begin
//在原有的客户端连接数组中有中断的客户端连接
if not session[i]CUsed then
begin
session[i]CHandle := SocketSocketHandle ;//客户端套接字句柄
session[i]CSocket := Socket; //客户端套接字
session[i]CName := SocketRemoteHost ; //客户端计算机名称
session[i]CAddress := SocketRemoteAddress ;//客户端计算机IP
session[i]CUsed := True; //连接数组当前位置已经占用
Break;
end;
j:=i;
end;
if j=sessions then
begin
inc(sessions);
session[j]CHandle := SocketSocketHandle ;
session[j]CSocket := Socket;
session[j]CName := SocketRemoteHost ;
session[j]CAddress := SocketRemoteAddress ;
session[j]CUsed := True;
end;
StatusBarPanels[]Text := 客户端 +SocketRemoteHost + 已经连接;
end;
//当客户端断开连接时
procedure TfrmServerMainServerSocketClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
var
i:integer;
begin
for i:= to sessions do
begin
if session[i]CHandle =SocketSocketHandle then
begin
session[i]CHandle :=;
session[i]CUsed := False;
Break;
end;
end;
StatusBarPanels[]Text :=客户端 +SocketRemoteHost + 已经断开;
end;
//关闭窗口
procedure TfrmServerMaintbCloseClick(Sender: TObject);
begin
Close;
end;
procedure TfrmServerMainFormCreate(Sender: TObject);
begin
sessions := ;
end;
procedure TfrmServerMainFormClose(Sender: TObject;
var Action: TCloseAction);
begin
ServerSocketClose ;
end;
//当客户端正在与服务器端连接时
procedure TfrmServerMainServerSocketGetSocket(Sender: TObject;
Socket: Integer; var ClientSocket: TServerClientWinSocket);
begin
StatusBarPanels[]Text :=客户端正在连接;
end;
//客户端发生错误
procedure TfrmServerMainServerSocketClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
StatusBarPanels[]Text :=客户端+SocketRemoteHost +发生错误!;
ErrorCode := ;
end;
end
2客户端源码(uClientMainpas)
unit uClientMain;
interface
uses
Windows Messages SysUtils Classes Graphics Controls Forms Dialogs
ScktComp ComCtrls ToolWin ExtCtrls StdCtrls Buttons;
const
SocketHost = ; //服务器端地址
type
TfrmClientMain = class(TForm)
ControlBar: TControlBar;
ToolBar: TToolBar;
tbConnected: TToolButton;
tbSend: TToolButton;
tbClose: TToolButton;
tbDisconnected: TToolButton;
ClientSocket: TClientSocket;
Edit: TEdit;
Memo: 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 TfrmClientMaintbConnectedClick(Sender: TObject);
begin
ClientSocketOpen ;
end;
//关闭套接字连接
procedure TfrmClientMaintbDisconnectedClick(Sender: TObject);
begin
ClientSocketClose;
end;
//接受服务器端的回复
procedure TfrmClientMainClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
MemoLinesAdd(SocketReceiveText);
end;
//发送信息到服务器端
procedure TfrmClientMaintbSendClick(Sender: TObject);
begin
ClientSocketSocketSendText(EditText);
end;
procedure TfrmClientMaintbCloseClick(Sender: TObject);
begin
Close;
end;
//设置要连接的服务器端地址
procedure TfrmClientMainFormShow(Sender: TObject);
begin
ClientSocketHost := SocketHost;
end;
//已经连接到服务器端
procedure TfrmClientMainClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
tbSendEnabled := True;
tbDisconnectedEnabled :=True;
btnSendEnabled := True;
StatusBarPanels[]Text := 已经连接到 + SocketRemoteHost ;
end;
//正在连接到服务器端
procedure TfrmClientMainClientSocketConnecting(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBarPanels[]Text := 正在连接到服务器 ;
end;
//当断开与服务器端的连接时发生
procedure TfrmClientMainClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
tbSendEnabled := False;
btnSendEnabled := False;
tbDisconnectedEnabled := False;
StatusBarPanels[]Text := 已经断开与 + SocketRemoteHost + 的连接;
end;
procedure TfrmClientMainFormClose(Sender: TObject;
var Action: TCloseAction);
begin
ClientSocketClose ;
end;
//当与服务器端的连接发生错误时
procedure TfrmClientMainClientSocketError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
StatusBarPanels[]Text := 与服务器端的连接发生错误;
ErrorCode := ;
end;
end
四小结
上述方法是比较简单的实现方法同时也是相对较容易理解的方法通过这个方法笔者成功实现了局域网内多个客户端与服务器端进行Socket通信的功能同时可以保证一个客户端的连接通信或是断开都不影响其它客户端的正常通信
五附录
服务器端窗体和客户端窗体及组件的属性设置队应的DFM文件
uServerMainpas对应的DFM文件(uServerMaindfm)
object frmServerMain: TfrmServerMain
Left =
Top =
BorderIcons = [biSystemMenu biMinimize]
BorderStyle = bsSingle
Caption = ServerSocket
ClientHeight =
ClientWidth =
Color = clBtnFace
FontCharset = DEFAULT_CHARSET
FontColor = clWindowText
FontHeight =
FontName = MS Sans Serif
FontStyle = []
OldCreateOrder = False
OnClose = FormClose
OnCreate = FormCreate
PixelsPerInch =
TextHeight =
object ControlBar: TControlBar
Left =
Top =
Width =
Height =
Align = alTop
AutoSize = True
TabOrder =
object ToolBar: TToolBar
Left =
Top =
Width =
Height =
ButtonHeight =
ButtonWidth =
Caption = ToolBar
EdgeInner = esNone
EdgeOuter = esNone
Flat = True
ShowCaptions = True
TabOrder =
object tbConnect: TToolButton
Left =
Top =
Caption = 连接
ImageIndex =
OnClick = tbConnectClick
end
object tbDisconnected: TToolButton
Left =
Top =
Caption = 断开
ImageIndex =
OnClick = tbDisconnectedClick
end
object tbClose: TToolButton
Left =
Top =
Caption = 关闭
ImageIndex =
OnClick = tbCloseClick
end
end
end
object Edit: TEdit
Left =
Top =
Width =
Height =
TabOrder =
Text = 你好!
end
object Memo: TMemo
Left =
Top =
Width =
Height =
Align = alTop
TabOrder =
end
object StatusBar: TStatusBar
Left =
Top =
Width =
Height =
Panels = <
item
Width =
end>
SimplePanel = False
end
object ServerSocket: TServerSocket
Active = False
Port =
ServerType = stNonBlocking
OnListen = ServerSocketListen
OnGetSocket = ServerSocketGetSocket
OnClientConnect = ServerSocketClientConnect
OnClientDisconnect = ServerSocketClientDisconnect
OnClientRead = ServerSocketClientRead
OnClientError = ServerSocketClientError
Left =
end
end
uClientMainpas对应的DFM文件(uClientMaindfm)
object frmClientMain: TfrmClientMain
Left =
Top =
BorderIcons = [biSystemMenu biMinimize]
BorderStyle = bsSingle
Caption = ClientSocket
ClientHeight =
ClientWidth =
Color = clBtnFace
FontCharset = DEFAULT_CHARSET
FontColor = clWindowText
FontHeight =
FontName = MS Sans Serif
FontStyle = []
OldCreateOrder = False
Position = poScreenCenter
OnClose = FormClose
OnShow = FormShow
PixelsPerInch =
TextHeight =
object ControlBar: TControlBar
Left =
Top =
Width =
Height =
Align = alTop
AutoSize = True
TabOrder =
object ToolBar: TToolBar
Left =
Top =
Width =
Height =
ButtonHeight =
ButtonWidth =
Caption = ToolBar
EdgeInner = esNone
EdgeOuter = esNone
Flat = True
ShowCaptions = True
TabOrder =
object tbConnected: TToolButton
Left =
Top =
Caption = 连接
ImageIndex =
OnClick = tbConnectedClick
end
object tbSend: TToolButton
Left =
Top =
Caption = 发送
Enabled = False
ImageIndex =
OnClick = tbSendClick
end
object tbDisconnected: TToolButton
Left =
Top =
Caption = 断开
Enabled = False
ImageIndex =
OnClick = tbDisconnectedClick
end
object tbClose: TToolButton
Left =
Top =
Caption = 退出
ImageIndex =
OnClick = tbCloseClick
end
end
end
object Edit: TEdit
Left =
Top =
Width =
Height =
TabOrder =
Text = 问候
end
object Memo: TMemo
Left =
Top =
Width =
Height =
Align = alTop
TabOrder =
end
object StatusBar: TStatusBar
Left =
Top =
Width =
Height =
Panels = <
item
Width =
end>
SimplePanel = False
end
object btnSend: TBitBtn
Left =
Top =
Width =
Height =
Caption = 发送
Enabled = False
TabOrder =
OnClick = tbSendClick
end
object ClientSocket: TClientSocket
Active = False
ClientType = ctNonBlocking
Port =
OnConnecting = ClientSocketConnecting
OnConnect = ClientSocketConnect
OnDisconnect = ClientSocketDisconnect
OnRead = ClientSocketRead
OnError = ClientSocketError
Left =
end
end