长亭百川云 - 文章详情

重叠IO之完成例程

Delphi研习社

46

2024-07-13

基于事件通知的重叠 I/O 模型,是在你投递了一个请求(比如 WSARecv),系统在完成以后是用事件来通知你的,而在完成例程中,系统在网络操作完成以后会自动调用你提供的回调函数

如果你想要使用重叠 I/O 机制带来的高性能模型,又懊恼于基于事件通知的重叠模型要受到 64 个等待事件的限制,还有点畏惧完成端口稍显复杂的初始化过程,那么"完成例程"无疑是你最好的选择!

函数介绍

在事件通知模型中我们使用 WSAWaitForMultipleEvents 和 WSAGetOverlappedResult 来完成事件通知的处理,在完成例程中很明显这两个函数用不到了。

有一个函数我们需要聊一下,WSARecv 函数,上一节我们有个参数设置为 NULL。这就是我们本次要聊的,它的原型如下

void LpwsaoverlappedCompletionRoutine(  
  DWORD dwError,  
  DWORD cbTransferred,  
  LPWSAOVERLAPPED lpOverlapped,  
  DWORD dwFlags  
)  

字段

说明

dwError

投递的重叠操作,比如 WSARecv,完成的状态是什么

cbTransferred

实际传输的字节总数

lpOverlapped

传递到最初的 IO 调用内的一个重叠 结构

dwFlags

返回操作结束时可能用的标志

编码实现

此处省略客户端代码了,因为就是无限发送 HelloWorld

服务器端代码是基于事件通知修改的,一直到监听客户端连接都一样,唯一变动的就是回调函数

procedure RecvCompletionRoutine(error, BytesTransferred: DWORD; Overlapped: POverlapped; InFlags: DWORD); stdcall;  
var  
  Index: Integer;  
begin  
  //遍历数组,获取之前的 Socket 和事件及缓冲区  
  for Index := 0 to WSA_MAXIMUM_WAIT_EVENTS - 1 do begin  
  
    if OverlappedDomain.Events[Index] = Overlapped^.hEvent then begin  
      //IO 已经完成  
      if (error = 0) and (BytesTransferred > 0) then  
        Writeln('客户端序号:' + IntToStr(Index) + ',内容:', PChar(wBuf.buf))  
      else begin  
        //数据已经不可读取(客户端发生异常)  
  
        closesocket(OverlappedDomain.Clients[Index]);  
  
        WSACloseEvent(OverlappedDomain.Events[Index]);  
  
        EventTotal := EventTotal - 1;  
      end;  
  
      break;  
    end;  
  end;  

在 无线侦听客户端连接的线程 中,我们需要调整一行代码

//很明显,在最后一个参数指定我们的回调函数  
WSARecv(OverlappedDomain.Clients[EventTotal], @wBuf, 1, Cardinal(rec), Cardinal(flg), @OverlappedDomain.Overlappeds[EventTotal], @RecvCompletionRoutine);

参考资料

国内的博客环境真的一言难尽,我是从第一篇文章中读到的第二篇

结语

昨天把事件通知的文章写完也没详细的审查,里面有些逻辑并没有讲清楚。唉,总不能重新发一遍吧,所以还是直接读代码吧

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2