最近查找有关winsock方面的资料,来源bmdh
客户端:窗体
unit ClientMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,WinSock,SocketClient;
type
TClientForm = class(TForm)
Label1: TLabel;
Label2: TLabel;
ed_Host: TEdit;
ed_Port: TEdit;
btn_Connect: TButton;
btn_Stop: TButton;
btn_Send: TButton;
ed_Text: TEdit;
Label3: TLabel;
procedure btn_SendClick(Sender: TObject);
procedure btn_StopClick(Sender: TObject);
procedure btn_ConnectClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
Client:TSocket;
FServerClient:TSocketClient;
public
{ Public declarations }
end;
var
ClientForm: TClientForm;
implementation
{$R *.dfm}
procedure TClientForm.btn_ConnectClick(Sender: TObject);
begin
FServerClient:=TSocketClient.Create;
FServerClient.Port:=StrToIntDef(ed_Port.Text,80);
FServerClient.Host:=AnsiString(ed_Host.Text);
if FServerClient.ConnectToServer then
label3.Caption:='连接服务端成功!';
end;
procedure TClientForm.btn_SendClick(Sender: TObject);
begin
FServerClient.SendData(AnsiString(ed_Text.Text));
end;
procedure TClientForm.btn_StopClick(Sender: TObject);
begin
FServerClient.SendData('Exit');
label3.Caption:='断开连接!';
WinSock.closesocket(Client);
end;
procedure TClientForm.FormCreate(Sender: TObject);
var
WSA:TWSAData;
begin
if WSAStartup($0101,WSA)<>0 then
begin
MessageDlg('创建套接字失败!',mtWarning,[mbYes],0);
exit;
end;
end;
end.
客户端掉用单元 clientsocket
unit SocketClient;
interface
uses Windows,Classes,SyncObjs,WinSock,SysUtils;
type
TSocketClient=class
private
//客户端套接字描述
FClientSocket:TSocket;
//服务端地址
FHost:AnsiString;
// 端口
FPort:Integer;
//初始化套接字
function InitSocket:Boolean;
public
constructor Create;overload;
//连接服务器
function ConnectToServer:Boolean;
//发送字符串
procedure SendData(s:AnsiString);
property Host:AnsiString read FHost write FHost;
property Port:Integer read FPort write FPort;
end;
implementation
const
BufLen=1024;
{ TSocketClient }
function TSocketClient.ConnectToServer: Boolean;
var
addr:sockaddr_in;
hostaddr:u_long;
begin
Result:=false;
FClientSocket:=socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
if FClientSocket<>INVALID_SOCKET then
begin
addr.sin_family:=PF_INET;
addr.sin_port:=htons(FPort);
hostaddr:=inet_addr(PAnsiChar(FHost));
if hostaddr=1 then
begin
//showmessage('IP地址错误!');
Exit;
end;
addr.sin_addr.S_addr:=hostaddr;
if connect(FClientSocket,addr,SizeOf(addr))<>0 then
begin
//showmessage('连接服务器超时');
Exit;
end;
end;
Result:=True;
// label.caption:='连接成功!'+Inttostr(Client);
end;
constructor TSocketClient.Create;
begin
InitSocket;
end;
function TSocketClient.InitSocket: Boolean;
var
WSA:TWSAData ;
begin
Result:=true;
if WSAStartup($0101,WSA)<>0 then
begin
Result:=False;
end;
end;
procedure TSocketClient.SendData(s: AnsiString);
var
buffer:array[0..1023] of Byte;
begin
FillChar(buffer,Length(buffer),0);
Move(s[1],buffer,Length(s));
WinSock.send(FClientSocket,buffer,Length(s),0);
end;
end.
服务端:窗体
unit ServerMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,WinSock,SocketServer;
type
TServerForm = class(TForm)
Label3: TLabel;
ed_Port: TEdit;
ListBox1: TListBox;
Label1: TLabel;
btn_Start: TButton;
procedure btn_StartClick(Sender: TObject);
private
{ Private declarations }
Server:TSocket;
FStop:Boolean;
FServerThread:TWorkThread;
FServerSocket:TSocketServer;
procedure DoGetData(const stream:TMemoryStream);
procedure DoClientConnected(const socket:TSocket);
procedure DoClientDisConnected;
public
{ Public declarations }
end;
var
ServerForm: TServerForm;
implementation
{$R *.dfm}
{ TServerForm }
procedure TServerForm.btn_StartClick(Sender: TObject);
begin
FServerSocket:=TSocketServer.Create(Self.Handle,False);
FServerSocket.Port:=StrToIntDef(ed_Port.Text,80);
FServerSocket.OnGetData:=Self.DoGetData;
FServerSocket.OnClientConnected:=Self.DoClientConnected;
if FServerSocket.ListenStart then
FServerSocket.ResumeThread;
end;
procedure TServerForm.DoClientConnected(const socket: TSocket);
begin
ListBox1.Items.Add('用户:'+FServerSocket.IP[FServerSocket.ClientSocketList.count-1]+'已连接!');
Label1.Caption:='客户端连接数:'+inttostr(FServerSocket.ClientCount);
end;
procedure TServerForm.DoClientDisConnected;
begin
ListBox1.Items.Add('用户:'+FserverSocket.IP[FServerSocket.ClientSocketList.count-1]+'已断开!');
Label1.Caption:='客户连接数:'+inttostr(FServerSocket.ClientCount);
end;
procedure TServerForm.DoGetData(const stream: TMemoryStream);
var
i:Integer;
buffer:array [0..1023] of AnsiChar;
s:AnsiString;
begin
FillChar(buffer,Length(buffer),0);
stream.Position:=0;
stream.Read(buffer,Length(buffer));
SetString(s,buffer,Length(buffer)) ;
//exit 退出标志
if Trim(LowerCase(s))='exit' then
begin
if FServerSocket.ClientIndex=-1 then
Exit;
DoClientDisConnected ;
//将退出的套接字的活动状态设置为FALSE
FServerSocket.ItemActived[FServerSocket.ClientIndex]:=false;
exit;
end;
ListBox1.Items.Add(s);
end;
end.
服务端调用单元 Serversocket
unit SocketServer;
interface
uses
Windows,Classes,SyncObjs,WinSock,SysUtils;
type
TGetDataEvent=procedure(const stream:TMemoryStream) of object;
TClientConnected=procedure(const Socket:TSocket) of object;
TWorkThread=class;
TServerItem=class;
TSocketServer=class
FServerSocket:TSocket;
//客户端连接列表
FClientSocketList:TStringList;
FServerItem:TServerItem;
//允许最大连接数
FMaxClientCout:Integer;
//客户端连接数
FClientCount:Integer;
//当前客户端的索引
FClientIndex:Integer;
//调用方的Handle
FCallHandle:HWND;
//接收用的内存流
FRecStream:TMemoryStream;
//接收缓冲区
FRecBuf:array of Byte;
FHost:AnsiString;
FPort:Integer;
FTimeVal:TTimeVal;
//工作线程
FWorkThread:TWorkThread;
//以下是自定义事件
FOnGetData:TGetDataEvent;
FOnClientConnected:TClientConnected;
//初始化套接字
function InitSocket:Boolean;
//从某个客户端套接字中获取数据
procedure GetDataFromClient(Socket:TSocket);
//检测是否有新的客户连接
procedure CheckNewSocket;
procedure SetMaxClientCount(const value:Integer);
function GetMaxClientCount:Integer;
function GetClientCount:Integer;
function GetMaxClient:Integer;
procedure SetMaxClient(const Value:Integer);
protected
procedure DoRevData(stream:TMemoryStream);
procedure DoClientConnected(Socket:TSocket);
//取得某个套接字的IP地址
function GetItemIP(index:Integer):PAnsiChar;
function GetItemActived(index:Integer):Boolean;
procedure SetItemActived(index:Integer;const value:Boolean);
public
//ACallHandel:调用者的句柄,CreageSuPended:线程是否挂起
constructor Create(ACallHandle:HWND;CreateSuspended:Boolean);overload;
//启用监听
function ListenStart:Boolean;
//执行线程
procedure ResumeThread;
property Host:AnsiString read FHost write FHost;
property Port:Integer read FPort write FPort;
property MaxClientCount:Integer read GetMaxClientCount write SetMaxClientCount;
property OnClientConnected:TClientConnected read FOnClientConnected write FOnClientConnected;
property OnGetData:TGetDataEvent read FOnGetData write FOnGetData;
property ClientSocketList:TStringList read FClientSocketList write FClientSocketList;
property IP[Index:Integer]:PAnsiChar read GetItemIP;
property ItemActived[index:Integer]:Boolean read GetItemActived write SetItemActived;
property ClientCount:Integer Read GetClientCount write FClientCount;
property ClientIndex:Integer read FClientIndex;
end;
TWorkThread=class(TThread)
private
//临界
FLock:TCriticalSection;
FSocketServer:Tsocketserver;
procedure Execute;override;
procedure ReciveFromClient;
public
constructor Create(ASocketServer:TSocketServer;CreateSuspended:Boolean);overload;
end;
TServerItem=class
private
FSocket:Tsocket;
FIP:PAnsiChar;
FActived:boolean;
public
property socket:TSocket read FSocket write FSocket;
property IP:PAnsiChar read FIP write FIP;
property Actived:Boolean read FActived write FActived;
end;
implementation
const
BufLen=1024;
{ TSocketServer }
procedure TSocketServer.CheckNewSocket;
var
fd:TFDSet;
addr:sockaddr_in;
addrlen:Integer;
val:Integer;
rec:TSocket;
item:TServerItem;
begin
WinSock.FD_ZERO(fd);
WinSock.FD_SET(FServerSocket,fd);
val:=WinSock.select(FServerSocket,@fd,nil,nil,@Ftimeval);//select 模式
if val>0 then
begin
addrlen:=SizeOf(addr);
//接收可用连接
rec:=WinSock.accept(FServerSocket,@addr,@addrlen);
if rec<>INVALID_SOCKET then
begin
item:=TServerItem.Create;
item.socket:=rec;
item.IP:=WinSock.inet_ntoa(addr.sin_addr);
item.Actived:=true;
//发现有新的连接添加到列表中
FClientSocketList.AddObject(IntToStr(rec),TObject(item));
FClientIndex:=FClientSocketList.Count-1;
FClientCount:=FClientSocketList.Count;
//触发连接事件
DoClientConnected(rec);
end;
end;
end;
constructor TSocketServer.Create(ACallHandle: HWND; CreateSuspended: Boolean);
begin
FCallHandle:=ACallHandle;
FClientIndex:=-1;
SetLength(FRecBuf,BufLen);
FPort:=80;
InitSocket;
FRecStream:=TMemoryStream.Create;
FClientSocketList:=TStringList.Create;
FWorkThread:=TWorkThread.Create(Self,true);
//设置等待时间
FTimeVal.tv_sec:=0;{单位:毫秒}
FTimeVal.tv_usec:=10;{单位:秒}
end;
procedure TSocketServer.DoClientConnected(Socket: TSocket);
begin
if Assigned(FOnClientConnected) then
begin
OnClientConnected(Socket);
end;
end;
procedure TSocketServer.DoRevData(stream: TMemoryStream);
begin
if Assigned(OnGetData) then
begin
OnGetData(FRecStream);
end;
end;
function TSocketServer.GetClientCount: Integer;
begin
Result:=FClientSocketList.Count;
end;
procedure TSocketServer.GetDataFromClient(Socket: TSocket);
var
fd:TFDSet;
val,reclen,i:Integer;
begin
WinSock.FD_ZERO(fd);
WinSock.FD_SET(socket,fd);
val:=WinSock.select(Socket,@fd,nil,nil,@FTimeval);
FRecStream.Clear;
//接收数据,reclen为接收到的数据长度
reclen:=WinSock.recv(Socket,FRecBuf,BufLen,0);
if reclen=0 then
Exit;
//写入到接收内存流中
FRecStream.Write(FRecBuf,reclen);
//触发调用者的接收数据事件
DoRevData(FRecStream);
end;
function TSocketServer.GetItemActived(index: Integer): Boolean;
begin
Result:=TServerItem(FClientSocketList.Objects[index]).Actived;
end;
function TSocketServer.GetItemIP(index: Integer): PAnsiChar;
begin
Result:=TServerItem(FClientSocketList.Objects[index]).IP;
end;
function TSocketServer.GetMaxClient: Integer;
begin
Result:=FMaxClientCout;
end;
function TSocketServer.GetMaxClientCount: Integer;
begin
Result:=FClientSocketList.Count;
end;
function TSocketServer.InitSocket: Boolean;
var
WSA:TWSAData;
begin
Result:=false;
if WSAStartup($0101,WSA)<>0 then
begin
Result:=false;
Exit;
end;
Result:=True;
end;
function TSocketServer.ListenStart: Boolean;
var
addr:sockaddr_in;
begin
Result:=False;
FServerSocket:=socket(PF_INET,SOCK_STREAM,IPPROTO_IP);
if FServerSocket=INVALID_SOCKET then
begin
Result:=False;
exit;
end;
addr.sin_family:=PF_INET;
addr.sin_port:=htons(FPort);
addr.sin_addr.S_addr:=INADDR_ANY;
if bind(FServerSocket,addr,SizeOf(addr))=SOCKET_ERROR then
begin
Result:=false;
closesocket(FServerSocket);
exit;
end;
listen(FServerSocket,5);
Result:=true;
end;
procedure TSocketServer.ResumeThread;
begin
FWorkThread.Resume;
end;
procedure TSocketServer.SetItemActived(index: Integer; const value: Boolean);
begin
TServerItem(FClientSocketList.Objects[index]).Actived:=value;
end;
procedure TSocketServer.SetMaxClient(const Value: Integer);
begin
FMaxClientCout:=value;
end;
procedure TSocketServer.SetMaxClientCount(const value: Integer);
begin
FMaxClientCout:=value;
end;
{ TWorkThread }
constructor TWorkThread.Create(ASocketServer: TSocketServer;
CreateSuspended: Boolean);
begin
FSocketServer:=ASocketServer;
FLock:=TCriticalSection.Create;
inherited Create(CreateSuspended);
FreeOnTerminate:=True;
end;
procedure TWorkThread.Execute;
begin
inherited;
FLock.Enter;
while not Terminated do
begin
ReciveFromClient;
FSocketServer.CheckNewSocket;
end;
FLock.Leave;
end;
//采用select轮询方式,从客户端获取数据
procedure TWorkThread.ReciveFromClient;
var
i:Integer;
begin
for i := FSocketServer.ClientCount-1 downto 0 do
begin
//如果套接字actived:=FALSE;则从类表中删除
if not TServerItem(FSocketServer.ClientSocketList.Objects[i]).Actived then
begin
FSocketServer.ClientSocketList.Delete(i);
FSocketServer.ClientCount:=FSocketServer.ClientCount-1;
Continue;
end;
FSocketServer.GetDataFromClient(TServerItem(FSocketServer.ClientSocketList.Objects[i]).socket);
end;
end;
end.