﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-~怪^_*兽~-随笔分类-互联网络</title><link>http://cppblog.com/ldcsaa/category/19110.html</link><description>虚荣锁身躯 心灵给酒醉 脆弱人类 懒问何为对
&lt;br&gt;&lt;font color="#CC0000"&gt;（怪兽乐园Q群：&lt;a target="_blank" href="http://jq.qq.com/?_wv=1027&amp;k=28lgXyB"&gt;&lt;strong&gt;75375912&lt;/strong&gt;&lt;/a&gt;）&lt;/font&gt;</description><language>zh-cn</language><lastBuildDate>Tue, 18 Jul 2017 06:24:46 GMT</lastBuildDate><pubDate>Tue, 18 Jul 2017 06:24:46 GMT</pubDate><ttl>60</ttl><item><title>高性能 TCP &amp; HTTP 通信框架 HP-Socket v4.3.1</title><link>http://www.cppblog.com/ldcsaa/archive/2017/07/17/215112.html</link><dc:creator>~怪^_*兽~</dc:creator><author>~怪^_*兽~</author><pubDate>Mon, 17 Jul 2017 02:03:00 GMT</pubDate><guid>http://www.cppblog.com/ldcsaa/archive/2017/07/17/215112.html</guid><wfw:comment>http://www.cppblog.com/ldcsaa/comments/215112.html</wfw:comment><comments>http://www.cppblog.com/ldcsaa/archive/2017/07/17/215112.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ldcsaa/comments/commentRss/215112.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ldcsaa/services/trackbacks/215112.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架，包含服务端组件、客户端组件和 Agent 组件，广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统，提供 C/C++、C#、Delphi、E（易语言）、Java、Python 等编程语言接口。HP-Socket 对通信层实现完全封装，应用程序不必关注通信层的任何细节；HP-Socket 提供基于事件通知模型的 API 接口，能非常简单高效地整合到新旧应用程序中。&nbsp;&nbsp;<a href='http://www.cppblog.com/ldcsaa/archive/2017/07/17/215112.html'>阅读全文</a><img src ="http://www.cppblog.com/ldcsaa/aggbug/215112.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ldcsaa/" target="_blank">~怪^_*兽~</a> 2017-07-17 10:03 <a href="http://www.cppblog.com/ldcsaa/archive/2017/07/17/215112.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.3</title><link>http://www.cppblog.com/ldcsaa/archive/2017/01/18/214607.html</link><dc:creator>~怪^_*兽~</dc:creator><author>~怪^_*兽~</author><pubDate>Wed, 18 Jan 2017 06:24:00 GMT</pubDate><guid>http://www.cppblog.com/ldcsaa/archive/2017/01/18/214607.html</guid><wfw:comment>http://www.cppblog.com/ldcsaa/comments/214607.html</wfw:comment><comments>http://www.cppblog.com/ldcsaa/archive/2017/01/18/214607.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ldcsaa/comments/commentRss/214607.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ldcsaa/services/trackbacks/214607.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架，包含服务端组件、客户端组件和 Agent 组件，广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统，提供 C/C++、C#、Delphi、E（易语言）、Java、Python 等编程语言接口。HP-Socket 对通信层实现完全封装，应用程序不必关注通信层的任何细节；HP-Socket 提供基于事件通知模型的 API 接口，能非常简单高效地整合到新旧应用程序中。&nbsp;&nbsp;<a href='http://www.cppblog.com/ldcsaa/archive/2017/01/18/214607.html'>阅读全文</a><img src ="http://www.cppblog.com/ldcsaa/aggbug/214607.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ldcsaa/" target="_blank">~怪^_*兽~</a> 2017-01-18 14:24 <a href="http://www.cppblog.com/ldcsaa/archive/2017/01/18/214607.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>高性能 TCP &amp; UDP 通信框架 HP-Socket v4.1.2</title><link>http://www.cppblog.com/ldcsaa/archive/2016/12/27/214560.html</link><dc:creator>~怪^_*兽~</dc:creator><author>~怪^_*兽~</author><pubDate>Tue, 27 Dec 2016 11:21:00 GMT</pubDate><guid>http://www.cppblog.com/ldcsaa/archive/2016/12/27/214560.html</guid><wfw:comment>http://www.cppblog.com/ldcsaa/comments/214560.html</wfw:comment><comments>http://www.cppblog.com/ldcsaa/archive/2016/12/27/214560.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ldcsaa/comments/commentRss/214560.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ldcsaa/services/trackbacks/214560.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架，包含服务端组件、客户端组件和 Agent 组件，广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统，提供 C/C++、C#、Delphi、E（易语言）、Java、Python 等编程语言接口。HP-Socket 对通信层实现完全封装，应用程序不必关注通信层的任何细节；HP-Socket 提供基于事件通知模型的 API 接口，能非常简单高效地整合到新旧应用程序中。&nbsp;&nbsp;<a href='http://www.cppblog.com/ldcsaa/archive/2016/12/27/214560.html'>阅读全文</a><img src ="http://www.cppblog.com/ldcsaa/aggbug/214560.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ldcsaa/" target="_blank">~怪^_*兽~</a> 2016-12-27 19:21 <a href="http://www.cppblog.com/ldcsaa/archive/2016/12/27/214560.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>高性能 TCP &amp; UDP 通信框架 HP-Socket v3.3.1 正式发布</title><link>http://www.cppblog.com/ldcsaa/archive/2015/02/03/209711.html</link><dc:creator>~怪^_*兽~</dc:creator><author>~怪^_*兽~</author><pubDate>Mon, 02 Feb 2015 19:07:00 GMT</pubDate><guid>http://www.cppblog.com/ldcsaa/archive/2015/02/03/209711.html</guid><wfw:comment>http://www.cppblog.com/ldcsaa/comments/209711.html</wfw:comment><comments>http://www.cppblog.com/ldcsaa/archive/2015/02/03/209711.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ldcsaa/comments/commentRss/209711.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ldcsaa/services/trackbacks/209711.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: HP-Socket 是一套通用的高性能 TCP/UDP 通信框架，包含服务端组件、客户端组件和 Agent 组件，广泛适用于各种不同应用场景的 TCP/UDP 通信系统，提供 C/C++、C#、Delphi、E（易语言）、Java、Python 等编程语言接口。HP-Socket 对通信层实现完全封装，应用程序不必关注通信层的任何细节；HP-Socket 提供基于事件通知模型的 API 接口，能非常简单高效地整合到新旧应用程序中。&nbsp;&nbsp;<a href='http://www.cppblog.com/ldcsaa/archive/2015/02/03/209711.html'>阅读全文</a><img src ="http://www.cppblog.com/ldcsaa/aggbug/209711.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ldcsaa/" target="_blank">~怪^_*兽~</a> 2015-02-03 03:07 <a href="http://www.cppblog.com/ldcsaa/archive/2015/02/03/209711.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>高性能 TCP &amp; UDP 通信框架 HP-Socket v3.2.2 正式发布</title><link>http://www.cppblog.com/ldcsaa/archive/2014/07/08/207580.html</link><dc:creator>~怪^_*兽~</dc:creator><author>~怪^_*兽~</author><pubDate>Tue, 08 Jul 2014 14:33:00 GMT</pubDate><guid>http://www.cppblog.com/ldcsaa/archive/2014/07/08/207580.html</guid><wfw:comment>http://www.cppblog.com/ldcsaa/comments/207580.html</wfw:comment><comments>http://www.cppblog.com/ldcsaa/archive/2014/07/08/207580.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ldcsaa/comments/commentRss/207580.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ldcsaa/services/trackbacks/207580.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: HP-Socket 是一套通用的高性能 TCP/UDP 通信框架，包含服务端组件、客户端组件和 Agent 组件，广泛适用于各种不同应用场景的 TCP/UDP 通信系统，提供 C/C++、C#、Delphi、E（易语言）、Java、Python 等编程语言接口。HP-Socket 对通信层实现完全封装，应用程序不必关注通信层的任何细节；HP-Socket 提供基于事件通知模型的 API 接口，能非常简单高效地整合到新旧应用程序中。&nbsp;&nbsp;<a href='http://www.cppblog.com/ldcsaa/archive/2014/07/08/207580.html'>阅读全文</a><img src ="http://www.cppblog.com/ldcsaa/aggbug/207580.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ldcsaa/" target="_blank">~怪^_*兽~</a> 2014-07-08 22:33 <a href="http://www.cppblog.com/ldcsaa/archive/2014/07/08/207580.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【★更新★】高性能 Windows C++ 通用组件 VC-Logger v2.0.3 正式发布</title><link>http://www.cppblog.com/ldcsaa/archive/2013/06/14/200961.html</link><dc:creator>~怪^_*兽~</dc:creator><author>~怪^_*兽~</author><pubDate>Thu, 13 Jun 2013 17:16:00 GMT</pubDate><guid>http://www.cppblog.com/ldcsaa/archive/2013/06/14/200961.html</guid><wfw:comment>http://www.cppblog.com/ldcsaa/comments/200961.html</wfw:comment><comments>http://www.cppblog.com/ldcsaa/archive/2013/06/14/200961.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ldcsaa/comments/commentRss/200961.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ldcsaa/services/trackbacks/200961.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: VC-Logger 是一个简单易用的 C++ 程序通用日子组件。设计时着重考虑三个方面：功能、可用性和性能。为了让大家能更方便的学习 VC-Logger，特此精心制作了几个测试用例：TestGUILogger（GUI 版本测试用例 / 静态加载）、TestDynamicLogger（GUI 版本测试用例 / 动态加载）、TestConsoleLogger（Console 版本测试用例 / 静态加载）。&nbsp;&nbsp;<a href='http://www.cppblog.com/ldcsaa/archive/2013/06/14/200961.html'>阅读全文</a><img src ="http://www.cppblog.com/ldcsaa/aggbug/200961.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ldcsaa/" target="_blank">~怪^_*兽~</a> 2013-06-14 01:16 <a href="http://www.cppblog.com/ldcsaa/archive/2013/06/14/200961.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>高性能 Windows Socket 服务端与客户端组件（HP-Socket v2.1.1 即将发布）</title><link>http://www.cppblog.com/ldcsaa/archive/2013/04/15/199410.html</link><dc:creator>~怪^_*兽~</dc:creator><author>~怪^_*兽~</author><pubDate>Mon, 15 Apr 2013 00:18:00 GMT</pubDate><guid>http://www.cppblog.com/ldcsaa/archive/2013/04/15/199410.html</guid><wfw:comment>http://www.cppblog.com/ldcsaa/comments/199410.html</wfw:comment><comments>http://www.cppblog.com/ldcsaa/archive/2013/04/15/199410.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/ldcsaa/comments/commentRss/199410.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ldcsaa/services/trackbacks/199410.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 自从本座发表了两篇关于 Windows Socket 通信组件实现的文章后，收到不少读者的留言，希望能分享完整的源代码。此时，本座不敢弊帚自珍。特意在此提供服务端组件和客户端组件的完整代码。另外，为便于读者学习和理解，花了一点点时间精心制作了两个测试用例，一个用于功能测试（TestEcho），另一个用于性能测试（TestEcho-PFM）。读者可以通过这两个测试用例入手，迅速掌握组件的使用方法。希望对大家有所帮助，谢谢 ~ ^_^ ~&nbsp;&nbsp;<a href='http://www.cppblog.com/ldcsaa/archive/2013/04/15/199410.html'>阅读全文</a><img src ="http://www.cppblog.com/ldcsaa/aggbug/199410.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ldcsaa/" target="_blank">~怪^_*兽~</a> 2013-04-15 08:18 <a href="http://www.cppblog.com/ldcsaa/archive/2013/04/15/199410.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【★更新★】发布本人所有博客文章中涉及的代码与工具（大部分是C++和Java）</title><link>http://www.cppblog.com/ldcsaa/archive/2013/03/29/198918.html</link><dc:creator>~怪^_*兽~</dc:creator><author>~怪^_*兽~</author><pubDate>Fri, 29 Mar 2013 03:17:00 GMT</pubDate><guid>http://www.cppblog.com/ldcsaa/archive/2013/03/29/198918.html</guid><wfw:comment>http://www.cppblog.com/ldcsaa/comments/198918.html</wfw:comment><comments>http://www.cppblog.com/ldcsaa/archive/2013/03/29/198918.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ldcsaa/comments/commentRss/198918.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ldcsaa/services/trackbacks/198918.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 为了更方便地管理博文中涉及的各种代码与工具资源，现在把这些资源迁移到 Google Code 中，有兴趣者可前往下载。&nbsp;&nbsp;<a href='http://www.cppblog.com/ldcsaa/archive/2013/03/29/198918.html'>阅读全文</a><img src ="http://www.cppblog.com/ldcsaa/aggbug/198918.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ldcsaa/" target="_blank">~怪^_*兽~</a> 2013-03-29 11:17 <a href="http://www.cppblog.com/ldcsaa/archive/2013/03/29/198918.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>发布本人所有博客文章中涉及的代码与工具（大部分是C++和Java）</title><link>http://www.cppblog.com/ldcsaa/archive/2013/01/06/196132.html</link><dc:creator>~怪^_*兽~</dc:creator><author>~怪^_*兽~</author><pubDate>Sun, 06 Jan 2013 15:05:00 GMT</pubDate><guid>http://www.cppblog.com/ldcsaa/archive/2013/01/06/196132.html</guid><wfw:comment>http://www.cppblog.com/ldcsaa/comments/196132.html</wfw:comment><comments>http://www.cppblog.com/ldcsaa/archive/2013/01/06/196132.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/ldcsaa/comments/commentRss/196132.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ldcsaa/services/trackbacks/196132.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;（为了能让更多人看到，再发一次旧文，望见谅）<span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;"><br /></span>&nbsp;&nbsp;&nbsp;为了更方便地管理博文中涉及的各种代码与工具资源，现在把这些资源迁移到 Google Code 中，有兴趣者可前往下载。</p><hr /><p><span style="font-size: 18pt;"><strong>C++</strong></span></p><p><strong>1、《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/06/13/2546551.html">高性能 Windows Socket 服务端与客户端组件（源代码及测试用例下载）</a>》</strong></p><p><strong>&nbsp; &nbsp; 《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/26/2367409.html">基于 IOCP 的通用异步 Windows Socket TCP 高性能服务端组件的设计与实现</a>》</strong></p><p><strong>&nbsp; &nbsp; 《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/15/2351756.html">通用异步 Windows Socket TCP 客户端组件的设计与实现</a>》</strong></p><p>　　摘要：编写 Windows Socket TCP 客户端其实并不困难，Windows 提供了6种 I/O 通信模型供大家选择。但本座看过很多客户端程序都把 Socket 通信和业务逻辑混在一起，剪不断理还乱。每个程序都 Copy / Parse 类似的代码再进行修改，实在有点情何以堪。因此本座利用一些闲暇时光写了一个基于 IOCP 的通用异步 Windows Socket TCP 高性能服务端组件和一个通用异步 Windows Socket TCP 客户端组件供各位看官参详参详，希望能激发下大家的灵感。</p><p>　　资源下载地址：<a href="http://ldcsaa.googlecode.com/files/socket_server_and_client.zip">http://ldcsaa.googlecode.com/files/socket_server_and_client.zip</a></p><p>&nbsp;</p><p><strong>2、《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/06/28/2560619.html">Windows C++ 应用程序通用日志组件（组件及测试程序下载）</a>》</strong></p><p>　　摘要：编写一个通用的日志组件应该着重考虑三个方面：功能、可用性和性能。下面，本座详细说明在设计日志组件时对这些方面问题的考虑：</p><ul><li style="list-style-type: none;"><ul><li>功能：本日志组件的目的是满足大多数应用程序记录日志的需求 &#8212;&#8212; 把日志输出到文件或发送到应用程序中，并不提供一些复杂但不常用的功能</li><li>可用性：本日志组件着重考虑了可用性，尽量让使用者用起来觉得简便、舒心</li><li>性能：性能是组件是否值得使用的硬指标，本组件从设计到编码的过程都尽量考虑到性能优化</li></ul></li></ul><p>　　资源下载地址：<a href="http://ldcsaa.googlecode.com/files/VC_Logger.zip">http://ldcsaa.googlecode.com/files/VC_Logger.zip</a></p><p>&nbsp;</p><p><strong>3、《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/18/2356638.html">如何养成良好的 C++ 编程习惯（一）&#8212;&#8212; 内存管理</a>》</strong></p><p>　　摘要：说起 C/C++ 的内存管理似乎令人望而生畏，满屏的 new / delete / malloc / free，OutPut 窗口无尽的 Memory Leak 警告，程序诡异的 0X00000004 指针异常，仿佛回到那一年我们一起哭过的日子，你 Hold 得住吗？其实，现实并没有你想的那么糟糕。只要你付出一点点，花一点点心思，没错！就一点点而已 &#8212;&#8212;&nbsp;<strong>用 C++ 类封装内存访问</strong>，就会解决你大部分的烦恼，让你受益终身。以 Windows 程序为例，主要有以下几种内存管理方式：</p><ul><li style="list-style-type: none;"><ul><li><strong>虚拟内存</strong>（Virtual Memory）</li><li><strong>默认堆</strong>和<strong>私有堆</strong>（Process Heap &amp; Private Heap）</li><li><strong>内存映射文件</strong>（File Mapping）</li><li><strong>进程堆栈</strong>（Heap，其实就是用 malloc()&nbsp;或&nbsp;默认的 new 操作符在 Process Heap 里一小块一小块地割肉 ^_^）</li><li><strong>栈</strong>（Stack，内存由调用者或被调用者自动管理）</li></ul></li></ul><p>　　资源下载地址：<a href="http://ldcsaa.googlecode.com/files/socket_server_and_client.zip">http://ldcsaa.googlecode.com/files/socket_server_and_client.zip</a>&nbsp;（源代码在 Common/Src 目录中）</p><p>&nbsp;</p><p><strong>4、《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/13/2348588.html">实现 Win32 程序的消息映射宏（类似 MFC ）</a>》</strong></p><p>　　摘要：对于消息映射宏，不用多说了，用过 MFC 的人都很清楚。但目前有不少程序由于各种原因并没有使用 MFC，所以本帖讨论一下如何在 Win32 程序中实现类似MFC的消息映射宏。其实 Windows 的头文件 &#8220;WindowsX.h&#8221;（注意：不是&#8220;Windows.h&#8221;） 中提供了一些有用的宏来帮助我们实现消息映射。本座是也基于这个头文件实现消息映射。</p><p>　　资源下载地址：<a href="http://ldcsaa.googlecode.com/files/socket_server_and_client.zip">http://ldcsaa.googlecode.com/files/socket_server_and_client.zip</a>&nbsp;（源代码在 Common/Src/Win32Helper.h 文件中）</p><p>&nbsp;</p><p><strong>5、《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/12/2348398.html">用宏实现 C++ Singleton 模式</a>》</strong></p><p>　　摘要：Singleton 设计模式应用非常广泛，实现起来也很简单，无非是私有化若干个构造函数，&#8220;operator =&#8221; 操作符，以及提供一个静态的创建和销毁方法。但是对每个类都写这些雷同的代码是本座不能容忍的，因此，本座使用宏把整个 Singleton 模式封装起来，无论是类的定义还是类的使用的极其简单。</p><p>　　资源下载地址：<a href="http://ldcsaa.googlecode.com/files/socket_server_and_client.zip">http://ldcsaa.googlecode.com/files/socket_server_and_client.zip</a>&nbsp;（源代码在 Common/Src/Singleton.h 文件中）</p><p>&nbsp;</p><p><strong>6、《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/12/2348302.html">C++ 封装私有堆（Private Heap）</a>》</strong></p><p>　　摘要：Private Heap 是 Windows 提供的一种内存内存机制，对于那些需要频繁分配和释放动态内存的应用程序来说，Private Heap 是提高应用程序性能的一大法宝，使用它能降低 new / malloc 的调用排队竞争以及内存空洞。</p><p>　　资源下载地址：<a href="http://ldcsaa.googlecode.com/files/socket_server_and_client.zip">http://ldcsaa.googlecode.com/files/socket_server_and_client.zip</a>&nbsp;（源代码在 Common/Src/PrivateHeap.h 文件中）</p><p>&nbsp;</p><p><strong>7、《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/12/2348160.html">基于 crt debug 实现的 Windows 程序内存泄漏检测工具</a>》</strong></p><p>　　摘要：Windows 程序内存泄漏检测是一项十分重要的工作，基于 GUI 的应用程序通常在调试结束时也有内存泄漏报告，但这个报告的信息不全面，不能定位到产生泄漏的具体行号。其实自己实现一个内存泄漏检测工具是一件非常简单的事情，但看过网上写的很多例子，普遍存在两种问题：</p><ul><li style="list-style-type: none;"><ul><li>要么考虑不周全，一种环境下能用，而在另外一种环境下却不能很好工作，或者漏洞报告的输出方式不合理。</li><li>要么过于保守，例如：完全没有必要在 _malloc_dbg() 和 _free_dbg() 的调用前后用 CriticalSection 进行保护（跟踪一下多线程环境下 new 和 malloc 的代码就会明白）。</li></ul></li></ul><p>　　资源下载地址：<a href="http://ldcsaa.googlecode.com/files/socket_server_and_client.zip">http://ldcsaa.googlecode.com/files/socket_server_and_client.zip</a>&nbsp;（源代码在 Common/Src/debug/win32_crtdbg.h 文件中）</p><hr /><p><span style="font-size: 18pt;"><strong>Java</strong></span></p><p><strong>1、《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/11/22/2782205.html">Portal-Basic Java Web 应用开发框架 v2.6.2 发布（源码、示例及文档）</a>》</strong></p><p>　　摘要：Portal-Basic Web 应用开发框架（简称 Portal-Basic）是一套功能完备的高性能 Web 应用开发框架，内置可扩展的 MVC Web 基础架构和 DAO 访问接口（已内置 Hibernate、MyBatis 和 JDBC 支持），集成 Action拦截、Form Bean / Dao Bean / Spring Bean 装配、国际化、文件上传下载和缓存等基础 Web 应用组件，提供高效灵活的纯 Jsp/Servlet API 编程模型，完美整合 Spring，非常容易学习和使用。</p><p>　　资源下载地址：<a href="http://code.google.com/p/portal-basic/downloads/list">http://code.google.com/p/portal-basic/downloads/list</a></p><p>&nbsp;</p><p><strong>2、《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/06/25/2560481.html">用 Java 实现的日志切割清理工具（源代码下载）</a>》</strong></p><p>　　摘要：对于服务器的日常维护来说，日志清理是非常重要的事情，如果残留日志过多则严重浪费磁盘空间同时影响服务的性能。如果用手工方式进行清理，会花费太多时间，并且很多时候难以满足实际要求。例如：如何在每个星期六凌晨3点把超过2G大的日志文件进行切割，保留最新的100M日志记录？网上没有发现能满足本座要求的日志切割工具，因此花了一些闲暇时间自己写了一个。由于要在多个平台上使用，为了方便采用 Java 实现。本工具命名为&nbsp;<strong>LogCutter</strong>，主要有以下特点：</p><ul><li style="list-style-type: none;"><ul><li>支持 Linux、Mac 和 Windows 等所有常见操作系统平台</li><li>支持命令行交互式运行</li><li>支持后台非交互式运行（Linux/MAC 下使用 daemon 进程实现，Windows 用系统 Service 实现）</li><li>支持两种日志清理方式（删除日志文件或切割日志文件）</li><li>支持对 GB18030、UTF-8、UTF-16LE、UTF-16BE 等常用日志文件类型进行切割（不会发生切掉半个字符的情况）</li><li>高度可配置（程序执行周期、要删除的日志文件过期时间、要切割的日志文件阀值和保留大小等均可配置</li></ul></li></ul><p>　　资源下载地址：<a href="http://ldcsaa.googlecode.com/files/LogCutter.zip">http://ldcsaa.googlecode.com/files/LogCutter.zip</a></p><p>&nbsp;</p><p><strong>3、《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/23/2364036.html">通用 Java 文件上传和下载组件的设计与实现</a>》</strong></p><p>　　摘要：文件上传和下载是 Web 应用中的一个常见功能，相信各位或多或少都曾写过这方面相关的代码。但本座看过不少人在实现上传或下载功能时总是不知不觉间与程序的业务逻辑纠缠在一起，因此，当其他地方要用到这些功能时则无可避免地 Copy / Pase，然后再进行修改。这样丑陋不堪的做法导致非常容易出错不说，更大的问题是严重浪费时间不断做重复类似的工作，这是本座绝不能容忍的。哎，人生苦短啊，浪费时间在这些重复工作身上实在是不值得，何不把这些时间省出来打几盘罗马或者踢一场球？为此，本座利用一些闲暇之时光编写了一个通用的文件上传和文件下载组件，实现方法纯粹是基于 JSP，没有太高的技术难度，总之老少咸宜 ^_^。现把设计的思路和实现的方法向各位娓娓道来，希望能起到抛砖引玉的效果，激发大家的创造性思维。</p><p>　　资源下载地址：<a href="http://code.google.com/p/portal-basic/downloads/list">http://code.google.com/p/portal-basic/downloads/list</a>&nbsp;（作为 Portal-Basic 第一部分，代码在 com.bruce.util.http 包中）</p><p>&nbsp;</p><p><strong>4、《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/16/2353030.html">深度剖析：Java POJO Bean 对象与 Web Form 表单的自动装配</a>》</strong></p><p>　　摘要：时下很多 Web 框架 都实现了 Form 表单域与 Java 对象属性的自动装配功能，该功能确实非常有用，试想如果没这功能则势必到处冲积着 request.getParameter() 系列方法与类型转换方法的调用。重复代码量大，容易出错，同时又不美观，影响市容。现在的问题是，这些框架通过什么方法实现自动装配的？如果不用这些框架我们自己如何去实现呢？尤其对于那些纯 JSP/Servlet 应用，要是拥有自动装配功能该多好啊！本座深知各位之期盼，决定把自动装配的原理和实现方法娓娓道来。</p><p>　　资源下载地址：<a href="http://code.google.com/p/portal-basic/downloads/list">http://code.google.com/p/portal-basic/downloads/list</a>&nbsp;（作为 Portal-Basic 第一部分，代码在 com.bruce.util 包中）</p><p>&nbsp;</p><p><strong>5、《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/14/2350751.html">Linux 安装 MySQL / MySQL 主从备份</a>》</strong></p><p>　　资源下载地址：<a href="http://ldcsaa.googlecode.com/files/services.zip">http://ldcsaa.googlecode.com/files/services.zip<br /></a></p><hr /><p>&nbsp;<strong style="color: #800000;">原文出处：</strong><a href="http://www.cnblogs.com/ldcsaa" target="_blank"><strong>怪兽的博客</strong></a><strong>&nbsp;&nbsp;</strong><a href="http://weibo.com/u/1402935851" target="_blank"><strong>怪兽的微博</strong></a><strong>&nbsp;&nbsp;</strong><a href="http://qun.qq.com/#jointhegroup/gid/75375912" target="_blank"><strong>怪兽乐园Q群</strong></a></p><img src ="http://www.cppblog.com/ldcsaa/aggbug/196132.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ldcsaa/" target="_blank">~怪^_*兽~</a> 2013-01-06 23:05 <a href="http://www.cppblog.com/ldcsaa/archive/2013/01/06/196132.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows C++ 应用程序通用日志组件（组件及测试程序下载）</title><link>http://www.cppblog.com/ldcsaa/archive/2012/07/02/181117.html</link><dc:creator>~怪^_*兽~</dc:creator><author>~怪^_*兽~</author><pubDate>Mon, 02 Jul 2012 02:46:00 GMT</pubDate><guid>http://www.cppblog.com/ldcsaa/archive/2012/07/02/181117.html</guid><wfw:comment>http://www.cppblog.com/ldcsaa/comments/181117.html</wfw:comment><comments>http://www.cppblog.com/ldcsaa/archive/2012/07/02/181117.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/ldcsaa/comments/commentRss/181117.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ldcsaa/services/trackbacks/181117.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 主要功能<br>a) 把日志信息输出到指定文件<br>b) 每日生成一个日志文件<br>c) 对于 GUI 程序，可以把日志信息发送到指定窗口<br>d) 对于Console应用程序，可以把日志信息发往标准输出 (std::cout)<br>e) 支持 MBCS / UNICODE，Console / GUI 程序<br>f) 支持动态加载和静态加载日志组件 DLL<br>g) 支持 DEBUG/TRACE/INFO/WARN/ERROR/FATAL 等多个日志级别&nbsp;&nbsp;<a href='http://www.cppblog.com/ldcsaa/archive/2012/07/02/181117.html'>阅读全文</a><img src ="http://www.cppblog.com/ldcsaa/aggbug/181117.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ldcsaa/" target="_blank">~怪^_*兽~</a> 2012-07-02 10:46 <a href="http://www.cppblog.com/ldcsaa/archive/2012/07/02/181117.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>高性能 Windows Socket 服务端与客户端组件（源代码及测试用例下载）</title><link>http://www.cppblog.com/ldcsaa/archive/2012/06/15/178763.html</link><dc:creator>~怪^_*兽~</dc:creator><author>~怪^_*兽~</author><pubDate>Fri, 15 Jun 2012 01:40:00 GMT</pubDate><guid>http://www.cppblog.com/ldcsaa/archive/2012/06/15/178763.html</guid><wfw:comment>http://www.cppblog.com/ldcsaa/comments/178763.html</wfw:comment><comments>http://www.cppblog.com/ldcsaa/archive/2012/06/15/178763.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.cppblog.com/ldcsaa/comments/commentRss/178763.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ldcsaa/services/trackbacks/178763.html</trackback:ping><description><![CDATA[<p>　　自从本座发表了两篇关于 Windows Socket 通信组件实现的文章后，收到不少读者的留言，希望能分享完整的源代码。此时，本座不敢弊帚自珍。特意在此提供服务端组件和客户端组件的完整代码。另外，为便于读者学习和理解，花了一点点时间精心制作了两个测试用例，一个用于功能测试（TestEcho），另一个用于性能测试（TestEcho-PFM）。读者可以通过这两个测试用例入手，迅速掌握组件的使用方法。希望对大家有所帮助，谢谢 ~ ^_^ ~</p>
<p>&nbsp;</p>
<p>　　（<a href="http://files.cnblogs.com/ldcsaa/socket_server_%26_client.zip" data-mce-href="http://files.cnblogs.com/ldcsaa/socket_server_%26_client.zip">轻踩这里，你懂的 ^_*</a>）</p>
<p>&nbsp;</p>
<hr />

