iocpdemo,数据回显

//iocpdemo,数据回显:简单的接受客户端连接,并原样返回客户端发送过来的消息
unit unMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, JwaWinsock2, ExtCtrls;

type
  TMysktOper = (soSend,soRecv);
  TClientSkt = packed record
    Ovlap: WSAOVERLAPPED;
    Handle: TSocket;
    SendBuf: array[0..4095] of byte;
    RecvBuf: array[0..4095] of byte;
    lpbsend: LPWSABUF;
    lpbrecv: LPWSABUF;
    sendbytes,recvbytes: Cardinal;
    Oper: TMysktOper;
  end;
  PClientSkt = ^TClientSkt;

  TMyThrd = class(TThread)
  protected
    procedure Execute; override;
  end;
  TLsnThrd = class(TThread)
  protected
    procedure Execute; override;
  end;
  TfrmMain = class(TForm)
    btnStart: TButton;
    btnStop: TButton;
    procedure btnStartClick(Sender: TObject);
    procedure btnStopClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
    FLsn: TLsnThrd;
  public
    { Public declarations }
  end;

var
  frmMain: TfrmMain;

implementation

var
  G_IOCP: THandle = 0;
  G_overlap: TOverlapped;
  G_clients: integer = 0;
  G_Stoped: Boolean = false;  

{$R *.dfm}

procedure TfrmMain.btnStartClick(Sender: TObject);
begin
  Flsn := TLsnThrd.Create(false);
end;

{ TMyThrd }

procedure TMyThrd.Execute;
var
  bts: Cardinal;
  keydata: Cardinal;
  ov: LPWSAOVERLAPPED;
  r: bool;
  skt: PClientSkt;
  lpb: LPWSABUF;
  flag: Cardinal;
begin
//  inherited;
  FreeOnTerminate := True;
  while not Terminated do
  begin
    r := GetQueuedCompletionStatus(G_IOCP,bts,keydata,POverlapped(ov),WSA_INFINITE);
    if (not r) or (ov = nil) then
      begin
        //RaiseLastOSError
      end
    else begin
       skt := PClientSkt(ov);
       FillChar(ov^,sizeof(_OVERLAPPED),0);
       if skt^.Oper = soRecv then
       begin
         move(skt^.RecvBuf[0],skt^.SendBuf[0],bts);
         skt^.lpbsend^.len := bts;
         skt^.lpbsend.buf := @(skt^.SendBuf[0]);
         WSASend(skt^.Handle,skt^.lpbsend,1,skt^.sendbytes,0,ov,nil);
         skt^.Oper := soSend;
       end
       else begin
         skt^.lpbrecv.buf := @skt^.RecvBuf[0];
         skt^.lpbrecv.len := 4095;
         flag := 0;
         WSARecv(skt^.Handle,skt^.lpbrecv,1,skt^.recvbytes,flag,ov,nil);
         skt^.Oper := soRecv;
       end;
    end;
  end;
end;

procedure TfrmMain.btnStopClick(Sender: TObject);
begin
  G_Stoped := True;
  exit;

end;

{ TLsnThrd }

procedure TLsnThrd.Execute;
var
  lsn,acpt: TSocket;
  wsa: WSAData;
  i,w: integer;
  sysinfo: SYSTEM_INFO;
  FWorkThreads: array of THandle;
  addr: sockaddr_in;
  pmyskt: PClientSkt;
  flag: Cardinal;
  pskaddr: PSockAddr;
  evLsn: Cardinal;
  evs: array[0..0] of Cardinal;
  idx: dword;
