Delphi编写事件模型客户端(3) 推荐
2009-06-15 11:02
351 查看
工作者线程是发送和接收数据的主要部分。没有这部分代码,是无法实现网络通信的。今天我就来讲一下我写的工作者线程是如何实现的。
首先是工作者线程的创建和销毁。
constructor TWorkThread.Create(Parent: TIOEvents);
begin
inherited Create(False);
FParent:=Parent;
end;
我写工作者线程的时候,是将父类(TIOEvents)通过参数传递进来,这样写是为了以后的使用方便。
destructor TWorkThread.Destroy;
begin
inherited;
end;
以下是工作者线程的主要代码。
procedure TWorkThread.Execute;
var
Index:Integer;
ne:TWSANETWORKEVENTS;
begin
while not Terminated do
begin
Index := WSAWaitForMultipleEvents(FParent.FEventNums,@FParent.FEventArray[0],FALSE,WSA_INFINITE,FALSE);
if Index = -1 then
begin
//得到-1应该是需要断开
Exit;
end;
//得到事件对应的数组下标
Index := Index - WSA_WAIT_EVENT_0;
//重置事件
WSAResetEvent(FParent.FEventArray[Index]);
if (Index = WSA_WAIT_FAILED) or (Index = WSA_WAIT_TIMEOUT) or (Index = WSA_INVALID_PARAMETER) or (WSA_INVALID_HANDLE = Index) or (WSANOTINITIALISED = Index) then
begin
Continue;
end;
//开始得到网络事件
if WSAEnumNetworkEvents(FParent.FSocketArray[Index],FParent.FEventArray[Index],@ne) <> INVALID_SOCKET then
begin
case ne.lNetworkEvents of
FD_READ: SocketRead; //接收数据
FD_WRITE: SocketWrite; //发送数据
FD_CLOSE: SocketClose; //连接关闭
end;
end;
end;
end;
由于我在函数WSAWaitForMultipleEvents中使用了参数WSA_INFINITE,这样程序会等在这里一直到套接字上有事件触发。事件触发以后我使用函数WSAResetEvent重置了事件。并使用函数WSAEnumNetworkEvents确定出触发了什么事件。根据不同的事件我调用不同的处理方法。
对于连接关闭事件我的实现是:
procedure TWorkThread.SocketClose;
begin
if Assigned(FParent.FOnDisConnect) then
begin
FParent.OnDisConnect;
end;
//服务端断开
FParent.ClearBuffer;
Destroy;
end;
对于接收到数据事件,我的实现是:
procedure TWorkThread.SocketRead;
var
BytesTransferred,dwFlags: DWORD;
iData:Pchar;
begin
BytesTransferred:=0;
FParent.PostRecv;
if WSAGetOverlappedResult(FParent.FSocket, @FParent.FRecvIOData.Overlapped, @BytesTransferred, FALSE, @dwFlags) then
begin
if BytesTransferred = 0 then
begin
Exit;
end;
FParent.FRecvIOData.BufferLen:=BytesTransferred;
GetMem(iData,FParent.FRecvIOData.BufferLen);
StrMove(iData,@FParent.FRecvIOData.Buffer,FParent.FRecvIOData.BufferLen);
if Assigned(FParent.FOnRecive) then
begin
FParent.FOnRecive(iData,FParent.FRecvIOData.BufferLen);
end;
FreeMem(iData);
end;
end;
我调用函数WSAGetOverlappedResult用来得到接收到的数据信息。并产生一个接收数据事件。
对于发送数据事件,我的处理方法是:
procedure TWorkThread.SocketWrite;
begin
Dec(FParent.FTotalCount);
if Assigned(FParent.FFirstNode) then
begin
if not FParent.PostSend then
begin
closesocket(FParent.FSocket);
end;
end
else
begin
FParent.FSending:=false;
end;
end;
继续投递一个PostSend。来继续发送,发送队列中的数据。至此,Event模型编写客户端通信的主要代码就已经全部写完了,我的代码一定会有一些问题,希望大家看了以后能指出错误来,好让大家一起进步。
initialization
begin
WSAStatupSocket;
end;
finalization
begin
WSACleanupSocket;
end;
end.
首先是工作者线程的创建和销毁。
constructor TWorkThread.Create(Parent: TIOEvents);
begin
inherited Create(False);
FParent:=Parent;
end;
我写工作者线程的时候,是将父类(TIOEvents)通过参数传递进来,这样写是为了以后的使用方便。
destructor TWorkThread.Destroy;
begin
inherited;
end;
以下是工作者线程的主要代码。
procedure TWorkThread.Execute;
var
Index:Integer;
ne:TWSANETWORKEVENTS;
begin
while not Terminated do
begin
Index := WSAWaitForMultipleEvents(FParent.FEventNums,@FParent.FEventArray[0],FALSE,WSA_INFINITE,FALSE);
if Index = -1 then
begin
//得到-1应该是需要断开
Exit;
end;
//得到事件对应的数组下标
Index := Index - WSA_WAIT_EVENT_0;
//重置事件
WSAResetEvent(FParent.FEventArray[Index]);
if (Index = WSA_WAIT_FAILED) or (Index = WSA_WAIT_TIMEOUT) or (Index = WSA_INVALID_PARAMETER) or (WSA_INVALID_HANDLE = Index) or (WSANOTINITIALISED = Index) then
begin
Continue;
end;
//开始得到网络事件
if WSAEnumNetworkEvents(FParent.FSocketArray[Index],FParent.FEventArray[Index],@ne) <> INVALID_SOCKET then
begin
case ne.lNetworkEvents of
FD_READ: SocketRead; //接收数据
FD_WRITE: SocketWrite; //发送数据
FD_CLOSE: SocketClose; //连接关闭
end;
end;
end;
end;
由于我在函数WSAWaitForMultipleEvents中使用了参数WSA_INFINITE,这样程序会等在这里一直到套接字上有事件触发。事件触发以后我使用函数WSAResetEvent重置了事件。并使用函数WSAEnumNetworkEvents确定出触发了什么事件。根据不同的事件我调用不同的处理方法。
对于连接关闭事件我的实现是:
procedure TWorkThread.SocketClose;
begin
if Assigned(FParent.FOnDisConnect) then
begin
FParent.OnDisConnect;
end;
//服务端断开
FParent.ClearBuffer;
Destroy;
end;
对于接收到数据事件,我的实现是:
procedure TWorkThread.SocketRead;
var
BytesTransferred,dwFlags: DWORD;
iData:Pchar;
begin
BytesTransferred:=0;
FParent.PostRecv;
if WSAGetOverlappedResult(FParent.FSocket, @FParent.FRecvIOData.Overlapped, @BytesTransferred, FALSE, @dwFlags) then
begin
if BytesTransferred = 0 then
begin
Exit;
end;
FParent.FRecvIOData.BufferLen:=BytesTransferred;
GetMem(iData,FParent.FRecvIOData.BufferLen);
StrMove(iData,@FParent.FRecvIOData.Buffer,FParent.FRecvIOData.BufferLen);
if Assigned(FParent.FOnRecive) then
begin
FParent.FOnRecive(iData,FParent.FRecvIOData.BufferLen);
end;
FreeMem(iData);
end;
end;
我调用函数WSAGetOverlappedResult用来得到接收到的数据信息。并产生一个接收数据事件。
对于发送数据事件,我的处理方法是:
procedure TWorkThread.SocketWrite;
begin
Dec(FParent.FTotalCount);
if Assigned(FParent.FFirstNode) then
begin
if not FParent.PostSend then
begin
closesocket(FParent.FSocket);
end;
end
else
begin
FParent.FSending:=false;
end;
end;
继续投递一个PostSend。来继续发送,发送队列中的数据。至此,Event模型编写客户端通信的主要代码就已经全部写完了,我的代码一定会有一些问题,希望大家看了以后能指出错误来,好让大家一起进步。
initialization
begin
WSAStatupSocket;
end;
finalization
begin
WSACleanupSocket;
end;
end.
相关文章推荐
- Delphi编写事件模型客户端(2) 推荐
- Delphi编写事件模型客户端(1)
- 蛙蛙推荐:Delphi 6 程序员代码编写标准指南
- 使用Delphi编写棋牌类游戏 -- 基础篇(3) 推荐
- 自己动手编写c++事件模型
- Delphi 编写ActiveForm窗体工程知识和样例(开发浏览器客户端应用程序)
- Delphi编写soap服务器与客户端程序
- 推送通知iOS客户端编写实现及推送服务器端编写 推荐
- 自己动手编写c++事件模型
- 【远控编写07】客户端界面的设计和编写--为对话框添加菜单栏并添加事件响应
- Delphi 编写ActiveForm窗体工程知识和样例(开发浏览器客户端应用程序)(有详细步骤)
- knockout 模型闭包 closespace,高内聚viewModel编写,event事件绑定
- 很幽默的讲解六种Socket IO模型 Delphi版本(自己Select查看,WM_SOCKET消息通知,WSAEventSelect自动收取,Overlapped I/O 事件通知模型,Overlapped I/O 完成例程模型,IOCP模型机器人)
- 编写高质量代码改善C#程序的157个建议[C#闭包的陷阱、委托、事件、事件模型]
- 用Delphi编写Web Service(实例)(续,用Delphi编写客户端)
- Delphi编写soap服务器与客户端程序
- Delphi 编写ActiveForm窗体工程知识和样例(开发浏览器客户端应用程序)
- 使用Delphi编写棋牌类游戏 – 设计篇(1) 推荐
- 在Delphi中编写自己的链表管理类。 推荐
- 编写高质量代码改善C#程序的157个建议——建议41:实现标准的事件模型