zoukankan      html  css  js  c++  java
  • delphi异步选择模型编程TCP

    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.

  • 相关阅读:
    第二章整理
    汇编实验二
    汇编实验一
    第一章整理
    第一部分 | 第1章 —— Hello Cocos2d-x
    返回 *this 的成员函数以及 const重载
    C++中的const
    680. Valid Palindrome II
    字典树
    单调队列
  • 原文地址:https://www.cnblogs.com/hnxxcxg/p/5359314.html
Copyright © 2011-2022 走看看