<p>&nbsp;</p>
<p><em><strong><span style="font-size: 14pt" data-mce-style="font-size: 14pt;">原文：《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/26/2367409.html" data-mce-href="http://www.cnblogs.com/ldcsaa/archive/2012/02/26/2367409.html">基于 IOCP 的通用异步 Windows Socket TCP 高性能服务端组件的设计与实现</a></span></strong></em><em><strong><span style="font-size: 14pt" data-mce-style="font-size: 14pt;">》</span></strong></em></p>
<p>&nbsp;</p>
<p><span style="font-size: 18pt" data-mce-style="font-size: 18pt;"><strong>设计概述</strong></span></p>
<p>　　服务端通信组件的设计是一项非常严谨的工作，其中性能、伸缩性和稳定性是必须考虑的硬性质量指标，若要把组件设计为通用组件提供给多种已知或未知的上层应用使用，则设计的难度更会大大增加，通用性、可用性和灵活性必须考虑在内。</p>
<p>　　现以一个基于 IOCP 的通用异步 Windows Socket TCP 服务端组件为例子，讲述其设计与实现相关的问题，希望能引发大家的思考，对大家日后开展相关类似工作时有所帮助。关于通用性、可用性、Socket 模型选型以及接口模型的设计等问题已经在本座前段时间发表的《<strong><a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/15/2351756.html" target="_blank" data-mce-href="http://www.cnblogs.com/ldcsaa/archive/2012/02/15/2351756.html">通用异步 Windows Socket TCP 客户端组件的设计与实现</a></strong>》中进行过阐述，此处就不再重复了。现在主要针对服务端通信组件的特点阐述设计其设计和实现相关的问题。</p>
<p>&nbsp;</p>
<p>　　<strong>一、线程结构</strong></p>
<p>　　与组件相关的线程有 3 种：使用者线程、Accept&nbsp; 线程和工作线程，其中后 2 种由组件实现。</p>
<ol><li style="list-style-type: none" data-mce-style="list-style-type: none;">
<ol><li><strong>使用者线程：</strong>通过调用 Start/Stop/Send 等组件方法操作组件的一个或多个线程，通常是程序的主线程或其它业务逻辑线程。</li><li><strong>Accept 线程：</strong>使用 AcceptEx() 接收客户端连接请求并创建 Client Socket 的线程，将其独立出来，实现为单独的线程将使组件的模块划分更清晰，更重要的是避免与业务逻辑和通信处理的相互影响。</li><li><strong>工作线程：</strong>使用 GetQueuedCompletionStatus() 监听网络事件并处理网络交互的多个线程，工作线程处理完网络事件后会向上层应用发送 OnAccept/OnSend/OnReceive 等组件通知。工作线程的数量可以根据实际情况之行设置（通常建议为：CPU&nbsp;Core Number&nbsp;* 2 + 2）。 </li></ol></li></ol>
<p>　　<strong>注意：</strong>如果上层应用在接收到 OnAccept/OnSend/OnReceive 这些组件通知时直接进行业务逻辑处理并在其中操作组件，则工作线程也成为了使用者线程。另外，如果要处理的业务逻辑比较耗时，上层应用应该在接收到组件通知后交由其他线程处理。</p>
<p>&nbsp;</p>
<p>　　<strong>二、性能</strong></p>
<p>　　组件采用 Windows 平台效率最高的&nbsp;IOCP Socket 通信模型，因此在通信接口的性能方面是有保证的，这里就不多说了。现在从组件的设计与实现的角度来来阐述性能的优化。组件在代码级别做了很多优化，一些看似多余或繁琐的代码其实都是为了性能服务；组件在设计方面主要采用了 2 中优化策略：缓存池和私有堆。</p>
<ol>
<ol><li><strong>缓存池：</strong>在通信的过程中，通常需要频繁的申请和释放内存缓冲区（TBufferObj）和 Socket 相关的结构体（TSocketObj），这会大大影响组件的性能，因此，组件为 TBufferObj 和 TSocketObj 建立了动态缓存池， 只有当缓存池中没有可用对象时才创建新对象，而当缓存对象过多时则会压缩缓存池。</li><li><strong>私有堆（Private Heap）：</strong>在操作系统中，new / malloc 等操作是串行化的，虽然一般的应用程序不用太在乎这个问题，但是在一个高并发的服务器中则是个不可忽略的问题，另外 TBufferObj 和 TSocketObj 均为大小固定的结构体，因此非常适合在私有堆中分配内存，避免与 new / malloc 竞争同时又减少内存空洞。（<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/12/2348302.html" target="_blank" data-mce-href="http://www.cnblogs.com/ldcsaa/archive/2012/02/12/2348302.html">关于私有堆的使用方法请参考这里 ^_^</a>） </li></ol></ol>
<p>&nbsp;　　</p>
<p>　　<strong>三、通用性与可用性</strong></p>
<p>　　与《<strong><a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/15/2351756.html" target="_blank" data-mce-href="http://www.cnblogs.com/ldcsaa/archive/2012/02/15/2351756.html">通用异步 Windows Socket TCP 客户端组件的设计与实现</a></strong>》描述的客户端接口一样，服务端组件也提供了两组接口：ISocketServer 接口提供组件操作方法，由上层应用直接调用；IServerSocketListener 接口提供组件通知方法，由上层应用实现，这两个接口设计得非常简单，主要方法均不超过 5 个。由于组件自身功能完备（不需要附带其它库或代码）并且职责单一（只管通信，不参与业务逻辑），因此可以十分方便第整合到任何类型的应用程序中。</p>
<p>&nbsp;</p>
<p>　　<strong>四、伸缩性</strong></p>
<p>　　可以根据实际的使用环境要求设置工作线程的数量、 TBufferObj 和 TSocketObj 缓存池的大小、TBufferObj 缓冲区的大小、Socket 监听队列的大小、AccepEx 派发的数目以及心跳检查的间隔等。</p>
<p>&nbsp;</p>
<p>　　<strong>五、连接标识</strong></p>
<p>　　组件完全封装了所有的底层 Socket 通信，上层应用看不到任何通信细节，不必也不能干预任何通信操作。另外，组件在 IServerSocketListener 通知接口的所有方法中都有一个 Connection ID 参数，该参数作为连接标识提供给上层应用识别不同的连接。</p>
<p>&nbsp;</p>
<hr />

