博客统计信息

51cto博客之星
用户名:fxh7622
文章数:109
评论数:478
访问量:397923
无忧币:2408
博客积分:3119
博客等级:7
注册日期:2006-11-03

Delphi编写事件模型客户端(3)
2009-06-15 11:02:41
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://fxh7622.blog.51cto.com/63841/166942
工作者线程是发送和接收数据的主要部分。没有这部分代码,是无法实现网络通信的。今天我就来讲一下我写的工作者线程是如何实现的。
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.
 

本文出自 “狗窝” 博客,请务必保留此出处http://fxh7622.blog.51cto.com/63841/166942

分享至
更多
一键收藏,随时查看,分享好友!
0人
了这篇文章
类别:网络开发技术圈()┆阅读()┆评论() ┆ 推送到技术圈返回首页

文章评论

 
2009-06-15 17:57:28
菜鸟来学习。

2009-06-16 23:21:20
想请教

2009-06-19 16:25:49
像博主学习!

2009-09-15 23:27:41
    其实用完成端口包装客户端也挺方便的。只要多加一个conn函数,逻辑部分都可以用S的,我感觉代码重用挺好的,有机会你也可以试试。而且还有一个好处,很容易就写出多并发的模拟端。还可以少开一些线程。
博主回复:
2009-09-16 22:28:45
嗯,有时间把我用IOCP写的客户端完善一下呵呵。

2010-02-26 15:59:17
我把你的代码运行了下,发现PostSend函数部分完成后无法触发Event。Sending一直为true,无法继续发送。

 

发表评论            

【技术门诊】专家解析:软考重点难点及应试技巧
昵  称:
登录  快速注册
验证码:

请点击后输入验证码博客过2级,无需填写验证码

内  容: