Delphi-IOCP学习笔记<三>====工作线程和Listener-阿里云开发者社区

开发者社区> 天地弦> 正文

Delphi-IOCP学习笔记<三>====工作线程和Listener

简介: 接第一次代码继续分析 uses JwaWinsock2, Windows, SysUtils; const DATA_BUFSIZE = 1024; IO_TYPE_Accept = 1; IO_TYPE_Recv = 2; type //...
+关注继续查看

接第一次代码继续分析

uses
  JwaWinsock2, Windows, SysUtils;

const
  DATA_BUFSIZE = 1024;

  IO_TYPE_Accept = 1;
  IO_TYPE_Recv = 2;



type
  //(1):单IO数据结构
  LPVOID = Pointer;
  LPPER_IO_OPERATION_DATA = ^PER_IO_OPERATION_DATA ;
  PER_IO_OPERATION_DATA = packed record
    Overlapped: OVERLAPPED;
    IO_TYPE: Cardinal;
    DataBuf: TWSABUF;
    Buffer: array [0..1024] of CHAR;
  end;

刚开始结存iocp的时候可能无法理解为什么要申明这样一个结构。

解释下,这个结构是GetQueuedCompletionStatus,PostQueuedCompletionStatus,WSARecv,WSASend,时需要用到一个POverlapped类型的参数。

也许还会有疑惑,为什么不直接使用系统自带的类型呢?

POverlapped = ^TOverlapped;
_OVERLAPPED = record
  Internal: DWORD;
  InternalHigh: DWORD;
  Offset: DWORD;
  OffsetHigh: DWORD;
  hEvent: THandle;
end;

///我可以解释下.是为了在PostQueuedCompletionStatus,WSARecv,WSASend尽可能多传递一下信息给GetQueuedCompletionStatus,所以一般都会扩展这一机构体

//再啰嗦下。定义的结构体,Overlapped: OVERLAPPED;必须放在第一个.你懂的。

//PostQueuedCompletionStatus,WSARecv,WSASend会触发工作线程的GetQueuedCompletionStatus返回<上一笔记有提到>

 

 

 

 

 

下面片段是Listen过程

 //下面循环进行循环获取客户端的请求。
  while (TRUE) do
  begin
     //当客户端有连接请求的时候,WSAAccept函数会新创建一个套接字cSocket。这个套接字就是和客户端通信的时候使用的套接字。
     cSocket:= WSAAccept(sSocket, nil, nil, nil, 0);

     //判断cSocket套接字创建是否成功,如果不成功则退出。
     if (cSocket= SOCKET_ERROR) then
     begin
        closesocket(sSocket);
        exit;
     end;

     //将套接字、完成端口绑定在一起。

     //     最开始的时候没有明白为什么还要调用一次createIoCompletionPort
     //
     //     后来经过google,和测试
     //
     //     是将新的套接字(socket)加入到iocp端口<绑定>
     //     这样工作线程才能处理这个套接字(socket)的数据包
     //如果把下面注释掉,WSARecv这个套接字时,GetQueuedCompletionStatus无法处理到收到的数据包
      
     //      2013年4月19日 09:56:00 
     //      注意第三个参数也需要进行绑定, 否则在工作线程中GetQueuedCompletionStatus时completionKey会取不到cSocket值
     lvPerIOPort := CreateIoCompletionPort(cSocket, lvIOPort, cSocket, 0);
     if (lvPerIOPort = 0) then
     begin
        Exit;
     end;

     //初始化数据包
     PerIoData := LPPER_IO_OPERATION_DATA(GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA)));
     ZeroMemory(@PerIoData.Overlapped, sizeof(OVERLAPPED));

     //数据包中的IO类型:有连接请求
     PerIoData.IO_TYPE := IO_TYPE_Accept;

     //通知工作线程,有新的套接字连接<第三个参数>
     PostQueuedCompletionStatus(lvIOPort, 0, cSocket, POverlapped(PerIOData));
  end;

 

 

下面是IOCP工作线程

 

function ServerWorkerThread(pData:Pointer): Integer; stdcall;
var
  CompletionPort:THANDLE;
  BytesTransferred:Cardinal;
  PerIoData:LPPER_IO_OPERATION_DATA;
  cSocket:TSocket;
  Flags:Cardinal;
  RecvBytes:Cardinal;
  lvResultStatus:BOOL;
  lvRet:Integer;

begin
  CompletionPort:=THandle(pData);
  //得到创建线程是传递过来的IOCP
   while(TRUE) do
   begin
        //工作者线程会停止到GetQueuedCompletionStatus函数处,直到接受到数据为止
        lvResultStatus := GetQueuedCompletionStatus(CompletionPort,
          BytesTransferred,
          cSocket,
          POverlapped(PerIoData), INFINITE);