<p>&nbsp;</p>
<p><em><strong><span style="font-size: 14pt" data-mce-style="font-size: 14pt;">原文：《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/15/2351756.html" data-mce-href="http://www.cnblogs.com/ldcsaa/archive/2012/02/15/2351756.html">通用异步 Windows Socket TCP 客户端组件的设计与实现</a></span></strong></em><em><strong><span style="font-size: 14pt" data-mce-style="font-size: 14pt;">》</span></strong></em></p>
<p>&nbsp;</p>
<p><span style="font-size: 18pt" data-mce-style="font-size: 18pt;"><strong>设计概述</strong></span></p>
<p>　　编写 Windows Socket TCP 客户端其实并不困难，Windows 提供了6种&nbsp;I/O 通信模型供大家选择。但本座看过很多客户端程序都把 Socket 通信和业务逻辑混在一起，剪不断理还乱。每个程序都 Copy / Parse 类似的代码再进行修改，实在有点情何以堪。因此本座利用一些闲暇时光写了一个<strong><a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/25/2367409.html" target="_blank" data-mce-href="http://www.cnblogs.com/ldcsaa/archive/2012/02/25/2367409.html">基于 IOCP 的通用异步 Windows Socket TCP&nbsp;高性能服务端组件</a></strong>和一个<strong>通用异步 Windows Socket TCP 客户端组件</strong>供各位看官参详参详，希望能激发下大家的灵感。本篇文章讲述客户端组件。闲话少说，我们现在步入正题。</p>
<ul><li>最重要的第一个问题：如何才能达到通用？ </li></ul>
<p>　　答：很简单。</p>
<p>　　　　1、限制组件的职能，说白了，<span style="color: #0000ff" data-mce-style="color: #0000ff;">通信组件的唯一职责就是接受和发送字节流</span>，绝对不能参与上层协议解析等工作。不在其位不谋其政就是这个意思。</p>
<p>　　　　2、与上层使用者解耦、互不依赖，组件与使用者通过接口方法进行交互，组件实现 ISocketClient 接口为上层提供操作方法；使用者通过&nbsp;IClientSocketListener 接口把自己注册为组件的 Listener，接收组件通知。因此，任何使用者只要实现了 IClientSocketListener 接口都可以使用组件；另一方面，你甚至可以自己重新写一个实现方式完全不同的组件实现给使用者调用，只要该组件遵从 ISocketClient 接口。这也是 DIP 设计原则的体现（<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/26/2368959.html" target="_blank" data-mce-href="http://www.cnblogs.com/ldcsaa/archive/2012/02/26/2368959.html">若想了解更多关于设计原则的内容请猛击这里 ^_^</a>）。</p>
<p>&nbsp;</p>
<ul><li>最重要的第二个问题：可用性如何，也就是说使用起来是否是否方便？ </li></ul>
<p>　　答：这个问题问得很好，可用性对所有通用组件都是至关重要的，如果太难用还不如自己重头写一个来得方便。因此，ISocketClient 和 IClientSocketListener 接口设计得尽量简单易用（通俗来说就是&#8220;傻瓜化&#8221;），这两个接口的主要方法均不超过 5 个。</p>
<p>&nbsp;</p>
<ul><li>最重要的第三个问题：组件的性能如何？ </li></ul>
<p>　　作为底层的通用组件，性能问题是必须考虑的，绝对不能成为系统的瓶颈。而另一方面，从实际出发，毕竟只是一个客户端组件，它的并发性要求远没有服务端那么高。因此，组件在设计上充分考虑了性能、现实使用情景、可用性和实现复杂性等因素，确保满足性能要求的同时又不会写得太复杂。做出以下两点设计决策：</p>
<ol>
<ol><li>在单独线程中实现 Socket 通信交互。这样可以避免与主线程或其他线程相互干扰。</li><li>I/O&nbsp;模型选择 WSAEventSelect。细说一下选择这种 I/O 模型的原因：（各种 I/O 模型的性能比较可以参考：《Windows 网络编程（中文第二版）》第 154 页） 
<ul><li>阻塞模型：（不解析，你懂的^_^）</li><li>非阻塞模型：（性能太低）</li><li>WSAAsyncSelect：&nbsp;（两个原因：a、性能太低；b、对于纯 Console 程序还要背负 HWND 实在是伤不起呀！）</li><li>重叠 I/O：（有点复杂了）</li><li>完成端口：（何必呢？） </li></ul></li></ol></ol>
<hr />

