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. 关于现在互联网是否还有机会类的价值文章,为什么有人掉进互联网创业的坑里,可能因为ta不懂这些

     --也是带着问题看这篇文章的,面临BAT时代的互联网创业者如何带领自己的公司存活成长,本文有些理念很有意思,前辈企业家是抓住机会干企业,现代化是发现问题最先解决干企业,最难的.同仁意愿不强的大问题才 ...

  2. 单片机成长之路(51基础篇) - 002 STC单片机冷启动和复位有什么区别

    STC单片机简介 STC单片机是一款增强型51单片机,完全兼容MCS-51,还增加了新的功能,比如新增两级中断优先级,多一个外中断,内置EEPROM,硬件看门狗,具有掉电模式,512B内存等.还支持I ...

  3. JAVA方法中的参数用final来修饰的原因

    JAVA方法中的参数用final来修饰的原因   很多人都说在JAVA中用final来修饰方法参数的原因是防止方法参数在调用时被篡改,其实也就是这个原因,但理解起来可能会有歧义,有的人认为是调用语句的 ...

  4. 获取CPU序列号的Delphi程序

    Unit CPUid; Interface Type TCpuType = (cpu8086, cpu286, cpu386, cpu486, cpuPentium); Function CpuTyp ...

  5. 如何使用maven优雅地管理项目版本号

    原文: https://blog.csdn.net/TeleDCOS/article/details/79853782

  6. java生成兑换码礼包码--工具类

    import java.util.HashSet; import java.util.Random; import java.util.Set; public class GenSerial { pr ...

  7. npm安装package.json中的模块依赖

    npm 一键安装 package.json里的依赖时有2种情况: 1.package.json不存在时 运行命令: npm init可自动创建package.json文件 2.package.json ...

  8. Sword libcurl回调函数相关知识

    libcurl响应回调函数说明   libcurl在默认情况下,回调里面会将数据分段的返回,不会一下子将发送端的数据全部塞到回调函数里面, 经过源码分析回调函数和curl_easy_perform是在 ...

  9. MySQL server has gone away

    场景: 批量写入数据时,MySQL server has gone away 解决方法: 在 my.ini 中 将 max_allowed_packet 参数设置大一点  show global va ...

  10. Android 最流行的吸顶效果的实现及代码

    开始逐渐领略到ItemDecoration的美~ 今天让我 使用 ItemDecoration 来完成 可推动的悬浮导航栏的效果,最终实现的效果如下图: 具体实现步骤如下: 根据我前面的文章所讲的Re ...