自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(20)
  • 资源 (44)
  • 收藏
  • 关注

转载 面向对象葵花宝典:思想,技巧,实现

http://blog.csdn.net/yah99_wolf/article/category/1802759/2

2014-04-03 17:32:32 349

转载 Tomcat服务器集群与负载均衡实现

一、前言在单一的服务器上执行WEB应用程序有一些重大的问题,当网站成功建成并开始接受大量请求时,单一服务器终究无法满足需要处理的负荷量,所以就有点显得有点力不从心了。另外一个常见的问题是会产生单点故障,如果该服务器坏掉,那么网站就立刻无法运作了。不论是因为要有较佳的扩充性还是容错能力,我们都会想在一台以上的服务器计算机上执行WEB应用程序。所以,这时候我们就需要用到集群这一门技术了。

2014-04-03 17:23:54 456

转载 分布式计算、并行计算及集群、网格、云计算的区别

并行计算:并行计算是相对于串行计算来说的。可分为时间上的并行和空间上的并行。 时间上的并行就是指流水线技术,而空间上的并行则是指用多个处理器并发的执行计算。并行计算的目的就是提供单处理器无法提供的性能(处理器能力或存储器),使用多处理器求解单个问题。分布式计算:分布式计算研究如何把一个需要非常巨大的计算能力才能解决的问题分成许多小的部分,然后把这些部分分配给许多计算机进行处理,最后把这些计

2014-04-03 17:07:32 629

转载 架构之路

http://zhongxinhua.iteye.com/blog/1260420

2014-04-03 10:31:49 349

转载 我的服务端之内存池