<p>&nbsp;<strong style="color: #800000">原文出处：</strong><a href="http://www.cnblogs.com/ldcsaa" target="_blank"><strong>怪兽的博客</strong></a><strong>&nbsp;&nbsp;</strong><a href="http://weibo.com/u/1402935851" target="_blank"><strong>怪兽的微博</strong></a><strong>&nbsp;&nbsp;</strong><a href="http://qun.qq.com/#jointhegroup/gid/75375912" target="_blank"><strong>怪兽乐园Q群</strong></a></p><img src ="http://www.cppblog.com/ldcsaa/aggbug/178763.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ldcsaa/" target="_blank">~怪^_*兽~</a> 2012-06-15 09:40 <a href="http://www.cppblog.com/ldcsaa/archive/2012/06/15/178763.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于 IOCP 的通用异步 Windows Socket TCP 高性能服务端组件的设计与实现</title><link>http://www.cppblog.com/ldcsaa/archive/2012/04/19/172011.html</link><dc:creator>~怪^_*兽~</dc:creator><author>~怪^_*兽~</author><pubDate>Thu, 19 Apr 2012 09:51:00 GMT</pubDate><guid>http://www.cppblog.com/ldcsaa/archive/2012/04/19/172011.html</guid><wfw:comment>http://www.cppblog.com/ldcsaa/comments/172011.html</wfw:comment><comments>http://www.cppblog.com/ldcsaa/archive/2012/04/19/172011.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/ldcsaa/comments/commentRss/172011.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ldcsaa/services/trackbacks/172011.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 设计概述　　服务端通信组件的设计是一项非常严谨的工作，其中性能、伸缩性和稳定性是必须考虑的硬性质量指标，若要把组件设计为通用组件提供给多种已知或未知的上层应用使用，则设计的难度更会大大增加，通用性、可用性和灵活性必须考虑在内。　　现以一个基于 IOCP 的通用异步 Windows Socket TCP 服务端组件为例子，讲述其设计与实现相关的问题，希望能引发大家的思考，对大家日后开展相关类...&nbsp;&nbsp;<a href='http://www.cppblog.com/ldcsaa/archive/2012/04/19/172011.html'>阅读全文</a><img src ="http://www.cppblog.com/ldcsaa/aggbug/172011.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ldcsaa/" target="_blank">~怪^_*兽~</a> 2012-04-19 17:51 <a href="http://www.cppblog.com/ldcsaa/archive/2012/04/19/172011.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>通用异步 Windows Socket TCP 客户端组件的设计与实现</title><link>http://www.cppblog.com/ldcsaa/archive/2012/04/15/171450.html</link><dc:creator>~怪^_*兽~</dc:creator><author>~怪^_*兽~</author><pubDate>Sun, 15 Apr 2012 02:42:00 GMT</pubDate><guid>http://www.cppblog.com/ldcsaa/archive/2012/04/15/171450.html</guid><wfw:comment>http://www.cppblog.com/ldcsaa/comments/171450.html</wfw:comment><comments>http://www.cppblog.com/ldcsaa/archive/2012/04/15/171450.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/ldcsaa/comments/commentRss/171450.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ldcsaa/services/trackbacks/171450.html</trackback:ping><description><![CDATA[<p>　　编写 Windows Socket TCP 客户端其实并不困难，Windows 提供了6种&nbsp;I/O 通信模型供大家选择。但本座看过很多客户端程序都把 Socket 通信和业务逻辑混在一起，剪不断理还乱。每个程序都 Copy / Parse 类似的代码再进行修改，实在有点情何以堪。因此本座利用一些闲暇时光写了一个<strong><a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/25/2367409.html" target="_blank">基于 IOCP 的通用异步 Windows Socket TCP&nbsp;高性能服务端组件</a></strong>和一个<strong>通用异步 Windows Socket TCP 客户端组件</strong>供各位看官参详参详，希望能激发下大家的灵感。本篇文章讲述客户端组件。闲话少说，我们现在步入正题。</p>
<ul><li>最重要的第一个问题：如何才能达到通用？ </li></ul>
<p>　　答：很简单。</p>
<p>　　　　1、限制组件的职能，说白了，<span style="color: #0000ff">通信组件的唯一职责就是接受和发送字节流</span>，绝对不能参与上层协议解析等工作。不在其位不谋其政就是这个意思。</p>
<p>　　　　2、与上层使用者解耦、互不依赖，组件与使用者通过接口方法进行交互，组件实现 ISocketClient 接口为上层提供操作方法；使用者通过&nbsp;IClientSocketListener 接口把自己注册为组件的 Listener，接收组件通知。因此，任何使用者只要实现了 IClientSocketListener 接口都可以使用组件；另一方面，你甚至可以自己重新写一个实现方式完全不同的组件实现给使用者调用，只要该组件遵从 ISocketClient 接口。这也是 DIP 设计原则的体现（<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/26/2368959.html" target="_blank">若想了解更多关于设计原则的内容请猛击这里 ^_^</a>）。</p>
<p>&nbsp;</p>
<ul><li>最重要的第二个问题：可用性如何，也就是说使用起来是否是否方便？ </li></ul>
<p>　　答：这个问题问得很好，可用性对所有通用组件都是至关重要的，如果太难用还不如自己重头写一个来得方便。因此，ISocketClient 和 IClientSocketListener 接口设计得尽量简单易用（通俗来说就是&#8220;傻瓜化&#8221;），这两个接口的主要方法均不超过 5 个。</p>
<p>&nbsp;</p>
<ul><li>最重要的第三个问题：组件的性能如何？ </li></ul>
<p>　　作为底层的通用组件，性能问题是必须考虑的，绝对不能成为系统的瓶颈。而另一方面，从实际出发，毕竟只是一个客户端组件，它的并发性要求远没有服务端那么高。因此，组件在设计上充分考虑了性能、现实使用情景、可用性和实现复杂性等因素，确保满足性能要求的同时又不会写得太复杂。做出以下两点设计决策：</p>
<ol><li style="list-style-type: none">
<ol><li>在单独线程中实现 Socket 通信交互。这样可以避免与主线程或其他线程相互干扰。</li><li>I/O&nbsp;模型选择 WSAEventSelect。细说一下选择这种 I/O 模型的原因：（各种 I/O 模型的性能比较可以参考：《Windows 网络编程（中文第二版）》第 154 页） 
<ul><li>阻塞模型：（不解析，你懂的^_^）</li><li>非阻塞模型：（性能太低）</li><li>WSAAsyncSelect：&nbsp;（两个原因：a、性能太低；b、对于纯 Console 程序还要背负 HWND 实在是伤不起呀！）</li><li>重叠 I/O：（有点复杂了）</li><li>完成端口：（何必呢？） </li></ul></li></ol></li></ol>
<p>&nbsp;</p>
<p>　　唉，理论的东西就先别吹那么多了，直接上代码吧，求你了 ！！</p>
<p>　　OK！先看看 <strong>ISocketClient</strong> 和 <strong>IClientSocketListener</strong> 的接口定义:</p>
<div class="cnblogs_code"><pre><span style="color: #008000">//</span><span style="color: #008000"> 组件操作类型</span><span style="color: #008000"><br /></span><span style="color: #0000ff">enum</span> EnSocketOperation<br />{<br />    SO_UNKNOWN    = <span style="color: #800080">0</span>,<br />    SO_ACCEPT    = <span style="color: #800080">1</span>,<br />    SO_CONNECT    = <span style="color: #800080">2</span>,<br />    SO_SEND        = <span style="color: #800080">3</span>,<br />    SO_RECEIVE    = <span style="color: #800080">4</span>,<br />};<br /><br /><span style="color: #008000">//</span><span style="color: #008000"> 组件监听器基接口</span><span style="color: #008000"><br /></span><strong><span style="color: #0000ff">class</span> ISocketListener</strong><br />{<br /><span style="color: #0000ff">public</span>:<br />    <span style="color: #0000ff">enum</span> EnHandleResult<br />    {<br />        HR_OK        = <span style="color: #800080">0</span>,<br />        HR_IGNORE    = <span style="color: #800080">1</span>,<br />        HR_ERROR    = <span style="color: #800080">2</span>,<br />    };<br /><br /><span style="color: #0000ff">public</span>:<br /><strong>　　<span style="color: #008000">//</span><span style="color: #008000"> 已发出数据通知</span><span style="color: #008000"><br /></span>　　<span style="color: #0000ff">virtual</span> EnHandleResult OnSend(DWORD dwConnectionID, <span style="color: #0000ff">const</span> BYTE* pData, <span style="color: #0000ff">int</span> iLength) = <span style="color: #800080">0</span>;</strong><br /><strong><span style="color: #008000">　　//</span><span style="color: #008000"> 已接收数据通知</span><span style="color: #008000"><br /></span>　　<span style="color: #0000ff">virtual</span> EnHandleResult OnReceive(DWORD dwConnectionID, <span style="color: #0000ff">const</span> BYTE* pData, <span style="color: #0000ff">int</span> iLength) = <span style="color: #800080">0</span>;</strong><br /><strong><span style="color: #008000">　　//</span><span style="color: #008000"> 关闭连接通知</span><span style="color: #008000"><br /></span><span style="color: #0000ff">　　virtual</span> EnHandleResult OnClose(DWORD dwConnectionID) = <span style="color: #800080">0</span>;</strong><br /><strong><span style="color: #008000">　　//</span><span style="color: #008000"> 通信错误通知</span><span style="color: #008000"><br /></span>　　<span style="color: #0000ff">virtual</span> EnHandleResult OnError(DWORD dwConnectionID, EnSocketOperation enOperation, <span style="color: #0000ff">int</span> iErrorCode) = <span style="color: #800080">0</span>;</strong><br /><br /><span style="color: #0000ff">public</span>:<br />    <span style="color: #0000ff">virtual</span> ~ISocketListener() {}<br />};<br /><br /><span style="color: #008000">//</span><span style="color: #008000"> 服务端组件监听器接口（暂时无视之）</span><span style="color: #008000"><br /></span><span style="color: #0000ff">class</span> IServerSocketListener : <span style="color: #0000ff">public</span> ISocketListener<br />{<br /><span style="color: #0000ff">public</span>:<br />    <span style="color: #008000">//</span><span style="color: #008000"> 接收连接通知</span><span style="color: #008000"><br /></span>    <span style="color: #0000ff">virtual</span> EnHandleResult OnAccept(DWORD dwConnectionID)    = <span style="color: #800080">0</span>;<br />    <span style="color: #008000">//</span><span style="color: #008000"> 服务关闭通知</span><span style="color: #008000"><br /></span>    <span style="color: #0000ff">virtual</span> EnHandleResult OnServerShutdown()                = <span style="color: #800080">0</span>;<br />};<br /><br /><span style="color: #008000">//</span><span style="color: #008000"> 客户端组件监听器接口</span><span style="color: #008000"><br /></span><strong><span style="color: #0000ff">class</span></strong> <strong>IClientSocketListener : <span style="color: #0000ff">public</span> ISocketListener</strong><br />{<br /><span style="color: #0000ff">public</span>:<br />　　<strong><span style="color: #008000">//</span><span style="color: #008000"> 连接完成通知</span><span style="color: #008000"><br /></span>　　<span style="color: #0000ff">virtual</span></strong> <strong>EnHandleResult OnConnect(DWORD dwConnectionID) = <span style="color: #800080">0</span>;</strong><br />};<br /><br /><span style="color: #008000">//</span><span style="color: #008000"> 服务端组件接口（暂时无视之）</span><span style="color: #008000"><br /></span><span style="color: #0000ff">class</span> ISocketServer<br />{<br /><span style="color: #0000ff">public</span>:<br />    <span style="color: #0000ff">enum</span> En_ISS_Error<br />    {<br />        ISS_OK                        = <span style="color: #800080">0</span>,<br />        ISS_SOCKET_CREATE            = <span style="color: #800080">1</span>,<br />        ISS_SOCKET_BIND                = <span style="color: #800080">2</span>,<br />        ISS_SOCKET_LISTEN            = <span style="color: #800080">3</span>,<br />        ISS_CP_CREATE                = <span style="color: #800080">4</span>,<br />        ISS_WORKER_THREAD_CREATE    = <span style="color: #800080">5</span>,<br />        ISS_SOCKE_ATTACH_TO_CP        = <span style="color: #800080">6</span>,<br />        ISS_ACCEPT_THREAD_CREATE    = <span style="color: #800080">7</span>,<br />    };<br /><br /><span style="color: #0000ff">public</span>:<br />    <span style="color: #0000ff">virtual</span> BOOL Start    (LPCTSTR pszBindAddress, USHORT usPort, <span style="color: #0000ff">long</span> lThreadCount)            = <span style="color: #800080">0</span>;<br />    <span style="color: #0000ff">virtual</span> BOOL Stop    ()                                                                    = <span style="color: #800080">0</span>;<br />    <span style="color: #0000ff">virtual</span> BOOL Send    (DWORD dwConnID, <span style="color: #0000ff">const</span> BYTE* pBuffer, <span style="color: #0000ff">int</span> iLen)                        = <span style="color: #800080">0</span>;<br />    <span style="color: #0000ff">virtual</span> BOOL HasStarted                ()                                                    = <span style="color: #800080">0</span>;<br />    <span style="color: #0000ff">virtual</span> En_ISS_Error GetLastError    ()                                                    = <span style="color: #800080">0</span>;<br />    <span style="color: #0000ff">virtual</span> LPCTSTR        GetLastErrorDesc()                                                    = <span style="color: #800080">0</span>;<br />    <span style="color: #0000ff">virtual</span> BOOL GetConnectionAddress(DWORD dwConnID, CString&amp; strAddress, USHORT&amp; usPort)    = <span style="color: #800080">0</span>;<br /><br /><br /><span style="color: #0000ff">public</span>:<br />    <span style="color: #0000ff">virtual</span> ~ISocketServer() {}<br />};<br /><br /><span style="color: #008000">//</span><span style="color: #008000"> 服务端组件接口智能指针</span><span style="color: #008000"><br /></span>typedef auto_ptr&lt;ISocketServer&gt;    ISocketServerPtr;<br /><br /><span style="color: #008000">//</span><span style="color: #008000"> 客户端组件接口</span><span style="color: #008000"><br /></span><strong><span style="color: #0000ff">class</span> ISocketClient</strong><br />{<br /><span style="color: #0000ff">public</span>:<br />    <span style="color: #008000">//</span><span style="color: #008000"> 操作结果码</span><span style="color: #008000"><br /></span>    <span style="color: #0000ff">enum</span> En_ISC_Error<br />    {<br />        ISC_OK                        = <span style="color: #800080">0</span>,<br />        ISC_CLIENT_HAD_STARTED        = <span style="color: #800080">1</span>,<br />        ISC_CLIENT_NOT_STARTED        = <span style="color: #800080">2</span>,<br />        ISC_SOCKET_CREATE_FAIL        = <span style="color: #800080">3</span>,<br />        ISC_CONNECT_SERVER_FAIL        = <span style="color: #800080">4</span>,<br />        ISC_WORKER_CREATE_FAIL        = <span style="color: #800080">5</span>,<br />        ISC_NETWORK_ERROR            = <span style="color: #800080">6</span>,<br />        ISC_PROTOCOL_ERROR            = <span style="color: #800080">7</span>,<br />    };<br /><br /><span style="color: #0000ff">public</span>:<br /><strong><span style="color: #008000">　　//</span><span style="color: #008000"> 启动通信</span><span style="color: #008000"><br /></span>　　<span style="color: #0000ff">virtual</span> BOOL Start (LPCTSTR pszRemoteAddress, USHORT usPort) = <span style="color: #800080">0</span>;</strong><br /><strong><span style="color: #008000">　　//</span><span style="color: #008000"> 关闭通信</span><span style="color: #008000"><br /></span>　　<span style="color: #0000ff">virtual</span> BOOL Stop () = <span style="color: #800080">0</span>;</strong><br /><strong>　　<span style="color: #008000">//</span><span style="color: #008000"> 发送数据</span><span style="color: #008000"><br /></span><span style="color: #0000ff">　　virtual</span> BOOL Send (DWORD dwConnID, <span style="color: #0000ff">const</span> BYTE* pBuffer, <span style="color: #0000ff">int</span> iLen) = <span style="color: #800080">0</span>;</strong><br /><strong>　　<span style="color: #008000">//</span><span style="color: #008000"> 是否已启动</span><span style="color: #008000"><br /></span><span style="color: #0000ff">　　virtual</span> BOOL HasStarted () = <span style="color: #800080">0</span>;</strong><br /><strong>　　<span style="color: #008000">//</span><span style="color: #008000"> 获取错误码</span><span style="color: #008000"><br /></span>　　<span style="color: #0000ff">virtual</span> En_ISC_Error GetLastError () = <span style="color: #800080">0</span>;</strong><br /><strong>　　<span style="color: #008000">//</span><span style="color: #008000"> 获取错误描述</span><span style="color: #008000"><br /></span>　　<span style="color: #0000ff">virtual</span> LPCTSTR GetLastErrorDesc() = <span style="color: #800080">0</span>;</strong><br /><br /><span style="color: #0000ff">public</span>:<br />    <span style="color: #0000ff">virtual</span> ~ISocketClient() {}<br />};<br /><br /><strong><span style="color: #008000">//</span><span style="color: #008000"> 客户端组件接口智能指针</span><span style="color: #008000"><br /></span>typedef auto_ptr&lt;ISocketClient&gt; </strong>   <strong>ISocketClientPtr</strong>;</pre></div>
<p>　　</p>
<p>　　<strong>ISocketClient</strong> 接口主要有以下三个方法：</p>
<ul><li>Start()：启动通信</li><li>Send()：发送数据</li><li>Stop()：停止通信 </li></ul>
<p>　　<strong>IClientSocketListener</strong> 接口有以下五个通知方法：</p>
<ul><li>OnConnect()</li><li>OnSend()</li><li>OnReceive()</li><li>OnClose()</li><li>OnError()&nbsp; </li></ul>
<p>&nbsp;　　够简单了吧^_^，使用者只需通过三个方法操作组件，然后处理五个组件通知。下面我们再看看组件的具体实现，先看组件类定义：</p>
<div class="cnblogs_code"><pre><span style="color: #008000">/*</span><span style="color: #008000"> 组件实现类 </span><span style="color: #008000">*/</span><br /><strong><span style="color: #0000ff">class</span> CSocketClient : <span style="color: #0000ff">public</span> ISocketClient</strong><br />{<br /><span style="color: #008000">//</span><span style="color: #008000"> ISocketClient 接口方法</span><span style="color: #008000"><br /></span><span style="color: #0000ff">public</span>:<br /><strong><span style="color: #0000ff">　　virtual</span> BOOL Start (LPCTSTR pszRemoteAddress, USHORT usPortt);</strong><br /><strong>　　<span style="color: #0000ff">virtual</span> BOOL Stop ();</strong><br /><strong><span style="color: #0000ff">　　virtual</span> BOOL Send (DWORD dwConnID, <span style="color: #0000ff">const</span> BYTE* pBuffer, <span style="color: #0000ff">int</span> iLen);</strong><br /><strong>　　<span style="color: #0000ff">virtual</span> BOOL HasStarted () {<span style="color: #0000ff">return</span> m_bStarted;}</strong><br /><strong>　　<span style="color: #0000ff">virtual</span> En_ISC_Error GetLastError () {<span style="color: #0000ff">return</span> sm_enLastError;}</strong><br /><strong>　　<span style="color: #0000ff">virtual</span> LPCTSTR GetLastErrorDesc();</strong><br /><br /><span style="color: #0000ff">private</span>:<br />    BOOL CreateClientSocket();<br />    BOOL ConnectToServer(LPCTSTR pszRemoteAddress, USHORT usPort);<br />    BOOL CreateWorkerThread();<br />    <span style="color: #008000">//</span><span style="color: #008000"> 网络事件处理方法</span><span style="color: #008000"><br /></span>    BOOL ProcessNetworkEvent();<br />    <span style="color: #0000ff">void</span> WaitForWorkerThreadEnd();<br />    BOOL ReadData();<br />    BOOL SendData();<br /><br />    <span style="color: #0000ff">void</span> SetLastError(En_ISC_Error code, LPCTSTR func, <span style="color: #0000ff">int</span> ec);<br /><br /><span style="color: #008000">//</span><span style="color: #008000"> 通信线程函数</span><span style="color: #008000"><br /></span><span style="color: #0000ff">static</span> <br />#ifndef _WIN32_WCE<br />    UINT<br /><span style="color: #0000ff">#else</span><br />    DWORD<br /><span style="color: #0000ff">#endif</span><br />     WINAPI WorkerThreadProc(LPVOID pv);<br /><br /><span style="color: #0000ff">private</span>:<br />    <span style="color: #0000ff">static</span> <span style="color: #0000ff">const</span> <span style="color: #0000ff">int</span> RECEIVE_BUFFER_SIZE    = <span style="color: #800080">8</span> * <span style="color: #800080">1024</span>;<br />    <span style="color: #0000ff">static</span> <span style="color: #0000ff">const</span> <span style="color: #0000ff">int</span> WORKER_THREAD_END_TIME    = <span style="color: #800080">3</span> * <span style="color: #800080">1000</span>;<br /><br />    <span style="color: #0000ff">static</span> <span style="color: #0000ff">const</span> <span style="color: #0000ff">long</span>    DEFALUT_KEEPALIVE_TIMES        = <span style="color: #800080">3</span>;<br />    <span style="color: #0000ff">static</span> <span style="color: #0000ff">const</span> <span style="color: #0000ff">long</span>    DEFALUT_KEEPALIVE_INTERVAL    = <span style="color: #800080">10</span> * <span style="color: #800080">1000</span>;<br /><br /><br /><strong><span style="color: #008000">//</span><span style="color: #008000"> 构造函数</span><span style="color: #008000"><br /></span><span style="color: #0000ff">public</span>:</strong><br /><strong>　　CSocketClient(IClientSocketListener* pListener)</strong><br /><strong>　　: m_pListener(pListener) <span style="color: #008000">//</span><span style="color: #008000"> 设置监听器对象</span><span style="color: #008000"><br /></span>　　, m_soClient(INVALID_SOCKET)</strong><br /><strong>　　, m_evSocket(NULL)</strong><br /><strong>　　, m_dwConnID(<span style="color: #800080">0</span>)</strong><br /><strong>　　, m_hWorker(NULL)</strong><br /><strong>　　, m_dwWorkerID(<span style="color: #800080">0</span>)</strong><br /><strong>　　, m_bStarted(FALSE)</strong><br /><strong>#ifdef _WIN32_WCE</strong><br /><strong>　　, sm_enLastError(ISC_OK)</strong><br /><strong><span style="color: #0000ff">#endif</span></strong><br /><strong>　　{</strong><br /><strong>　　　　ASSERT(m_pListener);</strong><br /><strong>　　}</strong><br /><br />    <span style="color: #0000ff">virtual</span> ~CSocketClient()    {<span style="color: #0000ff">if</span>(HasStarted()) Stop();}<br /><br /><span style="color: #0000ff">private</span>:<br />　　<strong><span style="color: #008000">//</span><span style="color: #008000"> 这是神马 ？？？</span><span style="color: #008000"><br /></span>　　CInitSocket m_wsSocket;</strong><br />    <br />    SOCKET            m_soClient;<br />    HANDLE            m_evSocket;<br />    DWORD            m_dwConnID;<br /><br />    CCriSec            m_scStop;<br />    CEvt            m_evStop;<br />    HANDLE            m_hWorker;<br /><br />#ifndef _WIN32_WCE<br />    UINT<br /><span style="color: #0000ff">#else</span><br />    DWORD<br /><span style="color: #0000ff">#endif</span><br />                    m_dwWorkerID;<br /><br />    CBufferPtr        m_sndBuffer;<br />    CCriSec            m_scBuffer;<br />    CEvt            m_evBuffer;<br /><br />    <span style="color: #0000ff">volatile</span> BOOL    m_bStarted;<br /><br /><span style="color: #0000ff">private</span>:<br />　　<span style="color: #008000">//</span><span style="color: #008000"> 监听器对象指针</span><span style="color: #008000"><br /></span><strong>　　IClientSocketListener* m_pListener;</strong><br /><br />#ifndef _WIN32_WCE<br />    __declspec(thread) <span style="color: #0000ff">static</span> En_ISC_Error    sm_enLastError;<br /><span style="color: #0000ff">#else</span><br />    <span style="color: #0000ff">volatile</span> En_ISC_Error                    sm_enLastError;<br /><span style="color: #0000ff">#endif</span><br />};</pre></div>
<p>&nbsp;</p>
<p>　　从上面的定义可以看出，组件实现类本身并没有提供额外的公共方法，它完全是可以被替换的。组件在构造函数中接收监听器对象，并且保存为其成员属性，因此可以在需要的时候向监听器发送事件通知。</p>
<p>　　另外，不知各位看官是否注意到一个奇怪的成员属性：&#8220;<strong>CInitSocket m_wsSocket;</strong> &#8221;，这个属性在其它地方从来都不会用到，那么它是干嘛的呢？在回答这个问题之前，首先想问问大家：Windows Socket 操作的整个操作过程中，第一个以及最后一个被调用的方法是什么？是 socket()、connect()、bind()、还是&nbsp;closesocket() 吗？都错！答案是 &#8212;&#8212; ::WSAStartup() 和 ::WSACleanup()。每个程序都要调用一下这两个方法确实是很烦的，又不雅观。&nbsp;其实，m_wsSocket 的唯一目的就是为了避免手工调用者两个方法，看看它的定义就明白了：</p>
<div class="cnblogs_code"><pre><span style="color: #0000ff">class</span> CInitSocket<br />{<br /><span style="color: #0000ff">public</span>:<br />    CInitSocket(LPWSADATA lpWSAData = NULL, BYTE minorVersion = <span style="color: #800080">2</span>, BYTE majorVersion = <span style="color: #800080">2</span>)<br />    {<br />        LPWSADATA lpTemp = lpWSAData;<br />        <span style="color: #0000ff">if</span>(!lpTemp)<br />            lpTemp    = (LPWSADATA)_alloca(<span style="color: #0000ff">sizeof</span>(WSADATA));<br /><br />        m_iResult    = <strong>::WSAStartup(MAKEWORD(minorVersion, majorVersion), lpTemp)</strong>;<br />    }<br /><br />    ~CInitSocket()<br />    {<br />        <span style="color: #0000ff">if</span>(IsValid())<br />　　　　　　<strong>::WSACleanup()</strong>;<br />    }<br /><br />    <span style="color: #0000ff">int</span>        GetResult()    {<span style="color: #0000ff">return</span> m_iResult;}<br />    BOOL    IsValid()    {<span style="color: #0000ff">return</span> m_iResult == <span style="color: #800080">0</span>;}<br /><br /><span style="color: #0000ff">private</span>:<br />    <span style="color: #0000ff">int</span>        m_iResult;<br />};</pre></div>
<p>&nbsp;</p>
<p>&nbsp;　　现在我们看看组件类实现文件中几个重要方法的定义：</p>
<div class="cnblogs_code"><pre><span style="color: #008000">//</span><span style="color: #008000"> 组件事件触发宏定义</span><span style="color: #008000"><br /></span><span style="color: #0000ff">#define</span> <strong>FireConnect</strong>(id)                    m_pListener-&gt;OnConnect(id)<br /><span style="color: #0000ff">#define</span> <strong>FireSend</strong>(id, data, len)            (m_bStarted ? m_pListener-&gt;OnSend(id, data, len)    : ISocketListener::HR_IGNORE)<br /><span style="color: #0000ff">#define</span> <strong>FireReceive</strong>(id, data, len)        (m_bStarted ? m_pListener-&gt;OnReceive(id, data, len)    : ISocketListener::HR_IGNORE)<br /><span style="color: #0000ff">#define</span> <strong>FireClose</strong>(id)                    (m_bStarted ? m_pListener-&gt;OnClose(id)                : ISocketListener::HR_IGNORE)<br /><span style="color: #0000ff">#define</span> <strong>FireError</strong>(id, op, code)            (m_bStarted ? m_pListener-&gt;OnError(id, op, code)    : ISocketListener::HR_IGNORE)<br /><br /><span style="color: #008000">//</span><span style="color: #008000"> 启动组件</span><span style="color: #008000"><br /></span>BOOL CSocketClient::Start(LPCTSTR pszRemoteAddress, USHORT usPort)<br />{<br />    BOOL isOK = FALSE;<br /><br />    <span style="color: #0000ff">if</span>(HasStarted())<br />    {<br />        SetLastError(ISC_CLIENT_HAD_STARTED, _T(__FUNCTION__), <span style="color: #800080">0</span>);<br />        <span style="color: #0000ff">return</span> isOK;<br />    }<br /><br />    <span style="color: #008000">//</span><span style="color: #008000"> 创建 socket</span><span style="color: #008000"><br /></span>    <span style="color: #0000ff">if</span>(CreateClientSocket())<br />    {<br />        <span style="color: #008000">//</span><span style="color: #008000"> 连接服务器（内部会调用 <strong>FireConnect()</strong> ）</span><span style="color: #008000"><br /></span>        <span style="color: #0000ff">if</span>(ConnectToServer(pszRemoteAddress, usPort))<br />        {<br />            <span style="color: #008000">//</span><span style="color: #008000"> 创建工作线程</span><span style="color: #008000"><br /></span>            <span style="color: #0000ff">if</span>(CreateWorkerThread())<br />                isOK = TRUE;<br />            <span style="color: #0000ff">else</span><br />                SetLastError(ISC_WORKER_CREATE_FAIL, _T(__FUNCTION__), <span style="color: #800080">0</span>);<br />        }<br />        <span style="color: #0000ff">else</span><br />            SetLastError(ISC_CONNECT_SERVER_FAIL, _T(__FUNCTION__), ::WSAGetLastError());<br />    }<br />    <span style="color: #0000ff">else</span><br />        SetLastError(ISC_SOCKET_CREATE_FAIL, _T(__FUNCTION__), ::WSAGetLastError());<br /><br />    isOK ? m_bStarted = TRUE : Stop();<br /><br />    <span style="color: #0000ff">return</span> isOK;<br />}<br /><br /><span style="color: #008000">//</span><span style="color: #008000"> 关闭组件</span><span style="color: #008000"><br /></span>BOOL CSocketClient::Stop()<br />{<br />    {<br />        CCriSecLock locallock(m_scStop);<br /><br />        m_bStarted = FALSE;<br /><br />        <span style="color: #0000ff">if</span>(m_hWorker != NULL)<br />        {<br />            <span style="color: #008000">//</span><span style="color: #008000"> 停止工作线程</span><span style="color: #008000"><br /></span>            <span style="color: #0000ff">if</span>(::GetCurrentThreadId() != m_dwWorkerID)<br />                WaitForWorkerThreadEnd();<br /><br />            ::CloseHandle(m_hWorker);<br />            m_hWorker        = NULL;<br />            m_dwWorkerID    = <span style="color: #800080">0</span>;<br />        }<br /><br />        <span style="color: #0000ff">if</span>(m_evSocket != NULL)<br />        {<br />            <span style="color: #008000">//</span><span style="color: #008000"> 关闭 WSAEvent</span><span style="color: #008000"><br /></span>            ::WSACloseEvent(m_evSocket);<br />            m_evSocket    = NULL;<br />        }<br /><br />        <span style="color: #0000ff">if</span>(m_soClient != INVALID_SOCKET)<br />        {<br />            <span style="color: #008000">//</span><span style="color: #008000"> 关闭socket</span><span style="color: #008000"><br /></span>            shutdown(m_soClient, SD_SEND);<br />            closesocket(m_soClient);<br />            m_soClient    = INVALID_SOCKET;<br />        }<br /><br />        m_dwConnID = <span style="color: #800080">0</span>;<br />    }<br /><br /> <span style="color: #008000">//</span><span style="color: #008000"> 释放其它资源</span><span style="color: #008000"><br /></span>    m_sndBuffer.Free();<br />    m_evBuffer.Reset();<br />    m_evStop.Reset();<br /><br />    <span style="color: #0000ff">return</span> TRUE;<br />}<br /><br /><span style="color: #008000">//</span><span style="color: #008000"> 发送数据</span><span style="color: #008000"><br /></span>BOOL CSocketClient::Send(DWORD dwConnID, <span style="color: #0000ff">const</span> BYTE* pBuffer, <span style="color: #0000ff">int</span> iLen)<br />{<br />    ASSERT(iLen &gt; <span style="color: #800080">0</span>);<br /><br />    <span style="color: #0000ff">if</span>(!HasStarted())<br />    {<br />        SetLastError(ISC_CLIENT_NOT_STARTED, _T(__FUNCTION__), <span style="color: #800080">0</span>);<br />        <span style="color: #0000ff">return</span> FALSE;<br />    }<br /><br />    CCriSecLock locallock(m_scBuffer);<br />    <br />    <span style="color: #008000">//</span><span style="color: #008000"> 把数据存入缓冲器</span><span style="color: #008000"><br /></span>    m_sndBuffer.Cat(pBuffer, iLen);<br />　　<span style="color: #008000">// 唤醒工作现场，发送数据</span><br />    m_evBuffer.Set();<br /><br />    <span style="color: #0000ff">return</span> TRUE;<br />}<br /><br /><span style="color: #008000">//</span><span style="color: #008000"> 工作线程函数</span><span style="color: #008000"><br /></span>#ifndef _WIN32_WCE<br />    UINT<br /><span style="color: #0000ff">#else</span><br />    DWORD<br /><span style="color: #0000ff">#endif</span><br />    WINAPI CSocketClient::WorkerThreadProc(LPVOID pv)<br />{<br />    CSocketClient* pClient = (CSocketClient*)pv;<br /><br />    TRACE0(<span style="color: #800000">"</span><span style="color: #800000">---------------&gt; 启动工作线程 &lt;---------------\n</span><span style="color: #800000">"</span>);<br /><br />    HANDLE hEvents[] = {pClient-&gt;m_evSocket, pClient-&gt;m_evBuffer, pClient-&gt;m_evStop};<br /><br />    <span style="color: #0000ff">while</span>(pClient-&gt;HasStarted())<br />    {<br />        <span style="color: #008000">//</span><span style="color: #008000"> 等待 socket 事件、发送数据事件和停止通信事件</span><span style="color: #008000"><br /></span>        DWORD retval = ::MsgWaitForMultipleObjectsEx(<span style="color: #800080">3</span>, hEvents, WSA_INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);<br /><br />        <span style="color: #0000ff">if</span>(retval == WSA_WAIT_EVENT_0)<br />        {<br />            <span style="color: #008000">//</span><span style="color: #008000"> 处理网络消息</span><span style="color: #008000"><br /></span>            <span style="color: #0000ff">if</span>(!pClient-&gt;ProcessNetworkEvent())<br />            {<br />                <span style="color: #0000ff">if</span>(pClient-&gt;HasStarted())<br />                    pClient-&gt;Stop();<br /><br />                <span style="color: #0000ff">break</span>;<br />            }<br />        }<br />        <span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span>(retval == WSA_WAIT_EVENT_0 + <span style="color: #800080">1</span>)<br />        {<br />            <span style="color: #008000">//</span><span style="color: #008000"> 发送数据（内部调用 <strong>FireSend()</strong> ）</span><span style="color: #008000"><br /></span>            <span style="color: #0000ff">if</span>(!pClient-&gt;SendData())<br />            {<br />                <span style="color: #0000ff">if</span>(pClient-&gt;HasStarted())<br />                    pClient-&gt;Stop();<br /><br />                <span style="color: #0000ff">break</span>;<br />            }<br />        }<br />        <span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span>(retval == WSA_WAIT_EVENT_0 + <span style="color: #800080">2</span>)<br />            <span style="color: #0000ff">break</span>;<br />        <span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span>(retval == WSA_WAIT_EVENT_0 + <span style="color: #800080">3</span>)<br />            <span style="color: #008000">//</span><span style="color: #008000"> 消息循环</span><span style="color: #008000"><br /></span>            ::PeekMessageLoop();<br />        <span style="color: #0000ff">else</span><br />            ASSERT(FALSE);<br />    }<br /><br />    TRACE0(<span style="color: #800000">"</span><span style="color: #800000">---------------&gt; 退出工作线程 &lt;---------------\n</span><span style="color: #800000">"</span>);<br /><br />    <span style="color: #0000ff">return</span> <span style="color: #800080">0</span>;<br />}<br /><br /><span style="color: #008000">//</span><span style="color: #008000"> 处理网络消息</span><span style="color: #008000"><br /></span>BOOL CSocketClient::ProcessNetworkEvent()<br />{<br />    ::WSAResetEvent(m_evSocket);<br /><br />    WSANETWORKEVENTS events;<br />    <br />    <span style="color: #0000ff">int</span> rc = ::WSAEnumNetworkEvents(m_soClient, m_evSocket, &amp;events);<br />    <br />    <span style="color: #0000ff">if</span>(rc == SOCKET_ERROR)<br />    {<br />        <span style="color: #0000ff">int</span> code = ::WSAGetLastError();<br />        SetLastError(ISC_NETWORK_ERROR, _T(__FUNCTION__), code);<br />　　　　　<strong>FireError</strong>(m_dwConnID, SO_UNKNOWN, code);<br /><br />        <span style="color: #0000ff">return</span> FALSE;<br />    }<br /><br />    <span style="color: #008000">/*</span><span style="color: #008000"> 可读取 </span><span style="color: #008000">*/</span><br />    <span style="color: #0000ff">if</span>(events.lNetworkEvents &amp; FD_READ)<br />    {<br />        <span style="color: #0000ff">int</span> iCode = events.iErrorCode[FD_READ_BIT];<br /><br />        <span style="color: #0000ff">if</span>(iCode == <span style="color: #800080">0</span>)<br />            <span style="color: #008000">//</span><span style="color: #008000"> 读取数据（内部调用 <strong>FireReceive()</strong> ）</span><span style="color: #008000"><br /></span>            <span style="color: #0000ff">return</span> ReadData();<br />        <span style="color: #0000ff">else</span><br />　　　　 {<br />　　　　　　SetLastError(ISC_NETWORK_ERROR, _T(__FUNCTION__), iCode);<br /><strong>　　　　　　FireError</strong>(m_dwConnID, SO_RECEIVE, iCode);<br />　　　　　　<span style="color: #0000ff">return</span> FALSE;<br />        }<br />    }<br /><br />    <span style="color: #008000">/*</span><span style="color: #008000"> 可发送 </span><span style="color: #008000">*/</span><br />    <span style="color: #0000ff">if</span>(events.lNetworkEvents &amp; FD_WRITE)<br />    {<br />        <span style="color: #0000ff">int</span> iCode = events.iErrorCode[FD_WRITE_BIT];<br /><br />        <span style="color: #0000ff">if</span>(iCode == <span style="color: #800080">0</span>)<br />            <span style="color: #008000">//</span><span style="color: #008000"> 发送数据（内部调用 <strong>FireSend()</strong> ）</span><span style="color: #008000"><br /></span>            <span style="color: #0000ff">return</span> SendData();<br />        <span style="color: #0000ff">else</span><br />        {<br />            SetLastError(ISC_NETWORK_ERROR, _T(__FUNCTION__), iCode);<br /><strong>　　　　　　　　FireError</strong>(m_dwConnID, SO_SEND, iCode);<br />            <span style="color: #0000ff">return</span> FALSE;<br />        }<br />    }<br /><br />    <span style="color: #008000">/*</span><span style="color: #008000"> socket 已关闭 </span><span style="color: #008000">*/</span><br />    <span style="color: #0000ff">if</span>(events.lNetworkEvents &amp; FD_CLOSE)<br />    {<br />        <span style="color: #0000ff">int</span> iCode = events.iErrorCode[FD_CLOSE_BIT];<br /><br />        <span style="color: #0000ff">if</span>(iCode == <span style="color: #800080">0</span>)<br /><strong>　　　　　　FireClose</strong>(m_dwConnID);<br />        <span style="color: #0000ff">else</span><br />        {<br />            SetLastError(ISC_NETWORK_ERROR, _T(__FUNCTION__), iCode);<br />　　　　　　　　<strong>FireError</strong>(m_dwConnID, SO_UNKNOWN, iCode);<br />        }<br /><br />        <span style="color: #0000ff">return</span> FALSE;<br />    }<br /><br />    <span style="color: #0000ff">return</span> TRUE;<br />}</pre></div>
<p>　　</p>
<p>　　从上面的代码可以看出：通信过程中，组件的使用者不需要对通信过程进行任何干预，整个底层通信过程对使用者来说是透明的，使用只需集中精力处理好几个组件通知。下面来看看组件的一个使用示例：</p>
<div class="cnblogs_code"><pre><strong><span style="color: #008000">/*</span><span style="color: #008000"> 组件使用者：实现 IClientSocketListener </span></strong><span style="color: #008000">*/</span><br /><strong><span style="color: #0000ff">class</span></strong> <strong>CMainClient : <span style="color: #0000ff">public</span></strong> <strong>IClientSocketListener</strong><br />{<br /><span style="color: #008000">//</span><span style="color: #008000"> 这些方法会操作组件</span><span style="color: #008000"><br /></span><span style="color: #0000ff">public</span>:<br />    <span style="color: #0000ff">bool</span> Login(LPCTSTR pszAddress, USHORT usPort, <span style="color: #0000ff">const</span> T_101_Data* pData);<br />    <span style="color: #0000ff">bool</span> Logout(<span style="color: #0000ff">const</span> T_201_Data* pData);<br />        BOOL SendData(EnCommandType enCmdType, <span style="color: #0000ff">const</span> TCommandData* pCmdData, WORD wCmdDataLen);<br />    <span style="color: #0000ff">long</span>    GetLastError();<br />    LPCTSTR    GetLastErrorDesc();<br /><br /><span style="color: #008000">//</span><span style="color: #008000"> 实现 IClientSocketListener</span><span style="color: #008000"><br /></span><span style="color: #0000ff">public</span>:<br /><strong>　　<span style="color: #0000ff">virtual</span> EnHandleResult OnConnect(DWORD dwConnectionID);</strong><br /><strong>　　<span style="color: #0000ff">virtual</span> EnHandleResult OnSend(DWORD dwConnectionID, <span style="color: #0000ff">const</span> BYTE* pData, <span style="color: #0000ff">int</span> iLength);</strong><br /><strong>　　<span style="color: #0000ff">virtual</span> EnHandleResult OnReceive(DWORD dwConnectionID, <span style="color: #0000ff">const</span> BYTE* pData, <span style="color: #0000ff">int</span> iLen);</strong><br /><strong>　　<span style="color: #0000ff">virtual</span> EnHandleResult OnClose(DWORD dwConnectionID);</strong><br /><strong>　　<span style="color: #0000ff">virtual</span> EnHandleResult OnError(DWORD dwConnectionID, EnSocketOperation enOperation, <span style="color: #0000ff">int</span> iErrorCode);</strong><br /><br /><span style="color: #0000ff">private</span>:<br />    BOOL ParseReceiveBuffer();<br />    <br />    <span style="color: #008000">//</span><span style="color: #008000"> 其它方法 。。。<br /><br /></span><span style="color: #008000">//</span><span style="color: #008000"> 构造函数</span><span style="color: #008000"><br /></span><span style="color: #0000ff">public</span>:<br /><strong>　　CMainClient()</strong><br /><strong>　　<span style="color: #008000">//</span><span style="color: #008000"> 创建组件，并把自己设置为组件的监听器</span><span style="color: #008000"><br /></span>　　: m_pscClient(<span style="color: #0000ff">new</span> CSocketClient(<span style="color: #0000ff">this</span>))</strong><br /><strong>　　, m_dwConnID(<span style="color: #800080">0</span>)</strong><br /><strong>　　{</strong><br /><strong>　　}</strong><br /><br />    <span style="color: #0000ff">virtual</span> ~CMainClient()    {}<br /><br /><span style="color: #0000ff">private</span>:<br />　　<span style="color: #008000">//</span><span style="color: #008000"> 组件属性</span><span style="color: #008000"><br /></span><strong>　　ISocketClientPtr m_pscClient;</strong><br />    DWORD               m_dwConnID;<br />    <br />    <span style="color: #008000">//</span><span style="color: #008000"> 其它属性 。。。</span><span style="color: #008000"><br /></span>};</pre></div>
<p>&nbsp;</p>
<div class="cnblogs_code"><pre>BOOL CMainClient::Login(LPCTSTR pszAddress, USHORT usPort, <span style="color: #0000ff">const</span> T_101_Data* pData)<br />{<br />    <span style="color: #008000">//</span><span style="color: #008000"> 启动通信</span><span style="color: #008000"><br /></span>    <span style="color: #0000ff">return</span>    <strong>m_pscClient-&gt;Start</strong>(pszAddress, usPort) &amp;&amp;<br />            SendData(CS_C_LOGIN_REQ, pData, <span style="color: #0000ff">sizeof</span>(T_101_Data));<br />}<br /><br />BOOL CMainClient::Logout(<span style="color: #0000ff">const</span> T_201_Data* pData)<br />{<br />    <span style="color: #0000ff">if</span>(pData)<br />    {<br />        SendData(CS_C_SET_STATUS, pData, <span style="color: #0000ff">sizeof</span>(T_201_Data));<br />        ::WaitWithMessageLoop(LOGOUT_WAIT_TIME);<br />    }<br /><br />    <span style="color: #008000">//</span><span style="color: #008000"> 停止通信</span><span style="color: #008000"><br /></span>    <span style="color: #0000ff">return</span> <strong>m_pscClient-&gt;Stop()</strong>;<br />}<br /><br />BOOL CMainClient::SendData(EnCommandType enCmdType, <span style="color: #0000ff">const</span> TCommandData* pCmdData, WORD wCmdDataLen)<br />{<br />    <span style="color: #0000ff">const</span> WORD wBufferLen    = CMD_ADDITIVE_SIZE + wCmdDataLen;<br />    CPrivateHeapByteBuffer buffer(m_hpPrivate, wBufferLen);<br />    BYTE* pBuffer    = buffer;<br /><br />    memcpy(pBuffer, &amp;wBufferLen, CMD_LEN_SIZE);<br />    pBuffer += CMD_LEN_SIZE;<br />    memcpy(pBuffer, &amp;enCmdType, CMD_TYPE_SIZE);<br />    pBuffer += CMD_TYPE_SIZE;<br />    memcpy(pBuffer, pCmdData, wCmdDataLen);<br />    pBuffer += wCmdDataLen;<br />    memcpy(pBuffer, &amp;CMD_FLAG, CMD_FLAG_SIZE);<br /><br />    <span style="color: #008000">//</span><span style="color: #008000"> 发送数据</span><span style="color: #008000"><br /></span>    <span style="color: #0000ff">return</span> <strong>m_pscClient-&gt;Send(m_dwConnID, buffer, wBufferLen)</strong>;<br />}<br /><br /><span style="color: #0000ff">long</span> CMainClient::GetLastError()<br />{<br />    <span style="color: #008000">//</span><span style="color: #008000"> 获取通信错误码</span><span style="color: #008000"><br /></span>    <span style="color: #0000ff">return</span> <strong>m_pscClient-&gt;GetLastError()</strong>;<br />}<br /><br />LPCTSTR CMainClient::GetLastErrorDesc()<br />{<br />    <span style="color: #008000">//</span><span style="color: #008000"> 获取通信错误描述</span><span style="color: #008000"><br /></span>    <span style="color: #0000ff">return</span> <strong>m_pscClient-&gt;GetLastErrorDesc()</strong>;<br />}<br /><br /><strong><span style="color: #008000">/*</span><span style="color: #008000"> 处理连接成功事件 </span><span style="color: #008000">*/</span></strong><br /><strong>ISocketListener::EnHandleResult CMainClient::OnConnect(DWORD dwConnectionID)</strong><br />{<br />    TRACE1(<span style="color: #800000">"</span><span style="color: #800000">&lt;CNNID: %d&gt; 已连接\n</span><span style="color: #800000">"</span>, dwConnectionID);<br />    m_dwConnID = dwConnectionID;<br />    <span style="color: #0000ff">return</span> HR_OK;<br />}<br /><br /><strong><span style="color: #008000">/*</span><span style="color: #008000"> 处理数据已发出事件 </span><span style="color: #008000">*/</span></strong><br /><strong>ISocketListener::EnHandleResult CMainClient::OnSend(DWORD dwConnectionID, <span style="color: #0000ff">const</span> BYTE* pData, <span style="color: #0000ff">int</span> iLength)</strong><br />{<br />    TRACE2(<span style="color: #800000">"</span><span style="color: #800000">&lt;CNNID: %d&gt; 发出数据包 (%d bytes)\n</span><span style="color: #800000">"</span>, dwConnectionID, iLength);<br />    <span style="color: #0000ff">return</span> HR_OK;<br />}<br /><br /><strong><span style="color: #008000">/*</span><span style="color: #008000"> 处理接收到数据事件</span></strong><strong><span style="color: #008000">*/</span></strong><br /><strong>ISocketListener::EnHandleResult CMainClient::OnReceive(DWORD dwConnectionID, <span style="color: #0000ff">const</span> BYTE* pData, <span style="color: #0000ff">int</span> iLen)</strong><br />{<br />    TRACE2(<span style="color: #800000">"</span><span style="color: #800000">&lt;CNNID: %d&gt; 接收数据包 (%d bytes)\n</span><span style="color: #800000">"</span>, dwConnectionID, iLen);<br /><br />    ASSERT(pData != NULL &amp;&amp; iLen &gt; <span style="color: #800080">0</span>);<br /><br />    <span style="color: #008000">//</span><span style="color: #008000"> 保存数据</span><span style="color: #008000"><br /></span>    m_rcBuffer.Cat(pData, iLen);<br /><br />    <span style="color: #008000">//</span><span style="color: #008000"> 解析数据</span><span style="color: #008000"><br /></span>    <span style="color: #0000ff">return</span> ParseReceiveBuffer() ? HR_OK : HR_ERROR;;<br />}<br /><br /><strong><span style="color: #008000">/*</span><span style="color: #008000"> 处理通信关闭事件</span></strong><strong><span style="color: #008000">*/</span></strong><br /><strong>ISocketListener::EnHandleResult CMainClient::OnClose(DWORD dwConnectionID)</strong><br />{<br />    TRACE1(<span style="color: #800000">"</span><span style="color: #800000">CNNID: %d&gt; 关闭连接\n</span><span style="color: #800000">"</span>, dwConnectionID);<br /><br />    <span style="color: #008000">//</span><span style="color: #008000"> 清理缓冲区</span><span style="color: #008000"><br /></span>    m_rcBuffer.Realloc(<span style="color: #800080">0</span>);<br />    <span style="color: #0000ff">return</span> HR_OK;<br />}<br /><br /><strong><span style="color: #008000">/*</span><span style="color: #008000"> 处理通信错误事件 </span></strong><span style="color: #008000">*/</span><br /><strong>ISocketListener::EnHandleResult CMainClient::OnError(DWORD dwConnectionID, EnSocketOperation enOperation, <span style="color: #0000ff">int</span> iErrorCode)</strong><br />{<br />    TRACE3(<span style="color: #800000">"</span><span style="color: #800000">&lt;CNNID: %d&gt; 网络错误 (OP: %d, CO: %d)\n</span><span style="color: #800000">"</span>, dwConnectionID, enOperation, iErrorCode);<br /><br />    <span style="color: #008000">//</span><span style="color: #008000"> 清理缓冲区</span><span style="color: #008000"><br /></span>    m_rcBuffer.Realloc(<span style="color: #800080">0</span>);<br /><br />    <span style="color: #0000ff">return</span> HR_OK;<br />}</pre></div>
<p>&nbsp;</p>
<p>　　好了，码了一个晚上的字，累啊！到此为止吧，感谢收看~</p>
<p>　　敬请继续收看《<a href="http://www.cnblogs.com/ldcsaa/archive/2012/02/25/2367409.html" target="_blank"><strong>基于 IOCP 的通用异步 Windows Socket TCP 高性能服务端组件的设计与实现</strong></a>》，晚安 ^_^</p>
<p>&nbsp;</p>
<p>　　（<a href="http://files.cnblogs.com/ldcsaa/socket.zip" target="_blank">想看源代码的朋友请狂点这里</a>）<br />&nbsp;</p>
<p><strong style="color: #800000">原文出处：<a href="http://www.cnblogs.com/ldcsaa" target="_blank"><strong>怪兽的博客</strong></a><strong>&nbsp;&nbsp;</strong><a href="http://weibo.com/u/1402935851" target="_blank"><strong>怪兽的微博</strong></a><strong>&nbsp;&nbsp;</strong><a href="http://qun.qq.com/#jointhegroup/gid/75375912" target="_blank"><strong>怪兽乐园Q群</strong></a></strong></p><img src ="http://www.cppblog.com/ldcsaa/aggbug/171450.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ldcsaa/" target="_blank">~怪^_*兽~</a> 2012-04-15 10:42 <a href="http://www.cppblog.com/ldcsaa/archive/2012/04/15/171450.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>