Winsock学习笔记5:I/O Overlapped (重叠)模式

Winsock学习笔记5:I/O Overlapped (重叠)模式

 

复制代码
unit Unit1;

interface

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

type
  TWorkThread 
= class(TThread)
  
private
    FMemo: TMemo;
    FBuff: 
array [0..10of Char;
    FClientSocket: TSocket;
    
procedure ShowRecv;
  
protected
    
procedure Execute;override;
  
public
    
constructor Create(Memo: TMemo; ClientSocket: TSocket);
  
end;

  TForm1 
= class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Timer1: TTimer;
    
procedure Timer1Timer(Sender: TObject);
    
procedure FormCreate(Sender: TObject);
  
private
    
{ Private declarations }
  
public
    
{ Public declarations }
  
end;

var
  Form1: TForm1;
  ServerSocket: TSocket;

implementation

{$R *.dfm}

{ TWorkThread }

constructor TWorkThread.Create(Memo: TMemo; ClientSocket: TSocket);
begin
  
inherited Create(False);

  FMemo:
= Memo;
  FClientSocket:
= ClientSocket;
end;

procedure TWorkThread.Execute;
var
  WSBuff: WSABuf;
  EventTotal: Integer;
  AcceptOverLapped: WSAOverLapped;
  WSAEventArray: 
array [0..WSA_MAXIMUM_WAIT_EVENTS - 1of WSAEvent;

  Idx: Integer;
  ReceiveBytes: DWORD;
  Flags: DWORD;
  ByteTransferred: DWORD;
begin
  
inherited;
  FreeOnTerminate:
= True;
  EventTotal:
= 0;

  
//创建事件
  WSAEventArray[EventTotal]:
= WSACreateEvent;
  
//置零
  ZeroMemory(@AcceptOverLapped, SizeOf(WSAOverLapped));
  
//关联事件
  AcceptOverLapped.hEvent:
= WSAEventArray[EventTotal];

  WSBuff.len:
= 22;  //缓冲区的长度要大于客户端发送的长度,如果小于客户端发送长度,会出现乱码
  WSBuff.buf:
= FBuff;
  Inc(EventTotal);

  
while not Terminated do
  
begin
    
//收消息
    WSARecv(FClientSocket, @WSBuff, EventTotal, ReceiveBytes, Flags, @AcceptOverlapped, 
nil);
    
//用WSAWaitForMultipleEvents检测是否有“事件”发生
    Idx:
= WSAWaitForMultipleEvents(EventTotal, @WSAEventArray[0], False, WSA_INFINITE, False);
    
//用WSAGetOverlappedResult取得结果
    WSAGetOverlappedResult(FClientSocket, @AcceptOverlapped, @ByteTransferred, False, Flags);
    
//显示收到的内容
    Synchronize(ShowRecv);

    
//清零AcceptOverLapped
    ZeroMemory(@AcceptOverLapped, SizeOf(WSAOverLapped));
    
//关联事件
    AcceptOverLapped.hEvent:
= WSAEventArray[Idx - WSA_WAIT_EVENT_0];

    
//重置Event
    WSAResetEvent(WSAEventArray[Idx 
- WSA_WAIT_EVENT_0]);
  
end;
end;

procedure TWorkThread.ShowRecv;
begin
  FMemo.Lines.Add(FBuff);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  WSData: TWSAData;
  LocalAddr: TSockaddr;
  SocketMode: Cardinal;
begin
  
//初始化Winsock
  WSAStartUp($
202, WSData);
  
//创建套接字
  ServerSocket:
= Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  
//设置LocalAddr的参数
  LocalAddr.sin_family:
= AF_INET;   //IPV4族
  LocalAddr.sin_addr.S_addr:
= INADDR_ANY;//这里不能写Inet_addr('127.0.0.1'),负责会绑定失败,不清楚原因是什么;
  LocalAddr.sin_port:
= Htons(1077); //Host To Net Short,主机字节顺序转为网络字节顺序
  
//绑定本机IP地址、端口,绑定之前先设置好LocalAddr的参数
  Bind(ServerSocket, @LocalAddr, SizeOf(LocalAddr));

  SocketMode:
= 1;
  IoCtlSocket(ServerSocket, FIONBIO, SocketMode);

  
//开始监听
  Listen(ServerSocket, 
5);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  ClientAddr: TSockAddr;
  ClientAddrLen: Integer;
  ClientSocket: TSocket;
begin
  
//接受客户端连接,为对应的客户端创建独立的线程
  ClientAddrLen:
= SizeOf(ClientAddr);
  ClientSocket:
= Accept(ServerSocket, ClientAddr, ClientAddrLen);
  
if ClientSocket <> INVALID_SOCKET then
    TWorkThread.Create(Memo1, ClientSocket);
end;

end.
复制代码

 

 

1.此代码只是为了学习函数的使用方法,为了使代码简单,此处使用Timer管理客户端连接,并为每个连接创建独立的线程,Overlapped的处理方式可在线程的执行部分查看,实际应用中不应该用这种模式;

2.此代码为消息型的重叠(I/O Overlapped)模式,还有一种“完成例程”模式(非完成端口);

posted @ 2012-09-20 08:54  马儿快跑  阅读(311)  评论(0编辑  收藏  举报