DELPHI中完成端口(IOCP)的简单分析(4)

 

在我以前写的文章中,一直说的是如何接收数据。但是对于如何发送数据却一点也没有提到。因为从代码量上来说接收的代码要比发送多很多。今天我就来写一下如何使用IOCP发送数据。

 
function TNetControl.SendSpecifyData(const Socket: TSocket; Data: array of char;
  DataLen: Integer): Boolean;

 
const

 
  DATA_BUFSIZE = 1024;  //这里定义一个发送数据的缓存长度,只要和接收的一直就可以

 
var
  PerIoData: LPPER_IO_OPERATION_DATA ;
  SendBytes, RecvBytes: DWORD;
  Flags: DWORD ;
  LenStr:String;
  SendBuf:array [0..DATA_BUFSIZE] of char;
begin
  try
 //由于粘包的关系,所以在需要发送的数据前面加入4位这次发送数据的长度。(详见我的前一篇文章)

 
 SetArrayLength(DataLen,LenStr) ;
    Fillchar(SendBuf,sizeof(SendBuf),#0);
    strmove(SendBuf,Pointer(LenStr),4);
    strmove(SendBuf+4,Data,DataLen);

 
 //在这里申请一个发送数据的"单IO数据结构"
    PerIoData := LPPER_IO_OPERATION_DATA(GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA)));
    if (PerIoData = nil) then
    begin
      Result:=false;
      exit;
    end;
    ZeroMemory(@PerIoData.Overlapped, sizeof(OVERLAPPED));
    //设置发送标记

 
 PerIoData.BytesRECV := 0;
    PerIoData.DataBuf.len := DataLen+4;
    PerIoData.DataBuf.buf:=@SendBuf;
    PerIoData.BytesSEND := DataLen+4;
    Flags := 0;

 
 //使用WSASend函数将数据发送
    if (WSASend(Socket, @(PerIoData.DataBuf), 1, @SendBytes, 0,@(PerIoData.Overlapped), nil) = SOCKET_ERROR) then
    begin
      if (WSAGetLastError() <> ERROR_IO_PENDING) then
      begin
        //最近在检查代码的时候发现以前这里只是使用Exit来退出是不正确的。这里需要删除申请的单IO数据结构,否子会出现内存泄露。 (2008年3月24日)
        //Exit;
        //表示发送失败,以后也不会有处理在工作者线程处出现。
        if PerIoData <> nil then
        begin
          GlobalFree(DWORD(PerIoData));
        end;
        Result:=false;
        Exit;
      end;
    end;
    Result:=true;
  except
    Result:=false;
  end;
end;
 
 
使用IOCP发送数据的代码就这些,但是这里需要说明一些问题。

 
1:读者一定发送我们在申请了“单IO数据结构”以后并没有对它进行释放。这是因为我们使用的是异步函数WSASend来进行发送数据,只有当我们确定将数据发送出去以后才可以将我们申请的这个结构释放。这就引出了第二个问题。

 
2:如何判断我们发送的数据已经发送。向我以前的文章中所说的“IOCP可以接受来自客户端的数据和自己发送出去的数据”,而区分这个数据是来自客户端还是自己发送出去的区分就是使用PerIoData.BytesRECV 和PerIoData.BytesSEND 如果PerIoData.BytesSEND >0则表示这个数据是自己发送出去的。现在咱们来回顾一下以前的代码,找出释放“单IO数据结构”的地方。

 
在第二篇文章我写了这样的代码。

 
//当我们判断出来接受的数据是我们发送出去的数据的时候,在这里我们清空我们申请的内存空间
else
begin
   GlobalFree(DWORD(PerIoData));
end;

 
这里就是我们释放“单IO数据结构”的地方。

 
到此我已经将整个的IOCP从创建、初始化、接收和发送简单的描述了一下。如果读者根据我写的思路或者代码就可以编写出以后稳定的基于IOCP的网络程序。

