Server端:
unit U_FrmServer;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Winsock2, StdCtrls;
const
WM_WINSOCK_ASYNC_MSG = WM_USER + 2987;
type
TTestServer = class(TComponent)
private
FWindow: HWND;
FServerSocket: TSocket;
protected
procedure WndProc(var Msg: TMessage);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure OpenServer;
end;
TfrmServer = class(TForm)
btnOpenServer: TButton;
procedure btnOpenServerClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
FServer: TTestServer;
public
{ Public declarations }
end;
var
frmServer: TfrmServer;
WSData: TWSAData;
implementation
{$R *.DFM}
{ TTestServer }
constructor TTestServer.Create(AOwner: TComponent);
begin
inherited;
FWindow := INVALID_HANDLE_VALUE;
FServerSocket := INVALID_SOCKET;
end;
destructor TTestServer.Destroy;
begin
{Clsses.}DeallocateHWnd(FWindow);
closesocket(FServerSocket);
inherited;
end;
procedure TTestServer.OpenServer;
var
sin: TSockAddrIn;
begin
//建立一个隐藏窗口,获得句柄
if FWindow = INVALID_HANDLE_VALUE then begin
FWindow := {Classes.} AllocateHWnd(WndProc);
end;
FServerSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sin.sin_family := AF_INET;
sin.sin_port := htons(4567);
sin.sin_addr.S_addr := INADDR_ANY;
//绑定套接字到本机
if bind(FServerSocket, @sin, SizeOf(sin)) = SOCKET_ERROR then exit;
//将套接字设置为窗体通知消息类型
WSAAsyncSelect(FServerSocket, FWindow, WM_WINSOCK_ASYNC_MSG,
FD_ACCEPT or FD_CLOSE or FD_READ or FD_WRITE);
//进入监听模式
listen(FServerSocket, 5);
end;
procedure TTestServer.WndProc(var Msg: TMessage);
var
sClient, sEvent: TSocket;
addrRemote: TSockAddrIn;
nAddrLen, nRecv: Integer;
sRecv: string;
begin
//非Socket消息
if Msg.Msg <> WM_WINSOCK_ASYNC_MSG then begin
Msg.Result := DefWindowProc(FWindow, Msg.Msg, Msg.WParam, Msg.LParam);
Exit;
end;
//取得有事件发生的套接字
sEvent := Msg.WParam;
if WSAGetSelectError(Msg.lParam) <> 0 then begin
closesocket(sEvent);
exit;
end;
//处理发生的事件
case WSAGetSelectEvent(Msg.lParam) of
//监听的套接字检测到有连接进入
FD_ACCEPT:
begin
nAddrLen := sizeOf(addrRemote);
sClient := accept(sEvent, addrRemote, nAddrLen);
WSAAsyncSelect(sClient, FWindow, WM_WINSOCK_ASYNC_MSG,
FD_READ or FD_WRITE or FD_CLOSE);
ShowMessage(inet_ntoa(addrRemote.sin_addr) + ' connected');
end;
FD_WRITE:
begin
end;
FD_READ:
begin
SetLength(sRecv, 1024);
nRecv := recv(sEvent, sRecv[1], 1024, 0);
if nRecv = -1 then closesocket(sEvent)
else begin
SetLength(sRecv, nRecv);
ShowMessage(sRecv);
end;
end;
FD_CLOSE:
begin
closesocket(sEvent);
ShowMessage('Clent Quit');
end;
end;
end;
procedure TfrmServer.btnOpenServerClick(Sender: TObject);
begin
FServer := TTestServer.Create(Self);
FServer.OpenServer;
end;
procedure TfrmServer.FormDestroy(Sender: TObject);
begin
FServer.Free;
end;
initialization
WSAStartup($0202, WSData);
finalization
WSACleanup;
end.
Client端:
[delphi] view plain copy
unit U_FrmClient;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Winsock2, StdCtrls;
const
WM_WINSOCK_ASYNC_MSG = WM_USER + 2988;
type
TTestClient = class(TComponent)
private
FWindow: HWND;
FClientSocket: TSocket;
protected
procedure WndProc(var Msg: TMessage);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure SendStr(Str: string);
procedure ConnectServer;
end;
TfrmClient = class(TForm)
btnConnect: TButton;
btnSend: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btnConnectClick(Sender: TObject);
procedure btnSendClick(Sender: TObject);
private
{ Private declarations }
FClient: TTestClient;
public
{ Public declarations }
end;
var
frmClient: TfrmClient;
WSData: TWSAData;
implementation
{$R *.DFM}
{ TTestClient }
procedure TTestClient.ConnectServer;
var
servAddr: TSockAddrIn;
begin
if FWindow = INVALID_HANDLE_VALUE then begin
FWindow := {Classes.} AllocateHWnd(WndProc);
end;
if FClientSocket = INVALID_SOCKET then begin
FClientSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if FClientSocket = INVALID_SOCKET then exit;
end;
servAddr.sin_family := AF_INET;
servAddr.sin_port := htons(4567);
servAddr.sin_addr.S_addr := inet_addr('127.0.0.1');
WSAAsyncSelect(FClientSocket, FWindow, WM_WINSOCK_ASYNC_MSG,
FD_CONNECT or FD_WRITE or FD_READ or FD_CLOSE);
if connect(FClientSocket, @servAddr, SizeOf(servAddr)) = -1 then exit;
PostMessage(FWindow, WM_WINSOCK_ASYNC_MSG, FClientSocket,
WSAMakeSelectReply(FD_CONNECT, 0));
end;
constructor TTestClient.Create(AOwner: TComponent);
begin
inherited;
FWindow := INVALID_HANDLE_VALUE;
FClientSocket := INVALID_SOCKET;
end;
destructor TTestClient.Destroy;
begin
{Clsses.}DeallocateHWnd(FWindow);
closesocket(FClientSocket);
inherited;
end;
procedure TTestClient.SendStr(Str: string);
begin
send(FClientSocket, Pointer(Str)^, Length(Str), 0);
end;
procedure TTestClient.WndProc(var Msg: TMessage);
begin
if Msg.Msg <> WM_WINSOCK_ASYNC_MSG then begin
Msg.Result := DefWindowProc(FWindow, Msg.Msg, Msg.WParam, Msg.LParam);
Exit;
end;
//客户端Socket
if Msg.WParam <> Integer(FClientSocket) then Exit;
if WSAGetSelectError(Msg.lParam) = 0 then begin
exit;
end;
case WSAGetSelectEvent(Msg.lParam) of
FD_CONNECT: ShowMessage('Connect Server succ');
FD_READ: ShowMessage('recv succ');
FD_WRITE: ShowMessage('send succ');
FD_CLOSE: ;
end;
end;
procedure TfrmClient.FormCreate(Sender: TObject);
begin
FClient := TTestClient.Create(Self);
end;
procedure TfrmClient.FormDestroy(Sender: TObject);
begin
FClient.Free;
end;
procedure TfrmClient.btnConnectClick(Sender: TObject);
begin
FClient.ConnectServer;
end;
procedure TfrmClient.btnSendClick(Sender: TObject);
begin
FClient.SendStr('test');
end;
initialization
WSAStartup($0202, WSData);
finalization
WSACleanup;
end.