if (lvResultStatus = False) then
        begin
          //当客户端连接断开或者客户端调用closesocket函数的时候,函数GetQueuedCompletionStatus会返回错误。如果我们加入心跳后,在这里就可以来判断套接字是否依然在连接。
          if cSocket<>0 then
          begin
            closesocket(cSocket);
          end;
          if PerIoData<>nil then
          begin
            GlobalFree(DWORD(PerIoData));
          end;
          continue;
        end;

        if PerIoData = nil then
        begin
          closesocket(cSocket);
          Break;
        end else  if (PerIoData<>nil) then
        begin
          ////shutdown(PerHandleData.Socket, 1);
          if PerIoData.IO_TYPE = IO_TYPE_Accept then  //连接请求
          begin
            GlobalFree(DWORD(PerIoData));
          end else if PerIoData.IO_TYPE = IO_TYPE_Recv then
          begin
            ////可以在这里处理数据……

            GlobalFree(DWORD(PerIoData));
          end;

          /////分配内存<可以加入内存池>
          PerIoData := LPPER_IO_OPERATION_DATA(GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA)));
          ZeroMemory(@PerIoData.Overlapped, sizeof(OVERLAPPED));
          Flags := 0;

          /////进入投递收取动作
          PerIoData.IO_TYPE := IO_TYPE_Recv;
          PerIoData.DataBuf.len:=DATA_BUFSIZE;
          ZeroMemory(@PerIoData.Buffer,sizeof(@PerIoData.Buffer));
          PerIoData.DataBuf.buf := @PerIoData.Buffer;

          /////异步收取数据
          WSARecv(cSocket,
             @PerIoData.DataBuf,
             1,
             RecvBytes,
             Flags,
             @PerIoData^, nil);
          if (WSAGetLastError() <> ERROR_IO_PENDING) then
          begin
            closesocket(cSocket);
            if PerIoData <> nil then
            begin
              GlobalFree(DWORD(PerIoData));
            end;
            Continue;
          end;
        end;
   end;
end;

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
WCF 笔记 (2) - 传输泛型 List 对象
在做邮件服务的时候遇到一个问题: 服务器端有个方法参数是个List 类型。当在客户端传参数的时候 ,你即使传个List类型的参数,也还是提示参数类型错误。 相关解决方法:http://www.cnblogs.com/wizardwu/archive/2009/08/09/1542102.html
629 0
history命令解析_学习笔记
时间:2017.11.13 作者:李强 参考:man,info,magedu讲义 声明:以下英文纯属个人翻译,英文B级,欢迎纠正,盗版不纠,才能有限,希望不误人子弟为好。 1、使用目的与场景     实现快速操作命令的一种方式 2、官方说明     Display or manipulate the history list. 3、写在前面     首先这里有两个概念history list和history file。
758 0
Java中ArrayList学习笔记
Java中ArrayList学习笔记 先看两段代码 这段代码在执行的时候会报 但是这样写就好着呢: 总结,研究报错的代码 ,在for循环的时候调用next()方法,next方法中调用了checkForComodification这个方法,这个方法里面判断modCount和expectedModCount不相等的时候就抛出ConcurrentModificationException这个异常。
721 0
每日学习与工作计划移至日事清APP
今天今天开始,每日学习与工作计划移至日事清APP。 博客园依然是我写文字的主战场。日事清APP仅限于做计划。
738 0
台湾大学林轩田机器学习基石课程学习笔记10 -- Logistic Regression
上一节课,我们介绍了Linear Regression线性回归,以及用平方错误来寻找最佳的权重向量w,获得最好的线性预测。本节课将介绍Logistic Regression逻辑回归问题。
26 0
teachable-machine:探索机器学习如何工作,浏览器中实时浏览
教学机器是一个实验,让所有人都非常方便的探索机器学习,在浏览器中实时浏览,不需要编程。学习更多实验,然后亲自尝试它 访问:https://teachablemachine.
812 0
Android学习之Image操作及时间日期选择器
一、基础学习 1.ImageView是图片容器,就相当于RadioGroup是RadioButton的容器一样,是View的直接子类。 1:        只需要记住图片在res/drawable-xxx下就行了。
807 0
AndroidStudio笔记(3)提升效率的 Live Templates
前言 安卓开发者现如今主流的编译器就是 Android Studio (以下简称AS),而 AS 是基于 IDEA 而定制化开发的编译器。AS 为我们提供了大量能够减少编码量和编码效率的功能,本文着重讲解 AS 自带的 Live Templates 和自定义 Live Templates。
1160 0
+关注
237
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载