DELPHI中完成端口(IOCP)的简单分析(4)的更多相关文章

  1. DELPHI中完成端口(IOCP)的简单分析(3)

    DELPHI中完成端口(IOCP)的简单分析(3)   fxh7622关注4人评论7366人阅读2007-01-17 11:18:24   最近太忙,所以没有机会来写IOCP的后续文章.今天好不容易有 ...

  2. DELPHI中完成端口(IOCP)的简单分析(2)

    DELPHI中完成端口(IOCP)的简单分析(2)   今天我写一下关于DELPHI编写完成端口(IOCP)的工作者线程中的东西.希望各位能提出批评意见.上次我写了关于常见IOCP的代码,对于IOCP ...

  3. DELPHI中完成端口(IOCP)的简单分析(1)

    DELPHI中完成端口(IOCP)的简单分析(1)   用DELPHI开发网络代码已经有一段时间了! 我发现在网上用VC来实现完成端口(IOCP)的代码很多,但是使用DELPHI来实现的就比较少了.对 ...

  4. java 中 “文件” 和 “流” 的简单分析

    java 中 FIle 和 流的简单分析 File类 简单File 常用方法 创建一个File 对象,检验文件是否存在,若不存在就创建,然后对File的类的这部分操作进行演示,如文件的名称.大小等 / ...

  5. rocketmq中的NettyRemotingClient类的简单分析

    rocketmq中的NettyRemotingClient类的简单分析 Bootstrap handler = this.bootstrap.group(this.eventLoopGroupWork ...

  6. Delphi中Android运行和JNI交互分析

    Androidapi.JNIBridge负责和JNI交互.,既然要交互,那么首先就是需要获得JNI的运行环境,Android本身内置的就有一个Java(Dalvik)虚拟机.所以这个第一步就肯定是要这 ...

  7. 关于Delphi中多线程传递参数的简单问题

    http://bbs.csdn.net/topics/390513469/ unit uThread; interface uses Classes; type Th = class(TThread) ...

  8. 不用注册热键方式在Delphi中实现定义快捷键(又简单又巧妙,但要当前窗体处在激活状态)

    第一步:在要实现快捷键的窗体中更改属性“KeyPreview”为True:第二步:在要实现快捷键的窗体中的OnKeyPress事件中填入一个过程名称(在Object Inspector中),填写好后回 ...

  9. jQuery中样式和属性模块简单分析

    1.行内样式操作 目标:扩展框架实现行内样式的增删改查 1.1 创建 css 方法 目标:实现单个样式或者多个样式的操作 1.1.1 css方法 -获取样式 注意:使用 style 属性只能获取行内样 ...

随机推荐

  1. 微信小程序--相关资料

    微信小程序Demo https://github.com/zce/weapp­-demojustjavac/awesome­wechat­weapp: 微信小程序开发资源汇总 https://gith ...

  2. top 命令

    首先介绍top中一些字段的含义: VIRT:virtual memory usage 虚拟内存1.进程"需要的"虚拟内存大小,包括进程使用的库.代码.数据等 2.假如进程申请100 ...

  3. Android 架构:Android Jetpack 架构组件的学习和分析

    参考:https://mp.weixin.qq.com/s/n-AzV7Ke8wxVhmC6ruUIUA 参考:https://jekton.github.io/2018/06/30/android- ...

  4. Atitit 关于共享经济之共享男女朋友的创业计划

    Atitit 关于共享经济之共享男女朋友的创业计划 1. 共享经济的历史与趋势 1 1.1. 共享经济三大特征=产能过剩+共享平台+人人参与. 1 1.2. 共享经济是个大趋势,使用权渐渐的取代所有权 ...

  5. RDLC 根据条件改变背景颜色-多个IIF

    =IIf(Fields!DATE_DIFF.Value < 5 ,"White",IIf(Fields!DATE_DIFF.Value >=5 AND Fields!D ...

  6. git忽略.idan目录

    git rm -r --cached .idea git add . git commit -m '忽略idea' git pull git push

  7. SpringBoot 推荐博客

    http://412887952-qq-com.iteye.com/category/356333

  8. rabbitmq 生产者 消费者(多个线程消费同一个队列里面的任务。) 一个通用rabbitmq消费确认,快速并发运行的框架。

    rabbitmq作为消息队列可以有消息消费确认机制,之前写个基于redis的通用生产者 消费者 并发框架,redis的list结构可以简单充当消息队列,但不具备消费确认机制,随意关停程序,会丢失一部分 ...

  9. 用 wait-notify 写一段代码来解决生产者-消费者问题

    在同步块中调用 wait() 和 notify()方法,如果阻塞,通过循环来测试等待条件.请参考答案中的示例代码. [生产者] import java.util.Vector; import java ...

  10. C#获取一个数组中的最大值、最小值、平均值

    C#获取一个数组中的最大值.最小值.平均值 1.给出一个数组 ,,,,,-,,,,}; 2.数组Array自带方法 本身是直接可以调用Min(),Max(),Average()方法来求出 最小值.最大 ...