begin
  FreeOnTerminate := True;
  if G_IOCP = 0 then
    G_IOCP := CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);
  if G_IOCP = 0 then
    Raise Exception.Create('create IO Complete Port Fail!!');
  w := WSAStartup(MakeWord(2,2),wsa);
  if w <> 0 then
    Raise Exception.Create('WINSOCK 2 Startup fail,error code: '+IntToStr(w));


  GetSystemInfo(sysinfo);
  SetLength(FWorkThreads,sysinfo.dwNumberOfProcessors * 2 + 1);
  for i := 0 to sysinfo.dwNumberOfProcessors * 2 + 1 do
    FWorkThreads[i] := Cardinal(TMyThrd.Create(False));
//  exit;
  lsn := WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,nil,0,WSA_FLAG_OVERLAPPED);
  if lsn = INVALID_SOCKET then
    Raise Exception.Create('Create listening socket fail,error code:'+IntToStr(WSAGetLastError));
  addr.sin_family := AF_INET;
  addr.sin_addr.S_addr := htonl(INADDR_ANY);
  addr.sin_port := htons(5500);
  if bind(lsn,@addr,sizeof(addr)) <> 0 then
    Raise Exception.Create('Binding listening socket fail,error code:'+IntToStr(WSAGetLastError));
  evLsn := WSACreateEvent;
  evs[0] := evLsn;
  WSAEventSelect(lsn,evLsn,FD_ACCEPT);
  if listen(lsn,10) <> 0 then
    Raise Exception.Create('Listening socket fail,error code:'+IntToStr(WSAGetLastError));

  G_Stoped := False;
  while true do
  begin
    if G_Stoped then
      Break;
    i := sizeof(addr);
    idx := WSAWaitForMultipleEvents(1,@evs[0],true,1000,False);
    if idx - WSA_WAIT_EVENT_0 = 0 then
    begin
      WSAResetEvent(evLsn);
      acpt := accept(lsn,@addr,@i);
      if acpt = INVALID_SOCKET then
        Raise Exception.Create('Accepting socket fail,error code:'+IntToStr(WSAGetLastError));
      InterlockedIncrement(G_Clients);
      GetMem(pmyskt,sizeof(TClientSkt));
  //    GetMem(pmyskt^.Ovlap,sizeof(TOverlapped));
      FillChar(pmyskt^.Ovlap,sizeof(TOverlapped),0);
      GetMem(pmyskt^.lpbsend,sizeof(WSABUF));
      GetMem(pmyskt^.lpbrecv,sizeof(WSABUF));
      pmyskt^.Handle := acpt;

      pmyskt^.lpbrecv.buf := @pmyskt^.RecvBuf[0];
      pmyskt^.lpbrecv.len := 4095;
      if  CreateIoCompletionPort(acpt,G_IOCP,Cardinal(pmyskt),0) = 0 then
        RaiseLastOSError;
      flag := 0;
      pmyskt^.Oper := soRecv;
      WSARecv(acpt,pmyskt^.lpbrecv,1,pmyskt^.recvbytes,flag,@pmyskt^.Ovlap,nil);
    end;
  end;
  for i := 0 to Length(FWorkThreads)-1 do
    TThread(FWorkThreads[i]).Terminate;
  closesocket(lsn);
  WSACloseEvent(evLsn);
  CloseHandle(G_IOCP);
  WSACleanup;
end;

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if not G_Stoped then
    btnStop.Click;
  Sleep(2000);
end;

end.
 
 
 
 
 
 
 
 
object frmMain: TfrmMain
  Left = 0
  Top = 0
  Caption = 'IOCP Demo'
  ClientHeight = 381
  ClientWidth = 595
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnClose = FormClose
  PixelsPerInch = 96
  TextHeight = 13
  object btnStart: TButton
    Left = 48
    Top = 8
    Width = 75
    Height = 25
    Caption = #21551#21160
    TabOrder = 0
    OnClick = btnStartClick
  end
  object btnStop: TButton
    Left = 48
    Top = 39
    Width = 75
    Height = 25
    Caption = #20572#27490
    TabOrder = 1
    OnClick = btnStopClick
  end
end


 

你可能感兴趣的:(iocpdemo,数据回显)