分类: 我的服务端 C/C++2014-01-05 00:03 1836人阅读 评论(9) 收藏 举报C++memorypool服务端内存碎片内存池内存池(Memory Pool)一、前言1、操作系统的内存分配方式1.1、连续分配方式顾名思义,这种分配方式,会将进程分配在连续的空间。连续分配方式一般可以分为固定分配方式、动态分配方式和伙伴系统(固定分配方式与

2014-01-08 17:43:00 391

转载 Hadoop科普文——常见的45个问题解答

发表于3小时前| 1161次阅读| 来源BDAN| 4 条评论| 作者BDAN大数据HadoopLinux摘要:时至今日,Hadoop已成为最流行的离线数据处理平台,然而它的集群配置起来并不简单。如果你学习Hadoop不久,相信下面这45个问题会对你有所帮助。在工作生活中,有些问题非常简单,但往往搜索半天也找不到所需的答案,在Hadoop的学习与使用过程中同样如

2014-01-08 17:36:44 535

转载 教你如何迅速秒杀掉:99%的海量数据处理面试题

http://blog.csdn.net/v_july_v/article/details/7382693

2013-11-20 16:49:27 510

转载 JAVA学习路线

最近,总有很多初学Java的朋友询问学Java要学哪些内容。回想8年前我学Java的时候,也是对此一无所知。看着那黑呼呼的命令行窗口,怎么也猜不出它和企业开发有什么关系,也想象不出在控制台输出的乘法口诀1*1=1除了给幼儿园的小朋友做练习之外还有什么用途。 现在,经历了8年的开发,终于可以有一点东西,供当年和我一样喜欢Java、想从事于java软件开发的朋友们参考。 1

2013-09-22 15:19:51 602

转载 大大大

http://blog.csdn.net/kofshower/article/details/5888810

2013-09-10 18:01:54 366

转载 Dll注入经典方法完整版

标签:Dll 注入 WinApi 远程线程原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://pnig0s1992.blog.51cto.com/393390/804484Pnig0s1992:算是复习了,最经典的教科书式的Dll注入。总结一下基本的注入过程,分注入和卸载注入Dll:1

2013-08-29 14:05:30 512

转载 怎样将自己的DLL加载到Explorer.exe

我们知道将动态连接库注入到其他进程中有很多种方法。最常见的方法是使用钩子函数(Hook),但是这种方法主要有两个缺点:第一如果某个进程没有加载User32.dll,那么Hook DLL将永远也不会被加载。第二Hook DLL加载的时机问题,只有在进程发出User32调用的时候, Hook DLL才有可能被加载。也就是说假设进程正在进行复杂的数值计算而没有时间进行消息调用的时候,Hook DLL

2013-08-28 16:18:03 2330

转载 屏蔽系统热键的方法总结

在编写程序的过程中,我们有时需要实现屏蔽操作系统一些热键的功能,如(ctrl+delete+alt,ctrl+shift+esc等)。网络上有很多关于这方面的资料,总结了一下,一般有如下两个方法:    1. 通过加载低级键盘钩子(WH_KEYBOARD_LL)截获大部分的系统热键,并屏蔽它。这个方法比较简单,但有个缺陷,那就是对ctrl+alt+delete没有办法。    2.

2013-08-28 16:13:49 1394

转载 Au3入门介绍

Au3http://wenku.baidu.com/view/54f9911255270722182ef707.html

2013-08-27 15:46:19 566

转载 libcurl教程

原文地址:http://curl.haxx.se/libcurl/c/libcurl-tutorial.html    译者:JGood(http://blog.csdn.net/JGood )    译者注:这是一篇介绍如何使用libcurl的入门教程。文档不是逐字逐句按原文翻译,而是根据笔者对libcurl的理解,参考原文写成。文中用到的一些例子,可能不是出自原文,而是笔者在学

2013-08-27 15:33:45 514

转载 【Bat命令集】

1 echo 和 @DOS在运行批处理时, 会依次执行批处理中的每条命令, 并且会在显示器上显示, 如果你不想让它们显示, 可以加一个“echo off” 当然,“echo off”也是命令, 它本身也会显示, 如果连这条也不显示, 就在前面加个“@”。@                      #关闭单行回显echo off               #从下一行开始关闭回显@

2013-08-23 12:21:01 538

转载 【libcurl使用简介】

【libcurl使用简介】 http://www.cppblog.com/qiujian5628/archive/2008/06/28/54873.html

2013-08-22 16:46:59 343

转载 UTF8 、GBK、UNICODE

UNICODE,GBK,UTF-8区别    简单来说,unicode,gbk和大五码就是编码的值,而utf-8,uft-16之类就是这个值的表现形式.而前面那三种编码是一兼容的,同一个汉字,那三个码值是完全不一样的.如"汉"的uncode值与gbk就是不一样的,假设uncode为a040,gbk为b030,而uft-8码,就是把那个值表现的形式.utf-8码完全只针对uncode来组织的,如

2013-08-19 16:14:20 453

转载 关于零长数组

typedef struct {int head; int size; char reply;char data[0];} packet;这里的char data[0] 即为零长数组;其不占用任何空间,甚至是一个指针的空间都不占;其主要是作为扩展数组用的,我们可以这样使用它,packet* cmd =( packet)malloc (sizeof(packet) + 2

2013-02-08 09:42:09 207

转载 并口串口COM口区别

并行接口,简称并口。并口采用的是25针D形接头。所谓“并行”,是指8位数据同时通过并行线进行传送,这样数据传送速度大大提高,但并行传送的线路长度受到限制,因为长度增加,干扰就会增加,数据也就容易出错,目前,并行接口主要作为打印机端口等。并口的工作模式:  1:SPP(Standard Parallel Port)称为标准并口,它是最早出现的并

2013-02-08 09:35:20 470

转载 淘宝开放平台技术历程

淘宝开放平台技术历程Author:放翁Date:2012/10/13注:文中所有的技术点都可以在http://blog.csdn.net/cenwenchu79 找到详细的文章,同时本文主要介绍开放平台技术发展历程,产品和业务内容不涵盖在此,因此受众群体主要是技术人员。2006年底,阿里巴巴提出了workat alibaba的战略,20来号人就被拉到湖畔花园马云的公寓里面开

2012-10-24 16:30:59 1596

算法导论中文版

算法导论中文版,对算法介绍深入,是学习算法的很好的书籍,这得很好的阅读

2014-04-04

高质量程序设计指南-C/C++ [林锐]

高质量程序设计语言是林锐先生的畅销书之一,里面介绍了很多在实际开发中使用到的方法和技巧,具有很强的实战性

2014-01-29

软件项目管理案例教程

软件项目管理案例教程,完整扫描版,非课件是对项目管理方法的介绍,从中可以学到一些相关经验

2013-12-12

淘宝技术这十年,完整最终确认版

淘宝技术这十年,完整最终确认版是对淘宝技术十年的历程回顾,其中有很多大容量并发的设计思想在里面,可以借鉴一二

2013-12-12

深入理解计算机系统

深入理解计算机系统中文高清扫描版,通过本书描述可以对计算机有一个更深入的了解,便于写出高效,安全的代码来

2013-12-12

程序员编程艺术第一~二十七章集锦与总结(教你如何编程)(by_July)定稿版

程序员编程艺术第一~二十七章集锦与总结(教你如何编程)(by_July)定稿版

2013-11-20

Hadoop权威指南

Hadoop权威指南,对于想了解学习大数据处理的同学们有莫大的帮助,hadoop就是个大数据处理的并行数据处理引擎。

2013-09-29

JAVA学习笔记

java学习笔记,对于初学者很有帮助,上传这本书,希望对有意愿学习JAVA的童鞋有所帮助

2013-09-22

ConsoleApplication1

一些基本的功能库,包括读写文件,线程,Socket,xml读写等等,待完善

2013-08-31

ModifyIEMain

自动化修改IE主页工具,省去手动添加修改。是懒人修改主页的很好的工具。

2013-08-31

LibCurlDemo

调用LibCurl库的Demo程序,对于初学者是个很好的借鉴作用。值得研究

2013-08-31

UTF8 unicode GBK码表

UTF8,UINCODE GBK码表,介绍了中文字符部分的区别 , 帮助开发指导使用

2013-08-21

公共函数集合

功能简介 通用于linux/windows平台C++的应用。 主要是对一些系统功能,进行了简洁封装。 主要有读写锁类, 线程类, 线程池类, 定时器类, socket1.1的封装类, ini文件类, txt文件类, 可删除内容的文件类, 查找文件类, 调试输出类, 字符串类, 同步的普通队列和优先级队列类, 智能指针和内存自动管理类,数据库类. 特别声明:因为环境限制,这次测试代码中,没有测试数据库类。我以前也只是在PostgreSQL,SQL Server2000和Acess2000中实际用过。如有朋友用到,请自行修改、测试。 这些类的风格,与个人习惯密切相关! 编译和运行: 1. windwos下,用vs2003打开pub下的test.sln文件,所有的测试程序和类库文件就载入,编译即可。其它程序引用库时,请选中/MDd选项。 2. linux下,执行pub下的Makefile文件,编译即可。如果没有安装PostgreSql,数据库部分会编译不过。 这是部分的代码: class C_Lock { public: C_Lock(); C_Lock(const C_Lock &); // 只是初始化, 和默认构造函数功能一样, 为了适应STL. 一个锁对象的赋值是没有意义的 ~C_Lock(); // 读锁. 要成对调用. void rLock(); void rUnlock(); // 写锁. 要成对调用. void wLock(); void wUnlock(); private: unsigned long m_uReadCount; // 读锁的计数 #ifdef _WIN32 CRITICAL_SECTION m_rCS; // 读锁 CRITICAL_SECTION m_wCS; // 写锁 HANDLE m_hEvent; // CriticalSection不是内核对象, WaitForSingleObject不能等待. 注意Event是自动重置的。 #else pthread_mutex_t m_wMutex; // 锁定同步资源 pthread_mutex_t m_rMutex; // 锁定iReadCount, m_condReadCountZero pthread_cond_t m_condReadCountZero; // 条件变量, 读计数为0的通知 #endif };

2013-05-21

跟我一起写makefile

描述如何编写makefile文件,里面有描写makefile的各种语法,用于在linux下编译连接。

2013-02-07

Enterprise Architect 教程

描述EA的使用方法,EA是一个功能全面的UML绘制工具,提供逆向工程的功能,有用例图,时序图等等

2013-02-06

Visual Leak Detector

检测内存泄露 前面提到了Visual C++内置的内存泄漏检测工具的工作原理。与该原理相同,因为全局变量以构造的相反顺序析构,在Visual Leak Detector析构时,几乎所有的其他变量都已经析构,此时如果仍然有未释放之堆内存,则必为内存泄漏。 分配的堆内存是通过一个链表来组织的,检查内存泄漏则是检查此链表。但是windows没有提供方法来访问这个链表。Visual Leak Detector使用了一个小技巧来得到它。首先在堆上申请一块临时内存,则该内存的地址可以转换成指向一个_CrtMemBlockHeader结构,在此结构中就可以获得这个链表。代码如下: char *pheap = new char; _CrtMemBlockHeader *pheader = pHdr(pheap)->pBlockHeaderNext; delete pheap; 其中pheader则为链表首指针。 报告生成 前面讲了Visual Leak Detector如何检测、记录内存泄漏及其其调用堆栈。但是如果要这个信息对程序员有用的话,必须转换成可读的形式。Visual Leak Detector使用SymGetLineFromAddr64()及SymFromAddr()生成可读的报告。 // Iterate through each frame in the call stack. for (frame = 0; frame < callstack->size(); frame++) { // Try to get the source file and line number associated with // this program counter address. if (pSymGetLineFromAddr64(m_process, (*callstack)[frame], &displacement;, &sourceinfo;)) { ... } // Try to get the name of the function containing this program // counter address. if (pSymFromAddr(m_process, (*callstack)[frame], &displacement64;, pfunctioninfo)) { functionname = pfunctioninfo->Name; } else { functionname = "(Function name unavailable)"; } ... } 概括讲来,Visual Leak Detector的工作分为3步,首先在初始化注册一个钩子函数;然后在内存分配时该钩子函数被调用以记录下当时的现场;最后检查堆内存分配链表以确定是否存在内存泄漏并将泄漏内存的现场转换成可读的形式输出。有兴趣的读者可以阅读Visual Leak Detector的源代码。 总结 在使用上,Visual Leak Detector简单方便,结果报告一目了然。在原理上,Visual Leak Detector针对内存泄漏问题的特点,可谓对症下药——内存泄漏不是不容易发现吗?那就每次内存分配是都给记录下来,程序退出时算总账;内存泄漏现象出现时不是已时过境迁,并非当时泄漏点的现场了吗?那就把现场也记录下来,清清楚楚的告诉使用者那块泄漏的内存就是在如何一个调用过程中泄漏掉的。 Visual Leak Detector是一个简单易用内存泄漏检测工具。现在最新的版本是1.9a,采用了新的检测机制,并在功能上有了很多改进。读者不妨体验一下。

2012-10-18

C++经典代码

//根据半径计算圆的周长和面积 #include <iostream.h> const float PI=3.1416; //声明常量(只读变量)PI 为3.1416 float fCir_L(float); //声明自定义函数fCir_L()的原型 float fCir_S(float); //声明自定义函数fCir_S()的原型 //以下是main()函数 main() { float r,l,s; //声明3 个变量 cout<<"R="; //显示字符串 cin&gt;&gt;r; //键盘输入 l=fCir_L(r); //计算圆的周长,赋值给变量l s=fCir_S(r); //计算圆的面积,赋值给变量s cout&lt;&lt;"l="&lt;&lt;l; //显示计算结果 cout&lt;&lt;"\ns="<<s; } //定义计算圆的周长的函数fCir_L() float fCir_L(float x) { float z=-1.0; //声明局部变量 if (x>=0.0) //如果参数大于0,则计算圆的周长 z=2*PI*x; return(z); //返回函数值 } //定

2012-09-04

软件架构设计的思想与模式

软件架构设计的思想与模式 中科院计算所培训中心谢新华 第一章 软件架构设计思想与体系创建 在软件组织中,架构师的作用是举足轻重的。本课程针对企业开发最关注的问题深入 研讨,抓住投入产出比这个企业的核心价值,讨论架构设计如何使这个核心价值得以实现。 我们认为,一个设计如果必须高手云集才能生产出符合质量要求的产品,并不一定是好的架 构。架构设计的目标是力争使用总体上能力一般的队伍,通过组织和设计的力量,生产出符 合质量要求的产品,从投资回报的角度,两者效果是完全不一样的。另一方面,由于需求变 更不可避免,而需求的变更必然造成设计调整进而造成总体投入的增加,这会极大的影响到 投资回报,所以我们必须研究架构设计如何更好的适应变更,通过设计确保变更、维护与升 级的成本下降。对这一系列问题的深入思考,成为现代软件架构设计的核心思维。 软件企业必须认真研究如何培养高水平的架构人员,但仅仅把架构设计作为一个孤立 的节点来讨论,或者仅仅就架构谈架构的在一个很窄的思维空间中研究问题是没有意义的。 任何设计都来自于目的,我们应该把架构设计放在整个项目过程的大环境下来研究,针对每 个关键节点对设计的影响特点进行研讨,这样才可能真正理解架构设计真正精髓的东西,使 未来的设计工作就会变得极有主动性和想象力。 随着经济全球化进程的不断推进,知识经济的时代已经到来。要增加软件

2012-09-04

常见设计模式的解析和实现(C++)

常见设计模式的解析和实现(C++)之一-Factory模式 作用: 定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。 UML结构图: 抽象基类: 1)Product:创建出来的对象的抽象基类. 2)Factory创建对象的工厂方法的抽象基类. 接口函数: 1)Creator::FactoryMethod:纯虚函数,由派生类实现,创建出对应的Product. 解析: 在这个模式中,有两个抽象基类,一个是Product为创建出来的对象的抽象基类, 一个是Factory是工厂的抽象基类,在互相协作的时候都是由相应的Factory派 生类来生成Product的派生类,也就是说如果要新增一种Product那么也要对应 的新增一个Factory,创建的过程委托给了这个Factory.也就是说一个Factory 和一个Product是一一对应的关系. 备注: 设计模式的演示图上把Factory类命名为Creator,下面的实现沿用了这个命名. 演示实现:

2012-09-04

C++实现Ping

int CPing::SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr) { static ECHOREQUEST echoReq; static nId = 1; static nSeq = 1; int nRet; // Fill in echo request echoReq.icmpHdr.Type = ICMP_ECHOREQ; echoReq.icmpHdr.Code = 0; echoReq.icmpHdr.Checksum = 0; echoReq.icmpHdr.ID = nId++; echoReq.icmpHdr.Seq = nSeq++; // Fill in some data to send for (nRet = 0; nRet < REQ_DATASIZE; nRet++) echoReq.cData[nRet] = ' '+nRet; // Save tick count when sent echoReq.dwTime = GetTickCount(); // Put data in packet and compute checksum echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq;, sizeof(ECHOREQUEST)); // Send the echo request nRet = sendto(s, /* socket */ (LPSTR)&echoReq;, /* buffer */ sizeof(ECHOREQUEST), 0, /* flags */ (LPSOCKADDR)lpstToAddr, /* destination */ sizeof(SOCKADDR_IN)); /* address length */ if (nRet == SOCKET_ERROR) WSAError("sendto()"); return (nRet); }

2012-09-04

Linux系统命令及其使用详解

Linux 系统命令及其使用详解(大全) (来源: 中国系统分析员)   cat cd   chmod chown   cp cut   名称:cat   使用权限:所有使用者   使用方式:cat [-AbeEnstTuv] [--help] [--version] fileName   说明:把档案串连接后传到基本输出(萤幕或加 > fileName 到另一个档案)   参数:   -n 或 --number 由 1 开始对所有输出的行数编号   -b 或 --number-nonblank 和 -n 相似,只不过对于空白行不编号   -s 或 --squeeze-blank 当遇到有连续两行以上的空白行,就代换为一行的空白行   -v 或 --show-nonprinting   范例:   cat -n textfile1 > textfile2 把 textfile1 的档案内容加上行号后输入 textfile2 这个档案里   cat -b textfile1 textfile2 >> textfile3 把 textfile1 和 textfile2 的档案内容加上行号(空白行不加)之后将内容附加到 textfile3   名称:cd   使用权限:所有使用者   使用方式:cd [dirName]   说明:变换工作目录至 dirName。 其中 dirName 表示法可为绝对路径或相对路径。若目录名称省略,则变换至使用者的 home directory (也就是刚 login 时所在的目录).另外,"~" 也表示为 home directory 的意思,"." 则是表示目前所在的目录,".." 则表示目前目录位置的上一层目录。   范例:跳到 /usr/bin/:   cd /usr/bin   跳到自己的 home directory:   cd ~   跳到目前目录的上上两层:   cd ../..   指令名称:chmod   使用权限:所有使用者   使用方式:chmod [-cfvR] [--help] [--version] mode file...   说明:Linux/Unix 的档案存取权限分为三级:档案拥有者,群组,其他。利用 chmod 可以藉以控制档案如何被他人所存取。   把计:   mode:权限设定字串,格式如下:[ugoa...][[+-=][rwxX]...][,...],其中u 表示该档案的拥有者,g 表示与该档案的拥有者属于同一个群体(group)者,o 表示其他以外的人,a 表示这三者

2012-08-31

More Effective C++

malloc( ) 在 C++ 中的对等物是 operator new,free( ) 在 C++ 中的对等物则是 operator delete。和 malloc( ) 及 free( ) 不同的是是,operator new 和 operator delete 都可以被重载,重载後的版本可接受与母版不同个数、不同型别的叁数。这对 operator new 来说一向正确,但直到最近,才对 operator delete 也成立。 operator new 的正常标记(signature)是: void * operator new(size_t) throw (std::bad_alloc); (从现在起,为了简化,我将刻意忽略 exception specifications(译注:就是上述 的 throw (std::bad_alloc)),因为它们和我目前要说的重点没有什麽密切关系。)operator new 的重载版本只能增加新叁数,所以一个 operator new 重载版本可能长这个样子: void * operator new(size_t, void *whereToPutObject) { return whereToPutObject; } 这个特殊版本的 operator new 接受一个额外的 void* 引数,指出此函式应该回传什 麽指标。由於这个特殊形式在 C++ 标准程式库中是如此常见而有用(宣告於表头档 <new>), 因而有了一个属於自己的名称:"placement new"。这个名称表现出其目的:允许程序员指 出「一个 object 应该诞生於记忆体何处」。 随着时间过去,任何「要求额外引数」的 operator new 版本,也都渐渐采用 placement new 这个术语。事实上这个术语已经被铭记於 C++ 标准规格中。因此,当 C++ 程序员谈到 所谓的 placement new 函式,他们所谈的可能是上述那个「需要额外一个 void* 叁数,用 以指出物件置於何处」的版本,但也可能是指那些「所需引数比单一而必要之 size_t 引数 更多」的任何 operator new 版本,包括上述函式,也包括其他「引数更多」的 operator new 函式。 换句话说,当我们把焦点集中在记忆体配置时,"placement new" 意味「operator new 的某个版本,接受额外引数」。这个术语在其他场合可能有其他意义,但我们不需继续深入, 所以,到此为止。如果你需要更多细节,请叁考本文最後所列的叁考读物。 和 placement new 类似,术语 "placement delete" 意味「operator delete 的某个版本, 接受额外引数」。operator delete 的「正常」标记如下: void operator delete(void*); 所以,任何版本的 operator delete,只要接受的引数多於上述的 void*,就是一个 placement delete 函式。 现在让我们重回本文所讨论的一个主题。当 heap object 在建构期间丢出一个异常, 会发生什麽事?再次考虑以下这个简单例子: class ABCD { ... }; ABCD *p = new ABCD; 假设产生 ABCD object 时导致了一个异常。前列的主文内容指出,如果异常来自 ABCD 建构式,operator delete 会自动被唤起,释放 operator new 所配置的记忆体。但如果 operator new 被多载化,情况将如何?如果不同版本的 operator new 以不同的方式配置

2012-08-31

rapidxml最快的解析XML

#ifndef RAPIDXML_HPP_INCLUDED #define RAPIDXML_HPP_INCLUDED // Copyright (C) 2006, 2009 Marcin Kalicinski // Version 1.13 // Revision $DateTime: 2009/05/13 01:46:17 $ //! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation // If standard library is disabled, user must provide implementations of required functions and typedefs #if !defined(RAPIDXML_NO_STDLIB) #include <cstdlib> // For std::size_t #include <cassert> // For assert #include <new> // For placement new #endif // On MSVC, disable "conditional expression is constant" warning (level 4). // This warning is almost impossible to avoid with certain types of templated code #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4127) // Conditional expression is constant #endif /////////////////////////////////////////////////////////////////////////// // RAPIDXML_PARSE_ERROR #if defined(RAPIDXML_NO_EXCEPTIONS) #define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); } namespace rapidxml { //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, //! this function is called to notify user about the error. //! It must be defined by the user. //! <br><br> //! This function cannot return. If it does, the results are undefined. //! <br><br> //! A very simple definition might look like that: //! <pre> //! void %rapidxml::%parse_error_handler(const char *what, void *where) //! { //! std::cout << "Parse error: " << what << "\n"; //! std::abort(); //! } //! </pre> //! \param what Human readable description of the error. //! \param where Pointer to character data where error was detected. void parse_error_handler(const char *what, void *where); } #else #include <exception> // For std::exception #define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where) namespace rapidxml { //! Parse error exception. //! This exception is thrown by the parser when an error occurs. //! Use what() function to get human-readable error message. //! Use where() function to get a pointer to position within source text where error was detected. //! <br><br> //! If throwing exceptions by the parser is undesirable, //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. //! This function must be defined by the user. //! <br><br> //! This class derives from <code>std::exception</code> class. class parse_error: public std::exception { public: //! Constructs parse error parse_error(const char *what, void *where) : m_what(what) , m_where(where) { } //! Gets human readable description of error. //! \return Pointer to null terminated description of the error. virtual const char *what() const throw() { return m_what; } //! Gets pointer to character data where error happened. //! Ch should be the same as char type of xml_document that produced the error. //! \return Pointer to location within the parsed string where error occured. template<class Ch> Ch *where() const { return reinterpret_cast<Ch *>(m_where); } private: const char *m_what; void *m_where; }; } #endif /////////////////////////////////////////////////////////////////////////// // Pool sizes #ifndef RAPIDXML_STATIC_POOL_SIZE // Size of static memory block of memory_pool. // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) #endif #ifndef RAPIDXML_DYNAMIC_POOL_SIZE // Size of dynamic memory block of memory_pool. // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) #endif #ifndef RAPIDXML_ALIGNMENT // Memory allocation alignment. // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. // All memory allocations for nodes, attributes and strings will be aligned to this value. // This must be a power of 2 and at least 1, otherwise memory_pool will not work. #define RAPIDXML_ALIGNMENT sizeof(void *) #endif namespace rapidxml { // Forward declarations template<class Ch> class xml_node; template<class Ch> class xml_attribute; template<class Ch> class xml_document; //! Enumeration listing all node types produced by the parser. //! Use xml_node::type() function to query node type. enum node_type { node_document, //!< A document node. Name and value are empty. node_element, //!< An element node. Name contains element name. Value contains text of first data node. node_data, //!< A data node. Name is empty. Value contains data text. node_cdata, //!< A CDATA node. Name is empty. Value contains data text. node_comment, //!< A comment node. Name is empty. Value contains comment text. node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. node_pi //!< A PI node. Name contains target. Value contains instructions. }; /////////////////////////////////////////////////////////////////////// // Parsing flags //! Parse flag instructing the parser to not create data nodes. //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. //! Can be combined with other flags by use of | operator. //! <br><br> //! See xml_document::parse() function. const int parse_no_data_nodes = 0x1; //! Parse flag instructing the parser to not use text of first data node as a value of parent element. //! Can be combined with other flags by use of | operator. //! Note that child data nodes of element node take precendence over its value when printing. //! That is, if element has one or more child data nodes <em>and</em> a value, the value will be ignored. //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. //! <br><br> //! See xml_document::parse() function. const int parse_no_element_values = 0x2; //! Parse flag instructing the parser to not place zero terminators after strings in the source text. //! By default zero terminators are placed, modifying source text. //! Can be combined with other flags by use of | operator. //! <br><br> //! See xml_document::parse() function. const int parse_no_string_terminators = 0x4; //! Parse flag instructing the parser to not translate entities in the source text. //! By default entities are translated, modifying source text. //! Can be combined with other flags by use of | operator. //! <br><br> //! See xml_document::parse() function. const int parse_no_entity_translation = 0x8; //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. //! By default, UTF-8 handling is enabled. //! Can be combined with other flags by use of | operator. //! <br><br> //! See xml_document::parse() function. const int parse_no_utf8 = 0x10; //! Parse flag instructing the parser to create XML declaration node. //! By default, declaration node is not created. //! Can be combined with other flags by use of | operator. //! <br><br> //! See xml_document::parse() function. const int parse_declaration_node = 0x20; //! Parse flag instructing the parser to create comments nodes. //! By default, comment nodes are not created. //! Can be combined with other flags by use of | operator. //! <br><br> //! See xml_document::parse() function. const int parse_comment_nodes = 0x40; //! Parse flag instructing the parser to create DOCTYPE node. //! By default, doctype node is not created. //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. //! Can be combined with other flags by use of | operator. //! <br><br> //! See xml_document::parse() function. const int parse_doctype_node = 0x80; //! Parse flag instructing the parser to create PI nodes. //! By default, PI nodes are not created. //! Can be combined with other flags by use of | operator. //! <br><br> //! See xml_document::parse() function. const int parse_pi_nodes = 0x100; //! Parse flag instructing the parser to validate closing tag names. //! If not set, name inside closing tag is irrelevant to the parser. //! By default, closing tags are not validated. //! Can be combined with other flags by use of | operator. //! <br><br> //! See xml_document::parse() function. const int parse_validate_closing_tags = 0x200; //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. //! By default, whitespace is not trimmed. //! This flag does not cause the parser to modify source text. //! Can be combined with other flags by use of | operator. //! <br><br> //! See xml_document::parse() function. const int parse_trim_whitespace = 0x400; //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. //! By default, whitespace is not normalized. //! If this flag is specified, source text will be modified. //! Can be combined with other flags by use of | operator. //! <br><br> //! See xml_document::parse() function. const int parse_normalize_whitespace = 0x800; // Compound flags //! Parse flags which represent default behaviour of the parser. //! This is always equal to 0, so that all other flags can be simply ored together. //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. //! This also means that meaning of each flag is a <i>negation</i> of the default setting. //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is <i>enabled</i> by default, //! and using the flag will disable it. //! <br><br> //! See xml_document::parse() function. const int parse_default = 0; //! A combination of parse flags that forbids any modifications of the source text. //! This also results in faster parsing. However, note that the following will occur: //! <ul> //! <li>names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends</li> //! <li>entities will not be translated</li> //! <li>whitespace will not be normalized</li> //! </ul> //! See xml_document::parse() function. const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. //! <br><br> //! See xml_document::parse() function. const int parse_fastest = parse_non_destructive | parse_no_data_nodes; //! A combination of parse flags resulting in largest amount of data being extracted. //! This usually results in slowest parsing. //! <br><br> //! See xml_document::parse() function. const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; /////////////////////////////////////////////////////////////////////// // Internals //! \cond internal namespace internal { // Struct that contains lookup tables for the parser // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). template<int Dummy> struct lookup_tables { static const unsigned char lookup_whitespace[256]; // Whitespace table static const unsigned char lookup_node_name[256]; // Node name table static const unsigned char lookup_text[256]; // Text table static const unsigned char lookup_text_pure_no_ws[256]; // Text table static const unsigned char lookup_text_pure_with_ws[256]; // Text table static const unsigned char lookup_attribute_name[256]; // Attribute name table static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes static const unsigned char lookup_digits[256]; // Digits static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters }; // Find length of the string template<class Ch> inline std::size_t measure(const Ch *p) { const Ch *tmp = p; while (*tmp) ++tmp; return tmp - p; } // Compare strings for equality template<class Ch> inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) { if (size1 != size2) return false; if (case_sensitive) { for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) if (*p1 != *p2) return false; } else { for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) if (lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p1)] != lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p2)]) return false; } return true; } } //! \endcond /////////////////////////////////////////////////////////////////////// // Memory pool //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. //! In most cases, you will not need to use this class directly. //! However, if you need to create nodes manually or modify names/values of nodes, //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. //! Not only is this faster than allocating them by using <code>new</code> operator, //! but also their lifetime will be tied to the lifetime of document, //! possibly simplyfing memory management. //! <br><br> //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. //! You can also call allocate_string() function to allocate strings. //! Such strings can then be used as names or values of nodes without worrying about their lifetime. //! Note that there is no <code>free()</code> function -- all allocations are freed at once when clear() function is called, //! or when the pool is destroyed. //! <br><br> //! It is also possible to create a standalone memory_pool, and use it //! to allocate nodes, whose lifetime will not be tied to any document. //! <br><br> //! Pool maintains <code>RAPIDXML_STATIC_POOL_SIZE</code> bytes of statically allocated memory. //! Until static memory is exhausted, no dynamic memory allocations are done. //! When static memory is exhausted, pool allocates additional blocks of memory of size <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> each, //! by using global <code>new[]</code> and <code>delete[]</code> operators. //! This behaviour can be changed by setting custom allocation routines. //! Use set_allocator() function to set them. //! <br><br> //! Allocations for nodes, attributes and strings are aligned at <code>RAPIDXML_ALIGNMENT</code> bytes. //! This value defaults to the size of pointer on target architecture. //! <br><br> //! To obtain absolutely top performance from the parser, //! it is important that all nodes are allocated from a single, contiguous block of memory. //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. //! If required, you can tweak <code>RAPIDXML_STATIC_POOL_SIZE</code>, <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> and <code>RAPIDXML_ALIGNMENT</code> //! to obtain best wasted memory to performance compromise. //! To do it, define their values before rapidxml.hpp file is included. //! \param Ch Character type of created nodes. template<class Ch = char> class memory_pool { public: //! \cond internal typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory typedef void (free_func)(void *); // Type of user-defined function used to free memory //! \endcond //! Constructs empty pool with default allocator functions. memory_pool() : m_alloc_func(0) , m_free_func(0) { init(); } //! Destroys pool and frees all the memory. //! This causes memory occupied by nodes allocated by the pool to be freed. //! Nodes allocated from the pool are no longer valid. ~memory_pool() { clear(); } //! Allocates a new node from the pool, and optionally assigns name and value to it. //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>. //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function //! will call rapidxml::parse_error_handler() function. //! \param type Type of node to create. //! \param name Name to assign to the node, or 0 to assign no name. //! \param value Value to assign to the node, or 0 to assign no value. //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. //! \return Pointer to allocated node. This pointer will never be NULL. xml_node<Ch> *allocate_node(node_type type, const Ch *name = 0, const Ch *value = 0, std::size_t name_size = 0, std::size_t value_size = 0) { void *memory = allocate_aligned(sizeof(xml_node<Ch>)); xml_node<Ch> *node = new(memory) xml_node<Ch>(type); if (name) { if (name_size > 0) node->name(name, name_size); else node->name(name); } if (value) { if (value_size > 0) node->value(value, value_size); else node->value(value); } return node; } //! Allocates a new attribute from the pool, and optionally assigns name and value to it. //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>. //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function //! will call rapidxml::parse_error_handler() function. //! \param name Name to assign to the attribute, or 0 to assign no name. //! \param value Value to assign to the attribute, or 0 to assign no value. //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. //! \return Pointer to allocated attribute. This pointer will never be NULL. xml_attribute<Ch> *allocate_attribute(const Ch *name = 0, const Ch *value = 0, std::size_t name_size = 0, std::size_t value_size = 0) { void *memory = allocate_aligned(sizeof(xml_attribute<Ch>)); xml_attribute<Ch> *attribute = new(memory) xml_attribute<Ch>; if (name) { if (name_size > 0) attribute->name(name, name_size); else attribute->name(name); } if (value) { if (value_size > 0) attribute->value(value, value_size); else attribute->value(value); } return attribute; } //! Allocates a char array of given size from the pool, and optionally copies a given string to it. //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>. //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function //! will call rapidxml::parse_error_handler() function. //! \param source String to initialize the allocated memory with, or 0 to not initialize it. //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. //! \return Pointer to allocated char array. This pointer will never be NULL. Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) { assert(source || size); // Either source or size (or both) must be specified if (size == 0) size = internal::measure(source) + 1; Ch *result = static_cast<Ch *>(allocate_aligned(size * sizeof(Ch))); if (source) for (std::size_t i = 0; i < size; ++i) result[i] = source[i]; return result; } //! Clones an xml_node and its hierarchy of child nodes and attributes. //! Nodes and attributes are allocated from this memory pool. //! Names and values are not cloned, they are shared between the clone and the source. //! Result node can be optionally specified as a second parameter, //! in which case its contents will be replaced with cloned source node. //! This is useful when you want to clone entire document. //! \param source Node to clone. //! \param result Node to put results in, or 0 to automatically allocate result node //! \return Pointer to cloned node. This pointer will never be NULL. xml_node<Ch> *clone_node(const xml_node<Ch> *source, xml_node<Ch> *result = 0) { // Prepare result node if (result) { result->remove_all_attributes(); result->remove_all_nodes(); result->type(source->type()); } else result = allocate_node(source->type()); // Clone name and value result->name(source->name(), source->name_size()); result->value(source->value(), source->value_size()); // Clone child nodes and attributes for (xml_node<Ch> *child = source->first_node(); child; child = child->next_sibling()) result->append_node(clone_node(child)); for (xml_attribute<Ch> *attr = source->first_attribute(); attr; attr = attr->next_attribute()) result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size())); return result; } //! Clears the pool. //! This causes memory occupied by nodes allocated by the pool to be freed. //! Any nodes or strings allocated from the pool will no longer be valid. void clear() { while (m_begin != m_static_memory) { char *previous_begin = reinterpret_cast&lt;header *&gt;(align(m_begin))->previous_begin; if (m_free_func) m_free_func(m_begin); else delete[] m_begin; m_begin = previous_begin; } init(); } //! Sets or resets the user-defined memory allocation functions for the pool. //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. //! Allocation function must not return invalid pointer on failure. It should either throw, //! stop the program, or use <code>longjmp()</code> function to pass control to other place of program. //! If it returns invalid pointer, results are undefined. //! <br><br> //! User defined allocation functions must have the following forms: //! <br><code> //! <br>void *allocate(std::size_t size); //! <br>void free(void *pointer); //! </code><br> //! \param af Allocation function, or 0 to restore default function //! \param ff Free function, or 0 to restore default function void set_allocator(alloc_func *af, free_func *ff) { assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet m_alloc_func = af; m_free_func = ff; } private: struct header { char *previous_begin; }; void init() { m_begin = m_static_memory; m_ptr = align(m_begin); m_end = m_static_memory + sizeof(m_static_memory); } char *align(char *ptr) { std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1)); return ptr + alignment; } char *allocate_raw(std::size_t size) { // Allocate void *memory; if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] { memory = m_alloc_func(size); assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp } else { memory = new char[size]; #ifdef RAPIDXML_NO_EXCEPTIONS if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc RAPIDXML_PARSE_ERROR("out of memory", 0); #endif } return static_cast<char *>(memory); } void *allocate_aligned(std::size_t size) { // Calculate aligned pointer char *result = align(m_ptr); // If not enough memory left in current pool, allocate a new pool if (result + size > m_end) { // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE) std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; if (pool_size < size) pool_size = size; // Allocate std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation char *raw_memory = allocate_raw(alloc_size); // Setup new pool in allocated memory char *pool = align(raw_memory); header *new_header = reinterpret_cast&lt;header *&gt;(pool); new_header->previous_begin = m_begin; m_begin = raw_memory; m_ptr = pool + sizeof(header); m_end = raw_memory + alloc_size; // Calculate aligned pointer again using new pool result = align(m_ptr); } // Update pool and return aligned pointer m_ptr = result + size; return result; } char *m_begin; // Start of raw memory making up current pool char *m_ptr; // First free byte in current pool char *m_end; // One past last available byte in current pool char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used free_func *m_free_func; // Free function, or 0 if default is to be used }; /////////////////////////////////////////////////////////////////////////// // XML base //! Base class for xml_node and xml_attribute implementing common functions: //! name(), name_size(), value(), value_size() and parent(). //! \param Ch Character type to use template<class Ch = char> class xml_base { public: /////////////////////////////////////////////////////////////////////////// // Construction & destruction // Construct a base with empty name, value and parent xml_base() : m_name(0) , m_value(0) , m_parent(0) { } /////////////////////////////////////////////////////////////////////////// // Node data access //! Gets name of the node. //! Interpretation of name depends on type of node. //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. //! <br><br> //! Use name_size() function to determine length of the name. //! \return Name of node, or empty string if node has no name. Ch *name() const { return m_name ? m_name : nullstr(); } //! Gets size of node name, not including terminator character. //! This function works correctly irrespective of whether name is or is not zero terminated. //! \return Size of node name, in characters. std::size_t name_size() const { return m_name ? m_name_size : 0; } //! Gets value of node. //! Interpretation of value depends on type of node. //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. //! <br><br> //! Use value_size() function to determine length of the value. //! \return Value of node, or empty string if node has no value. Ch *value() const { return m_value ? m_value : nullstr(); } //! Gets size of node value, not including terminator character. //! This function works correctly irrespective of whether value is or is not zero terminated. //! \return Size of node value, in characters. std::size_t value_size() const { return m_value ? m_value_size : 0; } /////////////////////////////////////////////////////////////////////////// // Node modification //! Sets name of node to a non zero-terminated string. //! See \ref ownership_of_strings. //! <br><br> //! Note that node does not own its name or value, it only stores a pointer to it. //! It will not delete or otherwise free the pointer on destruction. //! It is reponsibility of the user to properly manage lifetime of the string. //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - //! on destruction of the document the string will be automatically freed. //! <br><br> //! Size of name must be specified separately, because name does not have to be zero terminated. //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). //! \param name Name of node to set. Does not have to be zero terminated. //! \param size Size of name, in characters. This does not include zero terminator, if one is present. void name(const Ch *name, std::size_t size) { m_name = const_cast<Ch *>(name); m_name_size = size; } //! Sets name of node to a zero-terminated string. //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). //! \param name Name of node to set. Must be zero terminated. void name(const Ch *name) { this->name(name, internal::measure(name)); } //! Sets value of node to a non zero-terminated string. //! See \ref ownership_of_strings. //! <br><br> //! Note that node does not own its name or value, it only stores a pointer to it. //! It will not delete or otherwise free the pointer on destruction. //! It is reponsibility of the user to properly manage lifetime of the string. //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - //! on destruction of the document the string will be automatically freed. //! <br><br> //! Size of value must be specified separately, because it does not have to be zero terminated. //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). //! <br><br> //! If an element has a child node of type node_data, it will take precedence over element value when printing. //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. //! \param value value of node to set. Does not have to be zero terminated. //! \param size Size of value, in characters. This does not include zero terminator, if one is present. void value(const Ch *value, std::size_t size) { m_value = const_cast<Ch *>(value); m_value_size = size; } //! Sets value of node to a zero-terminated string. //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). //! \param value Vame of node to set. Must be zero terminated. void value(const Ch *value) { this->value(value, internal::measure(value)); } /////////////////////////////////////////////////////////////////////////// // Related nodes access //! Gets node parent. //! \return Pointer to parent node, or 0 if there is no parent. xml_node<Ch> *parent() const { return m_parent; } protected: // Return empty string static Ch *nullstr() { static Ch zero = Ch('\0'); return &zero; } Ch *m_name; // Name of node, or 0 if no name Ch *m_value; // Value of node, or 0 if no value std::size_t m_name_size; // Length of node name, or undefined of no name std::size_t m_value_size; // Length of node value, or undefined if no value xml_node<Ch> *m_parent; // Pointer to parent node, or 0 if none }; //! Class representing attribute node of XML document. //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. //! Thus, this text must persist in memory for the lifetime of attribute. //! \param Ch Character type to use. template<class Ch = char> class xml_attribute: public xml_base<Ch> { friend class xml_node<Ch>; public: /////////////////////////////////////////////////////////////////////////// // Construction & destruction //! Constructs an empty attribute with the specified type. //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. xml_attribute() { } /////////////////////////////////////////////////////////////////////////// // Related nodes access //! Gets document of which attribute is a child. //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. xml_document<Ch> *document() const { if (xml_node<Ch> *node = this->parent()) { while (node->parent()) node = node->parent(); return node->type() == node_document ? static_cast&lt;xml_document&lt;Ch> *>(node) : 0; } else return 0; } //! Gets previous attribute, optionally matching attribute name. //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found attribute, or 0 if not found. xml_attribute<Ch> *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_attribute<Ch> *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) return attribute; return 0; } else return this->m_parent ? m_prev_attribute : 0; } //! Gets next attribute, optionally matching attribute name. //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found attribute, or 0 if not found. xml_attribute<Ch> *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_attribute<Ch> *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) return attribute; return 0; } else return this->m_parent ? m_next_attribute : 0; } private: xml_attribute<Ch> *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero xml_attribute<Ch> *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero }; /////////////////////////////////////////////////////////////////////////// // XML node //! Class representing a node of XML document. //! Each node may have associated name and value strings, which are available through name() and value() functions. //! Interpretation of name and value depends on type of the node. //! Type of node can be determined by using type() function. //! <br><br> //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. //! Thus, this text must persist in the memory for the lifetime of node. //! \param Ch Character type to use. template<class Ch = char> class xml_node: public xml_base<Ch> { public: /////////////////////////////////////////////////////////////////////////// // Construction & destruction //! Constructs an empty node with the specified type. //! Consider using memory_pool of appropriate document to allocate nodes manually. //! \param type Type of node to construct. xml_node(node_type type) : m_type(type) , m_first_node(0) , m_first_attribute(0) { } /////////////////////////////////////////////////////////////////////////// // Node data access //! Gets type of node. //! \return Type of node. node_type type() const { return m_type; } /////////////////////////////////////////////////////////////////////////// // Related nodes access //! Gets document of which node is a child. //! \return Pointer to document that contains this node, or 0 if there is no parent document. xml_document<Ch> *document() const { xml_node<Ch> *node = const_cast&lt;xml_node&lt;Ch> *>(this); while (node->parent()) node = node->parent(); return node->type() == node_document ? static_cast&lt;xml_document&lt;Ch> *>(node) : 0; } //! Gets first child node, optionally matching node name. //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found child, or 0 if not found. xml_node<Ch> *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_node<Ch> *child = m_first_node; child; child = child->next_sibling()) if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) return child; return 0; } else return m_first_node; } //! Gets last child node, optionally matching node name. //! Behaviour is undefined if node has no children. //! Use first_node() to test if node has children. //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found child, or 0 if not found. xml_node<Ch> *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { assert(m_first_node); // Cannot query for last child if node has no children if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_node<Ch> *child = m_last_node; child; child = child->previous_sibling()) if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) return child; return 0; } else return m_last_node; } //! Gets previous sibling node, optionally matching node name. //! Behaviour is undefined if node has no parent. //! Use parent() to test if node has a parent. //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found sibling, or 0 if not found. xml_node<Ch> *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { assert(this->m_parent); // Cannot query for siblings if node has no parent if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_node<Ch> *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) return sibling; return 0; } else return m_prev_sibling; } //! Gets next sibling node, optionally matching node name. //! Behaviour is undefined if node has no parent. //! Use parent() to test if node has a parent. //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found sibling, or 0 if not found. xml_node<Ch> *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { assert(this->m_parent); // Cannot query for siblings if node has no parent if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_node<Ch> *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) return sibling; return 0; } else return m_next_sibling; } //! Gets first attribute of node, optionally matching attribute name. //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found attribute, or 0 if not found. xml_attribute<Ch> *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_attribute<Ch> *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) return attribute; return 0; } else return m_first_attribute; } //! Gets last attribute of node, optionally matching attribute name. //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters //! \return Pointer to found attribute, or 0 if not found. xml_attribute<Ch> *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const { if (name) { if (name_size == 0) name_size = internal::measure(name); for (xml_attribute<Ch> *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) return attribute; return 0; } else return m_first_attribute ? m_last_attribute : 0; } /////////////////////////////////////////////////////////////////////////// // Node modification //! Sets type of node. //! \param type Type of node to set. void type(node_type type) { m_type = type; } /////////////////////////////////////////////////////////////////////////// // Node manipulation //! Prepends a new child node. //! The prepended child becomes the first child, and all existing children are moved one position back. //! \param child Node to prepend. void prepend_node(xml_node<Ch> *child) { assert(child && !child->parent() && child->type() != node_document); if (first_node()) { child->m_next_sibling = m_first_node; m_first_node->m_prev_sibling = child; } else { child->m_next_sibling = 0; m_last_node = child; } m_first_node = child; child->m_parent = this; child->m_prev_sibling = 0; } //! Appends a new child node. //! The appended child becomes the last child. //! \param child Node to append. void append_node(xml_node<Ch> *child) { assert(child && !child->parent() && child->type() != node_document); if (first_node()) { child->m_prev_sibling = m_last_node; m_last_node->m_next_sibling = child; } else { child->m_prev_sibling = 0; m_first_node = child; } m_last_node = child; child->m_parent = this; child->m_next_sibling = 0; } //! Inserts a new child node at specified place inside the node. //! All children after and including the specified node are moved one position back. //! \param where Place where to insert the child, or 0 to insert at the back. //! \param child Node to insert. void insert_node(xml_node<Ch> *where, xml_node<Ch> *child) { assert(!where || where->parent() == this); assert(child && !child->parent() && child->type() != node_document); if (where == m_first_node) prepend_node(child); else if (where == 0) append_node(child); else { child->m_prev_sibling = where->m_prev_sibling; child->m_next_sibling = where; where->m_prev_sibling->m_next_sibling = child; where->m_prev_sibling = child; child->m_parent = this; } } //! Removes first child node. //! If node has no children, behaviour is undefined. //! Use first_node() to test if node has children. void remove_first_node() { assert(first_node()); xml_node<Ch> *child = m_first_node; m_first_node = child->m_next_sibling; if (child->m_next_sibling) child->m_next_sibling->m_prev_sibling = 0; else m_last_node = 0; child->m_parent = 0; } //! Removes last child of the node. //! If node has no children, behaviour is undefined. //! Use first_node() to test if node has children. void remove_last_node() { assert(first_node()); xml_node<Ch> *child = m_last_node; if (child->m_prev_sibling) { m_last_node = child->m_prev_sibling; child->m_prev_sibling->m_next_sibling = 0; } else m_first_node = 0; child->m_parent = 0; } //! Removes specified child from the node // \param where Pointer to child to be removed. void remove_node(xml_node<Ch> *where) { assert(where && where->parent() == this); assert(first_node()); if (where == m_first_node) remove_first_node(); else if (where == m_last_node) remove_last_node(); else { where->m_prev_sibling->m_next_sibling = where->m_next_sibling; where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; where->m_parent = 0; } } //! Removes all child nodes (but not attributes). void remove_all_nodes() { for (xml_node<Ch> *node = first_node(); node; node = node->m_next_sibling) node->m_parent = 0; m_first_node = 0; } //! Prepends a new attribute to the node. //! \param attribute Attribute to prepend. void prepend_attribute(xml_attribute<Ch> *attribute) { assert(attribute && !attribute->parent()); if (first_attribute()) { attribute->m_next_attribute = m_first_attribute; m_first_attribute->m_prev_attribute = attribute; } else { attribute->m_next_attribute = 0; m_last_attribute = attribute; } m_first_attribute = attribute; attribute->m_parent = this; attribute->m_prev_attribute = 0; } //! Appends a new attribute to the node. //! \param attribute Attribute to append. void append_attribute(xml_attribute<Ch> *attribute) { assert(attribute && !attribute->parent()); if (first_attribute()) { attribute->m_prev_attribute = m_last_attribute; m_last_attribute->m_next_attribute = attribute; } else { attribute->m_prev_attribute = 0; m_first_attribute = attribute; } m_last_attribute = attribute; attribute->m_parent = this; attribute->m_next_attribute = 0; } //! Inserts a new attribute at specified place inside the node. //! All attributes after and including the specified attribute are moved one position back. //! \param where Place where to insert the attribute, or 0 to insert at the back. //! \param attribute Attribute to insert. void insert_attribute(xml_attribute<Ch> *where, xml_attribute<Ch> *attribute) { assert(!where || where->parent() == this); assert(attribute && !attribute->parent()); if (where == m_first_attribute) prepend_attribute(attribute); else if (where == 0) append_attribute(attribute); else { attribute->m_prev_attribute = where->m_prev_attribute; attribute->m_next_attribute = where; where->m_prev_attribute->m_next_attribute = attribute; where->m_prev_attribute = attribute; attribute->m_parent = this; } } //! Removes first attribute of the node. //! If node has no attributes, behaviour is undefined. //! Use first_attribute() to test if node has attributes. void remove_first_attribute() { assert(first_attribute()); xml_attribute<Ch> *attribute = m_first_attribute; if (attribute->m_next_attribute) { attribute->m_next_attribute->m_prev_attribute = 0; } else m_last_attribute = 0; attribute->m_parent = 0; m_first_attribute = attribute->m_next_attribute; } //! Removes last attribute of the node. //! If node has no attributes, behaviour is undefined. //! Use first_attribute() to test if node has attributes. void remove_last_attribute() { assert(first_attribute()); xml_attribute<Ch> *attribute = m_last_attribute; if (attribute->m_prev_attribute) { attribute->m_prev_attribute->m_next_attribute = 0; m_last_attribute = attribute->m_prev_attribute; } else m_first_attribute = 0; attribute->m_parent = 0; } //! Removes specified attribute from node. //! \param where Pointer to attribute to be removed. void remove_attribute(xml_attribute<Ch> *where) { assert(first_attribute() && where->parent() == this); if (where == m_first_attribute) remove_first_attribute(); else if (where == m_last_attribute) remove_last_attribute(); else { where->m_prev_attribute->m_next_attribute = where->m_next_attribute; where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; where->m_parent = 0; } } //! Removes all attributes of node. void remove_all_attributes() { for (xml_attribute<Ch> *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) attribute->m_parent = 0; m_first_attribute = 0; } private: /////////////////////////////////////////////////////////////////////////// // Restrictions // No copying xml_node(const xml_node &); void operator =(const xml_node &); /////////////////////////////////////////////////////////////////////////// // Data members // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. // This is required for maximum performance, as it allows the parser to omit initialization of // unneded/redundant values. // // The rules are as follows: // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage node_type m_type; // Type of node; always valid xml_node<Ch> *m_first_node; // Pointer to first child node, or 0 if none; always valid xml_node<Ch> *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero xml_attribute<Ch> *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid xml_attribute<Ch> *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero xml_node<Ch> *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero xml_node<Ch> *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero }; /////////////////////////////////////////////////////////////////////////// // XML document //! This class represents root of the DOM hierarchy. //! It is also an xml_node and a memory_pool through public inheritance. //! Use parse() function to build a DOM tree from a zero-terminated XML text string. //! parse() function allocates memory for nodes and attributes by using functions of xml_document, //! which are inherited from memory_pool. //! To access root node of the document, use the document itself, as if it was an xml_node. //! \param Ch Character type to use. template<class Ch = char> class xml_document: public xml_node<Ch>, public memory_pool<Ch> { public: //! Constructs empty XML document xml_document() : xml_node<Ch>(node_document) { } //! Parses zero-terminated XML string according to given flags. //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. //! The string must persist for the lifetime of the document. //! In case of error, rapidxml::parse_error exception will be thrown. //! <br><br> //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. //! Make sure that data is zero-terminated. //! <br><br> //! Document can be parsed into multiple times. //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. template<int Flags> void parse(Ch *text) { assert(text); // Remove current contents this->remove_all_nodes(); this->remove_all_attributes(); // Parse BOM, if any parse_bom<Flags>(text); // Parse children while (1) { // Skip whitespace before node skip<whitespace_pred, Flags>(text); if (*text == 0) break; // Parse and append new child if (*text == Ch('<')) { ++text; // Skip '<' if (xml_node<Ch> *node = parse_node<Flags>(text)) this->append_node(node); } else RAPIDXML_PARSE_ERROR("expected <", text); } } //! Clears the document by deleting all nodes and clearing the memory pool. //! All nodes owned by document pool are destroyed. void clear()

2012-08-31

Client端口测试ICOP的性能

/////////////////////////////////////////////////////////////////// // 工作者线程: 为IOCP请求服务的工作者线程 // 也就是每当完成端口上出现了完成数据包,就将之取出来进行处理的线程 /////////////////////////////////////////////////////////////////// DWORD WINAPI CIOCPModel::_WorkerThread(LPVOID lpParam) { THREADPARAMS_WORKER* pParam = (THREADPARAMS_WORKER*)lpParam; CIOCPModel* pIOCPModel = (CIOCPModel*)pParam->pIOCPModel; int nThreadNo = (int)pParam->nThreadNo; pIOCPModel->_ShowMessage("工作者线程启动,ID: %d.",nThreadNo); OVERLAPPED *pOverlapped = NULL; PER_SOCKET_CONTEXT *pSocketContext = NULL; DWORD dwBytesTransfered = 0; // 循环处理请求,知道接收到Shutdown信息为止 while (WAIT_OBJECT_0 != WaitForSingleObject(pIOCPModel->m_hShutdownEvent, 0)) { BOOL bReturn = GetQueuedCompletionStatus( pIOCPModel->m_hIOCompletionPort, &dwBytesTransfered;, (PULONG_PTR)&pSocketContext;, &pOverlapped;, INFINITE); // 如果收到的是退出标志,则直接退出 if ( EXIT_CODE==(DWORD)pSocketContext ) { break; } // 判断是否出现了错误 if( !bReturn ) { DWORD dwErr = GetLastError(); // 显示一下提示信息 if( !pIOCPModel->HandleError( pSocketContext,dwErr ) ) { break; } continue; } else { // 读取传入的参数 PER_IO_CONTEXT* pIoContext = CONTAINING_RECORD(pOverlapped, PER_IO_CONTEXT, m_Overlapped); // 判断是否有客户端断开了 if((0 == dwBytesTransfered) && ( RECV_POSTED==pIoContext->m_OpType || SEND_POSTED==pIoContext->m_OpType)) { pIOCPModel->_ShowMessage( _T("客户端 %s:%d 断开连接."),inet_ntoa(pSocketContext->m_ClientAddr.sin_addr), ntohs(pSocketContext->m_ClientAddr.sin_port) ); // 释放掉对应的资源 pIOCPModel->_RemoveContext( pSocketContext ); continue; } else { switch( pIoContext->m_OpType ) { // Accept case ACCEPT_POSTED: { // 为了增加代码可读性,这里用专门的_DoAccept函数进行处理连入请求 pIOCPModel->_DoAccpet( pSocketContext, pIoContext ); } break; // RECV case RECV_POSTED: { // 为了增加代码可读性,这里用专门的_DoRecv函数进行处理接收请求 pIOCPModel->_DoRecv( pSocketContext,pIoContext ); } break; // SEND // 这里略过不写了,要不代码太多了,不容易理解,Send操作相对来讲简单一些 case SEND_POSTED: { } break; default: // 不应该执行到这里 TRACE(_T("_WorkThread中的 pIoContext->m_OpType 参数异常.\n")); break; } //switch }//if }//if }//while TRACE(_T("工作者线程 %d 号退出.\n"),nThreadNo); // 释放线程参数 RELEASE(lpParam); return 0; }

2012-08-31

IOCPExample_By_PiggyXP

IOCP的完成端口实现实例 /////////////////////////////////////////////////////////////////// // 工作者线程: 为IOCP请求服务的工作者线程 // 也就是每当完成端口上出现了完成数据包,就将之取出来进行处理的线程 /////////////////////////////////////////////////////////////////// DWORD WINAPI CIOCPModel::_WorkerThread(LPVOID lpParam) { THREADPARAMS_WORKER* pParam = (THREADPARAMS_WORKER*)lpParam; CIOCPModel* pIOCPModel = (CIOCPModel*)pParam->pIOCPModel; int nThreadNo = (int)pParam->nThreadNo; pIOCPModel->_ShowMessage("工作者线程启动,ID: %d.",nThreadNo); OVERLAPPED *pOverlapped = NULL; PER_SOCKET_CONTEXT *pSocketContext = NULL; DWORD dwBytesTransfered = 0; // 循环处理请求,知道接收到Shutdown信息为止 while (WAIT_OBJECT_0 != WaitForSingleObject(pIOCPModel->m_hShutdownEvent, 0)) { BOOL bReturn = GetQueuedCompletionStatus( pIOCPModel->m_hIOCompletionPort, &dwBytesTransfered;, (PULONG_PTR)&pSocketContext;, &pOverlapped;, INFINITE); // 如果收到的是退出标志,则直接退出 if ( EXIT_CODE==(DWORD)pSocketContext ) { break; } // 判断是否出现了错误 if( !bReturn ) { DWORD dwErr = GetLastError(); // 显示一下提示信息 if( !pIOCPModel->HandleError( pSocketContext,dwErr ) ) { break; } continue; } else { // 读取传入的参数 PER_IO_CONTEXT* pIoContext = CONTAINING_RECORD(pOverlapped, PER_IO_CONTEXT, m_Overlapped); // 判断是否有客户端断开了 if((0 == dwBytesTransfered) && ( RECV_POSTED==pIoContext->m_OpType || SEND_POSTED==pIoContext->m_OpType)) { pIOCPModel->_ShowMessage( _T("客户端 %s:%d 断开连接."),inet_ntoa(pSocketContext->m_ClientAddr.sin_addr), ntohs(pSocketContext->m_ClientAddr.sin_port) ); // 释放掉对应的资源 pIOCPModel->_RemoveContext( pSocketContext ); continue; } else { switch( pIoContext->m_OpType ) { // Accept case ACCEPT_POSTED: { // 为了增加代码可读性,这里用专门的_DoAccept函数进行处理连入请求 pIOCPModel->_DoAccpet( pSocketContext, pIoContext ); } break; // RECV case RECV_POSTED: { // 为了增加代码可读性,这里用专门的_DoRecv函数进行处理接收请求 pIOCPModel->_DoRecv( pSocketContext,pIoContext ); } break; // SEND // 这里略过不写了,要不代码太多了,不容易理解,Send操作相对来讲简单一些 case SEND_POSTED: { } break; default: // 不应该执行到这里 TRACE(_T("_WorkThread中的 pIoContext->m_OpType 参数异常.\n")); break; } //switch }//if }//if }//while TRACE(_T("工作者线程 %d 号退出.\n"),nThreadNo); // 释放线程参数 RELEASE(lpParam); return 0; }

2012-08-31

高质量C++/C编程指南

高质量C++C编程指南.pdf << Back to man.ChinaUnix.net 高质量C++/C编程指南 文件状态 [ ] 草稿文件 [√] 正式文件 [ ] 更改正式文件 文件标识: 当前版本: 1.0 作 者: 林锐 博士 完成日期:

2012-08-31

DataGrid数据刷新及选择.rar

Datagrid数据的绑定、数据删除修改不卡顿 选择项失去焦点颜色不褪却,是一个很好的学习研究的小Demo,可以随机删除刷新,可以支持1w条以上的数据显示

2020-11-01

C#的Wpf实现K线图_.zip

股票K线软件,C# ,wpf实现,上手快,容易学习,编译初学者参考学习,从中可以获得很多收益,可以做为股票市场入门学习资料。

2020-05-16

IndentGuide v14 (VS 2010).rar

这款插件的感化是给代码块增长对齐线,以标识匹配的花括号,让法度猿很轻易的找到对应的语句块。

2019-07-08

AutoIt-v3-setup.exe

Au3安装包,提供用户安装Au3脚本

2016-08-16

Au3的C++实例

Au3的C++开发实例,帮助初学者学些Au3界面控制脚本语言

2016-08-16

分布式操作系统

分布式操作系统,介绍当下最流行的操作系统,有很好的学习价值

2014-04-28

让技术人员看得懂的流程中文版

让技术人员看得懂的流程的中文版浅显易懂的从新审视面向对象开发流程,以及从需求到发布的整个流程的介绍,

2014-04-28

让技术人员看得懂的流程

让技术人员看得懂的流程,通过浅显的语言描述开发过程。

2014-04-08

100道面试题

从各个大公司中提炼出来的100道面试题,对于初入职场的人员有很大的帮助。

2014-04-08

卓有成效的程序员

卓有成效的程序员是讲述如何提高程序员工作效率的方法汇总,对工作效率提升很有意义

2014-04-04

构建高性能Web站点

介绍如何高效的搭建Web站点,有很多成功案例可以借鉴

2014-04-04

30天自制操作系统

自制操作系统,可以加深对操作系统的理解,便于编写高质量代码

2014-04-04

与孩子一起学编程

一本和孩子一起学习的编程书籍,做好孩子的启蒙教育

2014-04-04

JAVA并发编程实现

JAVA并发编程实现,提高JAVA的运行效率的书籍。

2014-04-04

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除