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..10] of 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 - 1] of 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.
interface
uses
WinSock2, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TWorkThread = class(TThread)
private
FMemo: TMemo;
FBuff: array [0..10] of 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 - 1] of 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)模式,还有一种“完成例程”模式(非完成端口);