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. Linux驱动面试题

    1. Linux设备中字符设备与块设备有什么主要的区别?请分别列举一些实际的设备说出它们是属于哪一类设备. 字符设备:字符设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程序来实现这种 ...

  2. C#指定长度截取字符串 并进行拼接。

    需求:有一个字符串需要按照指定长度拆分出来,然后在增加一个字符串拼接上. /// <summary> /// 字符串截取并拼接 /// </summary> /// <p ...

  3. 恶心github 下载慢

    起因 某天看github上面的代码,有点不耐烦,想下载下来再看,但是现在速度慢的可怜 解决思路 相关网站 获取域名相关ip ipaddress.com 这个有好处就是知道网站部署在哪里,如果有vpn的 ...

  4. BizTalk日志自动发送邮件通知

    更多内容请查看:BizTalk动手实验系列目录                             BizTalk 开发系列 BizTalk 培训/项目开发/技术支持请联系:Email:cbcye ...

  5. Control group namespaces

    https://www.toptal.com/linux/separation-anxiety-isolating-your-system-with-linux-namespaces https:// ...

  6. crawler_exa1

    编辑中... #! /usr/bin/env python # -*- coding:utf-8 -*- # Author: Tdcqma ''' 网页爬虫,版本 2017-09-20 21:16 ' ...

  7. 【原创 Hadoop&Spark 动手实践 4】Hadoop2.7.3 YARN原理与动手实践

    简介 Apache Hadoop 2.0 包含 YARN,它将资源管理和处理组件分开.基于 YARN 的架构不受 MapReduce 约束.本文将介绍 YARN,以及它相对于 Hadoop 中以前的分 ...

  8. mybatis #与$区别

    mybatis #与$区别 #{}变量解析到SQL有带引号字符串:如查询条件变量如:select * from user where name = #{name}; 为:select * from u ...

  9. Servlet 2.0 && Servlet 3.0 新特性

    概念:透传. Callback 在异步线程中是如何使用的.?? Servlet 2.0 && Servlet 3.0 新特性 Servlet 2.0 && Servle ...

  10. 利用Layer组件弹出多个对话框(非嵌套)与关闭及刷新

    页面A中弹出页面B,在页面B中弹出页面C,在layer做嵌套ifframe弹出时会遇到C页面被嵌套在B页面中,如果C尺寸大于B,则C将不能显示完整.这个时候可以考虑B,C页面均由A页面弹出从而避免嵌套 ...