﻿<?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://www.cppblog.com/tx7do/category/1517.html</link><description>严以律己,宽以待人. 三思而后行.&lt;/br&gt;
GMail/GTalk: yanglinbo#google.com;&lt;/br&gt;
MSN/Email: tx7do#yahoo.com.cn;&lt;/br&gt;
QQ: 3 0 3 3 9 6 9 2 0 .</description><language>zh-cn</language><lastBuildDate>Tue, 01 Apr 2014 15:47:46 GMT</lastBuildDate><pubDate>Tue, 01 Apr 2014 15:47:46 GMT</pubDate><ttl>60</ttl><item><title>使用libcurl实现的上传器</title><link>http://www.cppblog.com/tx7do/archive/2014/04/01/206424.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Tue, 01 Apr 2014 15:23:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2014/04/01/206424.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/206424.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2014/04/01/206424.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/206424.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/206424.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 头文件Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->/**//***********************************************************************&nbsp;Copyright&nbsp;...&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/archive/2014/04/01/206424.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/206424.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2014-04-01 23:23 <a href="http://www.cppblog.com/tx7do/archive/2014/04/01/206424.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>剖析 epoll ET/LT 触发方式的性能差异误解（定性分析）</title><link>http://www.cppblog.com/tx7do/archive/2013/04/20/199579.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 19 Apr 2013 16:59:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2013/04/20/199579.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/199579.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2013/04/20/199579.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/199579.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/199579.html</trackback:ping><description><![CDATA[<div><strong style="color: red">转载自:</strong><a style="color: red" href="http://blog.linezing.com/2011/01/%E5%89%96%E6%9E%90-epoll-etlt-%E8%A7%A6%E5%8F%91%E6%96%B9%E5%BC%8F%E7%9A%84%E6%80%A7%E8%83%BD%E5%B7%AE%E5%BC%82%E8%AF%AF%E8%A7%A3%EF%BC%88%E5%AE%9A%E6%80%A7%E5%88%86%E6%9E%90%EF%BC%89"><strong>http://blog.linezing.com/2011/01/%E5%89%96%E6%9E%90-epoll-etlt-%E8%A7%A6%E5%8F%91%E6%96%B9%E5%BC%8F%E7%9A%84%E6%80%A7%E8%83%BD%E5%B7%AE%E5%BC%82%E8%AF%AF%E8%A7%A3%EF%BC%88%E5%AE%9A%E6%80%A7%E5%88%86%E6%9E%90%EF%BC%89</strong></a><br /><br />
<div style="text-align: left; padding-bottom: 0px; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; letter-spacing: normal; padding-right: 0px; font: 12px 'Microsoft Yahei', Tahoma, Arial, Helvetica, sans-serif; white-space: normal; color: rgb(51,51,51); overflow: hidden; word-spacing: 0px; padding-top: 18px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="entry">
<p style="padding-bottom: 0px; line-height: 18px; margin: 0px 0px 18px; padding-left: 0px; padding-right: 0px; font-family: 微软雅黑; color: black; font-size: 16px; padding-top: 0px">平时大家使用 epoll 时都知道其事件触发模式有默认的 level-trigger 模式和通过 EPOLLET 启用的 edge-trigger 模式两种。从 epoll 发展历史来看，它刚诞生时只有 edge-trigger 模式，后来因容易产生 race-cond 且不易被开发者理解，又增加了 level-trigger 模式并作为默认处理方式。</p>
<p style="padding-bottom: 0px; line-height: 18px; margin: 0px 0px 18px; padding-left: 0px; padding-right: 0px; font-family: 微软雅黑; color: black; font-size: 16px; padding-top: 0px">二者的差异在于 level-trigger 模式下只要某个 fd 处于 readable/writable 状态，无论什么时候进行 epoll_wait 都会返回该 fd；而 edge-trigger 模式下只有某个 fd 从 unreadable 变为 readable 或从 unwritable 变为 writable 时，epoll_wait 才会返回该 fd。</p>
<p style="padding-bottom: 0px; line-height: 18px; margin: 0px 0px 18px; padding-left: 0px; padding-right: 0px; font-family: 微软雅黑; color: black; font-size: 16px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">通常的误区是：level-trigger 模式在 epoll 池中存在大量 fd 时效率要显著低于 edge-trigger 模式。</strong></p>
<p style="padding-bottom: 0px; line-height: 18px; margin: 0px 0px 18px; padding-left: 0px; padding-right: 0px; font-family: 微软雅黑; color: black; font-size: 16px; padding-top: 0px">但从 kernel 代码来看，edge-trigger/level-trigger 模式的处理逻辑几乎完全相同，差别仅在于 level-trigger 模式在 event 发生时不会将其从 ready list 中移除，略为增大了 event 处理过程中 kernel space 中记录数据的大小。</p>
<p style="padding-bottom: 0px; line-height: 18px; margin: 0px 0px 18px; padding-left: 0px; padding-right: 0px; font-family: 微软雅黑; color: black; font-size: 16px; padding-top: 0px">然而，edge-trigger 模式一定要配合 user app 中的 ready list 结构，以便收集已出现 event 的 fd，再通过 round-robin 方式挨个处理，以此避免通信数据量很大时出现忙于处理热点 fd 而导致非热点 fd 饿死的现象。统观 kernel 和 user space，由于 user app 中 ready list 的实现千奇百怪，不一定都经过仔细的推敲优化，因此 edge-trigger 的总内存开销往往还大于 level-trigger 的开销。</p>
<p style="padding-bottom: 0px; line-height: 18px; margin: 0px 0px 18px; padding-left: 0px; padding-right: 0px; font-family: 微软雅黑; color: black; font-size: 16px; padding-top: 0px">一般号称 edge-trigger 模式的优势在于能够减少 epoll 相关系统调用，这话不假，但 user app 里可不是只有 epoll 相关系统调用吧？为了绕过饿死问题，edge-trigger 模式的 user app 要自行进行 read/write 循环处理，这其中增加的系统调用和减少的 epoll 系统调用加起来，有谁能说一定就能明显地快起来呢？</p>
<p style="padding-bottom: 0px; line-height: 18px; margin: 0px 0px 18px; padding-left: 0px; padding-right: 0px; font-family: 微软雅黑; color: black; font-size: 16px; padding-top: 0px">实际上，epoll_wait 的效率是 O(ready fd num) 级别的，因此 edge-trigger 模式的真正优势在于减少了每次 epoll_wait 可能需要返回的 fd 数量，在并发 event 数量极多的情况下能加快 epoll_wait 的处理速度，但别忘了这只是针对 epoll 体系自己而言的提升，与此同时 user app 需要增加复杂的逻辑、花费更多的 cpu/mem 与其配合工作，总体性能收益究竟如何？只有实际测量才知道，无法一概而论。不过，为了降低处理逻辑复杂度，常用的事件处理库大部分都选择了 level-trigger 模式（如 libevent、boost::asio等）</p>
<p style="padding-bottom: 0px; line-height: 18px; margin: 0px 0px 18px; padding-left: 0px; padding-right: 0px; font-family: 微软雅黑; color: black; font-size: 16px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">结论：<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" />&#8226; epoll 的 edge-trigger 和 level-trigger 模式处理逻辑差异极小，性能测试结果表明常规应用场景 中二者性能差异可以忽略。<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" />&#8226; 使用 edge-trigger 的 user app 比使用 level-trigger 的逻辑复杂，出错概率更高。<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" />&#8226; edge-trigger 和 level-trigger 的性能差异主要在于 epoll_wait 系统调用的处理速度，是否是 user app 的性能瓶颈需要视应用场景而定，不可一概而论。</strong></p>
<p style="padding-bottom: 0px; line-height: 18px; margin: 0px 0px 18px; padding-left: 0px; padding-right: 0px; font-family: 微软雅黑; color: black; font-size: 14px; padding-top: 0px">欢迎就此话题进行深入调研、讨论！</p>
<p style="padding-bottom: 0px; line-height: 18px; margin: 0px 0px 18px; padding-left: 0px; padding-right: 0px; font-family: 微软雅黑; color: black; font-size: 12px; padding-top: 0px">参考资料：<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" />&#8226; linux kernel source：fs/eventpoll.c<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" />&#8226; &#8220;Comparing and Evaluating epoll, select, and poll Event<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" />Mechanisms&#8221;：http://bcr2.uwaterloo.ca/~brecht/papers/getpaper.php?file=ols-2004.pdf<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" />&#8226; &#8220;Edge-triggered interfaces are too difficult?&#8221;：http://lwn.net/Articles/25137/</p>
<p style="padding-bottom: 0px; line-height: 18px; margin: 0px 0px 18px; padding-left: 0px; padding-right: 0px; padding-top: 0px">By QingWu</p></div>
<p style="text-align: left; padding-bottom: 0px; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px 0px 18px; padding-left: 0px; letter-spacing: normal; padding-right: 0px; font: 12px/18px 'Microsoft Yahei', Tahoma, Arial, Helvetica, sans-serif; white-space: normal; color: rgb(153,153,153); overflow: hidden; word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="post-info-bottom"><br class="Apple-interchange-newline" /></p></div><img src ="http://www.cppblog.com/tx7do/aggbug/199579.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2013-04-20 00:59 <a href="http://www.cppblog.com/tx7do/archive/2013/04/20/199579.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网页游戏分线到不分线</title><link>http://www.cppblog.com/tx7do/archive/2012/11/22/195532.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Thu, 22 Nov 2012 03:16:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2012/11/22/195532.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/195532.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2012/11/22/195532.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/195532.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/195532.html</trackback:ping><description><![CDATA[<div><strong style="color: red">转载自：</strong><a style="color: red" href="http://www.cnblogs.com/me-sa/archive/2011/12/10/erlang0020.html"><strong>http://www.cnblogs.com/me-sa/archive/2011/12/10/erlang0020.html</strong></a><br /><br />
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp;&nbsp; 这一年来可以明显看到一个变化：网页游戏分线从标配逐渐变成了可选，越来越多的游戏开始不分线；当初为什么要分线？现在为什么又不分线？技术上面临着什么挑战？仅仅是技术问题么？</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><strong>术语解释</strong></p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp; 不同的技术实现"一条线"的概念也不尽相同，我们使用的Erlang实现，这里的一条线对应Erlang的一个VM.</p>
<h1 style="background-image: url(http://common.cnblogs.com/Skins/redcross/images/bg_title.gif); border-bottom: rgb(204,204,204) 0px dashed; text-align: left; line-height: 18px; widows: 2; text-transform: none; background-color: rgb(255,255,255); font-variant: normal; font-style: normal; text-indent: 0px; margin: 10px 0px; padding-left: 10px; letter-spacing: normal; font-family: Verdana, Helvetica, Arial; white-space: normal; orphans: 2; height: 23px; color: white; font-size: 12px; word-spacing: 0px; padding-top: 2px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">为什么要分线？</h1>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp;&nbsp; 可以通过比较来回答这个问题：所有玩家都在同一条线上 VS 同样数量的玩家被分配在多条线；如果所有玩家(假定1000人)都在一条线上首先同一场景的玩家数就会比较高，特别是一些游戏的热点区域比如副本入口，主城中心，传送门等等，当然同屏人数也会高；服务器端对应相关场景的广播压力，和业务逻辑的运算压力都集中在一条线上。而进行了分线之后，相当于把玩家做了分流，同一场景以及同屏的人数都会减少，一方面服务器端单条线的运算压力下降了，另一方面客户端的同屏人数也降了下来；</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp;分线实际上帮服务器端和客户端都减轻了压力，特别是很长一段时间内Flash客户端的同屏人数一直有人数限制，多数游戏能做到100多人，不会超过200人；这实际上是木桶理论中的短板，即使服务器端能做到不分线，客户端也支撑不了那么高的同屏；（当然现在这个问题已经有了突破）</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 总结一下，为什么分线：分担运算压力 同屏人数限制</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;</p>
<h1 style="background-image: url(http://common.cnblogs.com/Skins/redcross/images/bg_title.gif); border-bottom: rgb(204,204,204) 0px dashed; text-align: left; line-height: 18px; widows: 2; text-transform: none; background-color: rgb(255,255,255); font-variant: normal; font-style: normal; text-indent: 0px; margin: 10px 0px; padding-left: 10px; letter-spacing: normal; font-family: Verdana, Helvetica, Arial; white-space: normal; orphans: 2; height: 23px; color: white; font-size: 12px; word-spacing: 0px; padding-top: 2px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">分线对设计的影响</h1>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp; 分线实际上是突破技术瓶颈支撑更多玩家的方案，一旦分线自然就会带来"换线"和"跨线"的问题；所谓换线，就是玩家显示的从一条线路切换到另一条线路；不在同一条线的玩家就属于"跨线"；玩家一个在1线，一个在2线，他们要交易怎么办？组队呢？聊天呢？战斗呢？即使是忽略掉交互的因素，只看一个玩家，这一个玩家上线应该选择哪条线？如果玩家在战斗，交易，挂机等状态下能够换线么？在这些状态下下线然后上线怎么处理？</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 本质上换线实际上是玩家数据从一个Erlang节点迁移到另一个Erlang节点，有一个销毁和重建的过程；而跨线是两个玩家的数据在不同的Erlang节点内。</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 一部分解决方案是来自于策划，会有一些游戏状态的互斥，比如不允许跨线交易，不允许在修炼状态换线，等等；另外一方面就要在做设计的时候充分考虑分线了：</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp; 玩家不在一条线怎么办？玩家当前能不能换线？玩家在当前这个状态换线了怎么办？玩家下线之后再上线怎么办？我这个服务是全局的应该怎么办？......</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp; 具体技术实现上，Erlang做这个有先天优势，启动多个节点，设计一个网关节点做负载均衡；做水平扩展是很容易的。</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;</p>
<h1 style="background-image: url(http://common.cnblogs.com/Skins/redcross/images/bg_title.gif); border-bottom: rgb(204,204,204) 0px dashed; text-align: left; line-height: 18px; widows: 2; text-transform: none; background-color: rgb(255,255,255); font-variant: normal; font-style: normal; text-indent: 0px; margin: 10px 0px; padding-left: 10px; letter-spacing: normal; font-family: Verdana, Helvetica, Arial; white-space: normal; orphans: 2; height: 23px; color: white; font-size: 12px; word-spacing: 0px; padding-top: 2px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">分线血泪</h1>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 可以发现分线的设计需要在完成某一个功能的同时考虑到多条线的情况，会增加问题的复杂度；我不知道有多少采取分线策略的游戏曾经因为分线栽过跟头,我们就差点因为分线的一个bug把游戏经济系统搞死；事情大概经过：</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 某周日23点左右 运营的同事告诉我游戏内有玩家金币异常</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp;23:30左右到公司&nbsp; 封号，分析日志，发现金币来源应该是玩家交易，排除服务器被攻击可能</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 0点左右&nbsp; 封锁了交易的所有协议，停服更新</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 1点左右 发现还有一处可能出现问题的地方 再次更新</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 2点 从玩家日志库抓取异常玩家的数据做分析 发现玩家金币成倍增长2 4 8 16 32 64 也就是说，金币被&#8221;复制了&#8220;，但是玩家怎么做到的？是自己和自己交易么？分析代码虽然缺少这个防护，但是交易使用的SQL也保证了他得不到收益。</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 3:00 ~5:00 在本地测试环境，反复模拟各种情况下的交易，答案：当时游戏存在一个分线选择的bug导致玩家可以同时登陆两条线，玩家使用两个账号反复登陆换线，然后进行交易就可以把金币通过交易复制；&nbsp;&nbsp;</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp; 6点左右补丁做好热更新第一个版本</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp; 7点左右客户端补丁也做了分发</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 第二天运营提交了相关账号的修复规则，一个游戏的充值有一个前提保证就是游戏内的经济系统稳定，一旦出现刷金币之类的事情搞乱了经济系统，这个游戏服也就死掉了；</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;</p>
<h1 style="background-image: url(http://common.cnblogs.com/Skins/redcross/images/bg_title.gif); border-bottom: rgb(204,204,204) 0px dashed; text-align: left; line-height: 18px; widows: 2; text-transform: none; background-color: rgb(255,255,255); font-variant: normal; font-style: normal; text-indent: 0px; margin: 10px 0px; padding-left: 10px; letter-spacing: normal; font-family: Verdana, Helvetica, Arial; white-space: normal; orphans: 2; height: 23px; color: white; font-size: 12px; word-spacing: 0px; padding-top: 2px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">为什么不分线了？</h1>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp; 首先分线的种种限制，比如跨线不能交易等等增加了玩家操作步骤，需要玩家先选择换线；另外，分线分流玩家分散了压力也分散了人气，显得游戏不热闹；</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp;&nbsp;其次在Flash同屏问题已经有了优化方案，可以看一下现在非常火爆的神魔遮天，它的同屏人数远远超出了100的限制；观察一下神魔遮天的处理，当一个区域聚集了很多人的时候，它并不是一下全部渲染出来，而是一个一个渲染出来的；还有一些客户端的优化策略，这些方案的组合结果就是同屏人数可以更多；</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;</p>
<h1 style="background-image: url(http://common.cnblogs.com/Skins/redcross/images/bg_title.gif); border-bottom: rgb(204,204,204) 0px dashed; text-align: left; line-height: 18px; widows: 2; text-transform: none; background-color: rgb(255,255,255); font-variant: normal; font-style: normal; text-indent: 0px; margin: 10px 0px; padding-left: 10px; letter-spacing: normal; font-family: Verdana, Helvetica, Arial; white-space: normal; orphans: 2; height: 23px; color: white; font-size: 12px; word-spacing: 0px; padding-top: 2px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">怎么实现？</h1>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp; 有的不分线是通过拆分游戏的功能模块实现的，比如把场景运算放在单独的erlang节点，以功能为单位拆分成多个节点分担压力；一旦压力上去就可以通过增加对应的功能节点来缓解压力；实际上是换了一种分担压力的方式，对于客户端和玩家这些都是透明的。</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 我们从分线到不分线更困难一些，之前所有的逻辑都是在一个节点内完成，很难按照功能拆分游戏，那将是颠覆性的。咨询立涛，他给我们的建议是只开一条线，开启SMP，单线支撑2000~3000人应该没有问题。</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; Erlang SMP VM比普通Erlang VM要慢那么一点点，但是可以充分发挥多核优势&nbsp;摘录一点资料：</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 从OTP R12B开始，如果操作系统报告有多于1个的CPU（或者核心）VM的SMP版本会自动启动，并且根据CPU或者核心的数量启动同样数量的调度器。</p>
<p style="text-align: justify; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px 0px 1.5em; padding-left: 0px; letter-spacing: normal; padding-right: 0px; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp; 没有SMP支持的Erlang VM只有1个运行在主处理线程中的调度器。该调度器从运行队列（run-queue）中取出可以运行的Erlang进程以及IO任务，而且因为只有一个线程访问他们所以无须锁定任何数据。而带有SMP支持的Erlang VM可以有一个或多个调度器，每个运行在一个线程中。调度器从同一个公共运行队列中取出可运行的Erlang进程和IO任务。在SMP VM中所有的共享数据结构都会由锁进行保护，运行队列就是这样一个由锁保护的数据结构。</p>
<p style="text-align: justify; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px 0px 1.5em; padding-left: 0px; letter-spacing: normal; padding-right: 0px; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 详情看这里：<a style="color: gray; text-decoration: " href="http://shiningray.cn/some-facts-about-erlang-and-smp.html">http://shiningray.cn/some-facts-about-erlang-and-smp.html</a></p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 实践过程中，我们还是采取了一个折中的方案，只要玩家在一条线上不超过阈值，就只开启这一条线，客户端也没有线路选择的功能，如果超过阈值，就开启新线路，并通知客户端显示选线功能；</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;</p>
<h1 style="background-image: url(http://common.cnblogs.com/Skins/redcross/images/bg_title.gif); border-bottom: rgb(204,204,204) 0px dashed; text-align: left; line-height: 18px; widows: 2; text-transform: none; background-color: rgb(255,255,255); font-variant: normal; font-style: normal; text-indent: 0px; margin: 10px 0px; padding-left: 10px; letter-spacing: normal; font-family: Verdana, Helvetica, Arial; white-space: normal; orphans: 2; height: 23px; color: white; font-size: 12px; word-spacing: 0px; padding-top: 2px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">仅仅是技术问题么？</h1>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp;&nbsp;从分线到不分线不仅仅是技术问题，策划同样要做调整，比如游戏内的一些容易堆积玩家的区域要想办法分散压力，比如增加入口，修改NPC位置等等；还有一些数值限制也需要重新考虑，比如一个活动分线模式最多只允许30个玩家参与，不分线了这个限制就要改掉否则大部分玩家都参与不了这个活动。</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;&nbsp; 单服最高在线超过3000人怎么办？首先现在游戏平台能推到这个在线的情况都很少了；其次如果超过这个值，一般都是开启新服，也就是通过运营手段而非技术手段解决这个问题。</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp;</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp; 从分线到不分线，下一站是什么？一个世界？</p>
<p style="text-align: justify; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 10px auto; letter-spacing: normal; font: 12px/18px Verdana, Helvetica, Arial; white-space: normal; orphans: 2; color: rgb(48,48,48); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">&nbsp; 对于开发者，下一战又是什么？</p><br class="Apple-interchange-newline" /></div><img src ="http://www.cppblog.com/tx7do/aggbug/195532.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2012-11-22 11:16 <a href="http://www.cppblog.com/tx7do/archive/2012/11/22/195532.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Google开源实时通信项目WebRTC</title><link>http://www.cppblog.com/tx7do/archive/2012/10/24/193776.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Wed, 24 Oct 2012 06:26:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2012/10/24/193776.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/193776.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2012/10/24/193776.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/193776.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/193776.html</trackback:ping><description><![CDATA[<div><strong style="color: red">转载自:</strong><a style="color: red" href="http://www.infoq.com/cn/news/2011/06/google-webrtc"><strong>http://www.infoq.com/cn/news/2011/06/google-webrtc</strong></a><br /><br />
<div style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; font: 13px/19px Lucida, 'Lucida Grande', Tahoma, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" id="newsContent">
<p>最近，Google正式开源了<a style="color: rgb(11,89,178); text-decoration: underline" href="http://sites.google.com/site/webrtc/home">WebRTC实时通信项目</a>，希望浏览器厂商能够将该技术内建在浏览器中，从而使Web应用开发人员能够通过HTML标签和JavaScript API就实现Web音频、视频通信功能。</p>
<p>WebRTC（Web Real Time Communication）并不是Google原来自己的技术。在2010年，Google以大约6820万美元<a style="color: rgb(11,89,178); text-decoration: underline" href="http://www.computerworld.com/s/article/9176906/Google_to_acquire_voice_and_video_codec_company">收购</a>了VoIP软件开发商Global IP Solutions公司，并因此获得了该公司拥有的WebRTC技术。如今，互联网的音频、视频通信服务技术一般都是私有技术，如<a style="color: rgb(11,89,178); text-decoration: underline" href="http://www.skype.com/">Skype</a>， 需要通过安装插件或者桌面客户端来实现通信功能。Google希望Web开发人员能够直接在浏览器中创建视频或语音聊天应用，Global IP Solutions公司之前已经针对Android、Windows Mobile、iPhone制作了基于WebRTC的移动客户端。Google此次将WebRTC开源出来，就是希望浏览器厂商能够将该技术直接内嵌到浏 览器中，从而方便Web开发人员。</p>
<p>WebRTC的<a style="color: rgb(11,89,178); text-decoration: underline" href="http://sites.google.com/site/webrtc/blog">博客</a>说明了WebRTC的优势和发展方向：</p>
<blockquote style="background-image: url(http://cdn2.infoq.com/styles/cn/i/bg-blockquote.gif); border-bottom: rgb(239,239,239) 2px solid; border-left: rgb(239,239,239) 2px solid; padding-bottom: 5px; background-color: rgb(250,250,250); padding-left: 5px; padding-right: 5px; background-position: 5px 5px; color: rgb(51,51,51); margin-left: 20px; border-top: rgb(239,239,239) 2px solid; margin-right: 0px; border-right: rgb(239,239,239) 2px solid; padding-top: 5px; border-image: initial; background-origin: initial; background-clip: initial">
<p style="margin-top: 0px">直到现在，实时通信仍然需要私有的信号处理技术，大部分都是通过插件和客户端来安装使用。我们通过WebRTC开源了收购GIPS后获得的音频、视频引擎技术，让开发人员能够了解信号处理技术，并使用了BSD风格的<a style="color: rgb(11,89,178); text-decoration: underline" href="http://sites.google.com/site/webrtc/license-rights/license">授权</a>。这会支持开发人员通过简单的HTML和JavaScript API创建音频和视频聊天应用。</p>
<p style="margin-bottom: 0px">我们正在与其他浏览器开发厂商Mozilla和Opera等紧密合作，尽快在浏览器中实现这项技术以便于Web社区使用。此外，我们还积极地参与IETF和W3C工作组的活动，定义和实现一套实时通信标准。</p></blockquote>
<p>其<a style="color: rgb(11,89,178); text-decoration: underline" href="http://sites.google.com/site/webrtc/faq">官网</a>上列表了使用WebRTC技术的四个理由：</p>
<ol><li>互联网成功的一个关键因素是一些核心技术如HTML、HTTP和TCP/IP是开放和免费实现的。目前，在浏览器通信领域还没有免费、高质量、完整的解决方案。WebRTC就是这样的技术。</li><li>该技术已经集成了最佳的音频、视频引擎，并被部署到数以百万级的终端中，经过超过8年的磨练。Google不会从该技术中收取费用。</li><li>包含了使用STUN、ICE、TURN、RTP-over-TCP的关键NAT和防火墙穿越技术，并支持代理。</li><li>构建在浏览器中，WebRTC通过提供直接映射到PeerConnection的信号状态机来抽象信号处理。Web开发人员因此可以选择适合应用场景的协议（例如：SIP、XMPP/Jingle等等）。</li></ol>
<p>WebRTC的架构图如下所示：</p>
<p align="center"><img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-image: initial" alt="" src="http://www.infoq.com/resource/news/2011/06/google-webrtc/zh/resources/11.png" _p="true" _href="img://11.png" /></p>
<p align="center">图 1 &nbsp;WebRTC架构图（图片来源：WebRTC官方网站）</p>
<p>关于架构图的组成部分，包括：</p>
<blockquote style="background-image: url(http://cdn2.infoq.com/styles/cn/i/bg-blockquote.gif); border-bottom: rgb(239,239,239) 2px solid; border-left: rgb(239,239,239) 2px solid; padding-bottom: 5px; background-color: rgb(250,250,250); padding-left: 5px; padding-right: 5px; background-position: 5px 5px; color: rgb(51,51,51); margin-left: 20px; border-top: rgb(239,239,239) 2px solid; margin-right: 0px; border-right: rgb(239,239,239) 2px solid; padding-top: 5px; border-image: initial; background-origin: initial; background-clip: initial">Web API&#8212;&#8212;第三方开发人员用来开发基于Web的应用，如视频聊天。<br />WebRTC Native C++ API&#8212;&#8212;浏览器厂商用于实现Web API的函数集。<br />Session Management&#8212;&#8212;抽象session层，支持调用构建和管理层，由应用开发者来决定如何实现协议。<br />VoiceEngine&#8212;&#8212;音频媒体链的框架，从声卡到网络。<br />iSAC&#8212;&#8212;一种用于VoIP和流音频的宽带和超宽带音频编解码器，iSAC采用16 kHz或32 kHz的采样频率和12&#8212;52 kbps的可变比特率。<br />iLBC&#8212;&#8212;用于VoIP和流音频的窄带语音编解码器，使用8 kHZ的采样频率，20毫秒帧比特率为15.2 kbps，30毫米帧的比特率为13.33 kbps，标准由IETF RFC 3951和3952定义。<br />NetEQ for Voice&#8212;&#8212;动态抖动缓存和错误隐藏算法，用于缓解网络抖动和丢包引起的负面影响。在保持高音频质量的同时尽可能降低延迟。<br />VideoEngine&#8212;&#8212;视频媒体链的框架，从相机像头到网络，从网络到屏幕。<br />VP8&#8212;&#8212;来自于WebM项目的视频编解码器，非常适合RTC，因为它是为低延迟而设计开发的。<br />Image enhancements&#8212;&#8212;消除通过摄像头获取的图片的视频噪声等。<br />其他更详细的架构分析可以查看这里的<a style="color: rgb(11,89,178); text-decoration: underline" href="http://sites.google.com/site/webrtc/reference/webrtc-components">文档</a>。</blockquote>
<p>PeerConnection位于WebRTC Native C++ API的最上层，它的代码实现来源于<a style="color: rgb(11,89,178); text-decoration: underline" href="http://code.google.com/apis/talk/libjingle/index.html">libjingle</a>（一款p2p开发工具包），目前被应用于WebRTC中。其中关键的两个类定义是：</p>
<blockquote style="background-image: url(http://cdn2.infoq.com/styles/cn/i/bg-blockquote.gif); border-bottom: rgb(239,239,239) 2px solid; border-left: rgb(239,239,239) 2px solid; padding-bottom: 5px; background-color: rgb(250,250,250); padding-left: 5px; padding-right: 5px; background-position: 5px 5px; color: rgb(51,51,51); margin-left: 20px; border-top: rgb(239,239,239) 2px solid; margin-right: 0px; border-right: rgb(239,239,239) 2px solid; padding-top: 5px; border-image: initial; background-origin: initial; background-clip: initial">class &nbsp;PeerConnectionObserver {<br />public:<br />&nbsp;virtual void OnError();<br />&nbsp;virtual void OnSignalingMessage(const std::string&amp; msg);<br />&nbsp;virtual void OnAddStream(const std::string&amp; stream_id,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int channel_id,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool video);<br />&nbsp;virtual void OnRemoveStream(const std::string&amp; stream_id,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int channel_id,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool video);<br />}; 
<p>该类定义了一个抽象的观察者。开发人员应该继承实现自己的观察者类。</p>class &nbsp;PeerConnection {<br />public:<br />&nbsp;explicit PeerConnection(const std::string&amp; config);<br />&nbsp;bool Initialize();<br />&nbsp;void RegisterObserver(PeerConnectionObserver* observer);<br />&nbsp;bool SignalingMessage(const std::string&amp; msg);<br />&nbsp;bool AddStream(const std::string&amp; stream_id, bool video);<br />&nbsp;bool RemoveStream(const std::string&amp; stream_id);<br />&nbsp;bool Connect();<br />&nbsp;void Close();<br />&nbsp;bool SetAudioDevice(const std::string&amp; wave_in_device,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const std::string&amp; wave_out_device);<br />&nbsp;bool SetLocalVideoRenderer(cricket::VideoRenderer* renderer);<br />&nbsp;bool SetVideoRenderer(const std::string&amp; stream_id,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cricket::VideoRenderer* renderer);<br />&nbsp;bool SetVideoCapture(const std::string&amp; cam_device);<br />};<br />
<p style="margin-bottom: 0px">具体的函数说明可以查看相应的<a style="color: rgb(11,89,178); text-decoration: underline" href="http://sites.google.com/site/webrtc/reference#TOC-PeerConnection-Native-APIs">API介绍</a>。</p></blockquote>
<p>正如Google所说的，它一直在参与制定和实现HTML 5标准中的<a style="color: rgb(11,89,178); text-decoration: underline" href="http://www.whatwg.org/specs/web-apps/current-work/complete/video-conferencing-and-peer-to-peer-communication.html">视频会议和p2p通信部分</a>，虽然还不是正式标准，但是我们可以从草案的示例中看到未来Web开发人员的使用情况：</p>
<blockquote style="background-image: url(http://cdn2.infoq.com/styles/cn/i/bg-blockquote.gif); border-bottom: rgb(239,239,239) 2px solid; border-left: rgb(239,239,239) 2px solid; padding-bottom: 5px; background-color: rgb(250,250,250); padding-left: 5px; padding-right: 5px; background-position: 5px 5px; color: rgb(51,51,51); margin-left: 20px; border-top: rgb(239,239,239) 2px solid; margin-right: 0px; border-right: rgb(239,239,239) 2px solid; padding-top: 5px; border-image: initial; background-origin: initial; background-clip: initial">// the first argument describes the STUN/TURN server configuration<br />var local = new PeerConnection('TURNS example.net', sendSignalingChannel);<br />local.signalingChannel(...); // if we have a message from the other side, pass it along here<br />// (aLocalStream is some GeneratedStream object)<br />local.addStream(aLocalStream); // start sending video<br />function sendSignalingChannel(message) {<br />&nbsp;... // send message to the other side via the signaling channel<br />}<br />function receiveSignalingChannel (message) {<br />&nbsp;// call this whenever we get a message on the signaling channel<br />&nbsp;local.signalingChannel(message);<br />}<br />local.onaddstream = function (event) {<br />&nbsp;// (videoElement is some &lt;video&gt; element)<br />&nbsp;videoElement.src = URL.getObjectURL(event.stream);<br />};<br /></blockquote>
<p>目前有关Web实时通信的技术标准正在制定当中，W3C的<a style="color: rgb(11,89,178); text-decoration: underline" href="http://www.w3.org/2011/04/webrtc-charter.html">Web Real-Time Communication工作组</a>今年五月份刚刚正式成立，并计划在今年第三季度发布第一个公开草案，从其工作组的路线图中可以看出，正式的推荐标准预计将在2013年第一季度发布，有关W3C标准是否会对WebRTC项目的发展有所影响，未来还要看草案的具体细节。</p>
<p>Google希望开源的WebRTC技术能够获得越来越多的浏览器厂商支持，WebRTC的网站已经宣布将在Chrome、Firefox和Opera上实现相应的API接口。Opera首席技术官H&#229;kon Wium Lie对媒体<a style="color: rgb(11,89,178); text-decoration: underline" href="http://www.theregister.co.uk/2011/06/01/google_open_sources_webrtc/">表示</a>，Google能够把价值不菲的代码贡献出来非常了不起，Opera一直希望能够在浏览器中实现实时通信技术。</p>
<p>提到实时通信技术，不得不让人想起行业巨头Skype。巧合的是，就在前不久，微软刚刚斥资85亿美元现金<a style="color: rgb(11,89,178); text-decoration: underline" href="http://news.ifeng.com/gundong/detail_2011_05/11/6302654_0.shtml">收购</a>网络电话服务商Skype，当时有许多分析师指出，<a style="color: rgb(11,89,178); text-decoration: underline" href="http://www.infoq.com/cn/news/2011/05/microsoft-skype">微软的收购将直面Google的竞争</a>：</p>
<blockquote style="background-image: url(http://cdn2.infoq.com/styles/cn/i/bg-blockquote.gif); border-bottom: rgb(239,239,239) 2px solid; border-left: rgb(239,239,239) 2px solid; padding-bottom: 5px; background-color: rgb(250,250,250); padding-left: 5px; padding-right: 5px; background-position: 5px 5px; color: rgb(51,51,51); margin-left: 20px; border-top: rgb(239,239,239) 2px solid; margin-right: 0px; border-right: rgb(239,239,239) 2px solid; padding-top: 5px; border-image: initial; background-origin: initial; background-clip: initial">
<p style="margin-top: 0px">&#8230;...收购也挫败了竞争对手Google利用Skype技术完善通话服务的计划。</p>
<p>MSN即时通讯、必应（bing）搜索、网络广告等成了微软在互联网领域迎战谷歌的三大阵地。然而，相对于谷歌在互联网行业的呼风唤雨，微软的互联网战略一直没有真正展现出让业界看到其能够挑战谷歌的核心优势。</p>
<p>谷歌和苹果都已经在网络电话上投入了数年时间。苹果一直在力推iChat和FaceTime，谷歌也在普及其网络通信相关产品Chat和Voice。不过，谷歌和苹果都有一个共同的问题，他们很难在竞争对手的平台上生存。苹果用户无法和谷歌以及微软的用户进行视频聊天，谷歌在跨 平台方面做了很多努力，但是仍有不少障碍。</p>
<p>不过Skype则没有这一问题，作为免费服务的Skype可以运行在苹果、Linux以及Windows电脑上，也支持Android和iPhone等手机平台，甚至可以在电视机上运行。</p>
<p style="margin-bottom: 0px">收购Skype，微软不仅仅是为了从中受益，微软还希望借此使Skype远离谷歌的&#8220;魔爪&#8221;。如果谷歌收购了Skype，这对微软来说无疑是一个沉重的打击。想想吧，如果谷歌收购了Skype，并将Skype整合进Google Apps、Gmail、Google Talk和Google Voice等谷歌产品之中，再想想如果谷歌将Skype与Android平台进行一些深度整合，这对微软来说，无疑是一场灾难。即便微软并未很好的将Skype整合进自家产品之中，但这也避免了谷歌通过收购Skype来获得巨大的价值。</p></blockquote>
<p>就在微软收购Skype不久，Google就宣布对WebRTC开源，这不免让人有所联想。有国外媒体<a style="color: rgb(11,89,178); text-decoration: underline" href="http://thenextweb.com/google/2011/06/01/google-releases-developer-preview-of-webrtc-its-open-real-time-voice-and-video-platform/">评论</a>说，Google此次开源是想让广大用户远离该行业的领导者如Skype和Apple的FaceTime平台。通过浏览器来支持实时通信技术，Google希望开发社区能够在自己的应用中集成该功能，从而削弱其他对手。</p>
<p>这已经不是Google第一次大方地开源关键项目。去年，Google曾经将VP8视频编解码项目开源，以支持HTML 5技术中的视频媒体播放。如今，多种主流浏览器都已经支持VP8格式，成为主要的多媒体格式，相比伴随着专利、付费纠纷的H.264，开放、免费的VP8更让浏览器厂商放心。</p>
<p>这次WebRTC的开源会对浏览器厂商和实时通信技术领域带来哪些影响，InfoQ中文站将持续关注和及时报道，也欢迎读者朋友发表自己的看法。</p>
<p id="lastElm"></p></div>
<p style="padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); list-style-type: none; margin-top: 5px; text-indent: 0px; padding-left: 0px; padding-right: 0px; font: 12px/19px Lucida, 'Lucida Grande', Tahoma, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(115,115,115); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="miniBio"><strong><a style="padding-bottom: 0px; padding-left: 2px; padding-right: 2px; color: rgb(28,73,123) !important; text-decoration: none; padding-top: 0px" class="editorlink f_taxonomyEditor" href="http://www.infoq.com/cn/author/%E5%B4%94%E5%BA%B7">崔康</a><span class="Apple-converted-space">&nbsp;</span></strong>热情的技术探索者，资深软件工程师，InfoQ编辑，从事企业级Web应用的相关工作，关注性能优化、Web技术、浏览器等领域。</p><br class="Apple-interchange-newline" /></div><img src ="http://www.cppblog.com/tx7do/aggbug/193776.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2012-10-24 14:26 <a href="http://www.cppblog.com/tx7do/archive/2012/10/24/193776.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>IOCP+UDP收包的时候:报0xC000000005，读取0x00000010错误的问题</title><link>http://www.cppblog.com/tx7do/archive/2012/10/15/193298.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Mon, 15 Oct 2012 03:42:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2012/10/15/193298.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/193298.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2012/10/15/193298.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/193298.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/193298.html</trackback:ping><description><![CDATA[最近发现我那简单得不再简单的IOCP+UDP的底层出错了,在大数据量的时候经常会报错,并且清一色都是报的:报0xC000000005，读取0x00000010错误.报错之后,整个程序的堆栈就全部破坏掉了.从发现问题到今日问题的解决,已经过去了一个月的时间.<br />唯一能够找到相关的资料只有:<a href="http://www.cppblog.com/HendricLee/archive/2008/07/29/57436.html">http://www.cppblog.com/HendricLee/archive/2008/07/29/57436.html</a><br />但是事实上,我的Overlapped都是复用的.因此,不大可能是此问题导致的.经过测试证明,也确实与此无关.<br />昨晚上又做了一系列的测试,结果到最后依旧是无果,百般无奈之下,只好问人,后面QQ好友Sagasarate告诉了我原委,我知道之后,只有两种感觉:想哭,想撞墙.<img border="0" alt="" src="http://www.cppblog.com/Emoticons/QQ/02.gif" width="20" height="20" /><br />至于为什么,请看以下代码便知了.非常非常之低级的错误.<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">bool</span><span style="color: #000000">&nbsp;CUDPRecvSendThread::postRecvRequest(CUdpOverLappedRecv</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;pOverLappedRecv)<br /><img id="Codehighlighter1_78_626_Open_Image" onclick="this.style.display='none'; Codehighlighter1_78_626_Open_Text.style.display='none'; Codehighlighter1_78_626_Closed_Image.style.display='inline'; Codehighlighter1_78_626_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_78_626_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_78_626_Closed_Text.style.display='none'; Codehighlighter1_78_626_Open_Image.style.display='inline'; Codehighlighter1_78_626_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_78_626_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_78_626_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;ASSERT(pOverLappedRecv);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(pOverLappedRecv&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;NULL)&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">false</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;pOverLappedRecv</span><span style="color: #000000">-&gt;</span><span style="color: #000000">Reset();<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwBytesRecv&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwFlags&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;nSenderAddrSize&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">sizeof</span><span style="color: #000000">&nbsp;(sockaddr_in);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;rc&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;rc&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;::WSARecvFrom(m_ServerSocket,&nbsp;pOverLappedRecv</span><span style="color: #000000">-&gt;</span><span style="color: #000000">GetWsaBuffer(),&nbsp;</span><span style="color: #000000">1</span><span style="color: #000000">,&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">dwBytesRecv,&nbsp;</span><span style="color: #000000">&amp;</span><span style="color: #000000">dwFlags,<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pOverLappedRecv</span><span style="color: #000000">-&gt;</span><span style="color: #000000">GetClientAddr(), &amp;nSenderAddrSize,<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pOverLappedRecv</span><span style="color: #000000">-&gt;</span><span style="color: #000000">GetOverlapped(),&nbsp;NULL);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(rc&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;SOCKET_ERROR)<br /><img id="Codehighlighter1_501_609_Open_Image" onclick="this.style.display='none'; Codehighlighter1_501_609_Open_Text.style.display='none'; Codehighlighter1_501_609_Closed_Image.style.display='inline'; Codehighlighter1_501_609_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_501_609_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_501_609_Closed_Text.style.display='none'; Codehighlighter1_501_609_Open_Image.style.display='inline'; Codehighlighter1_501_609_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_501_609_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_501_609_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwErrorCode&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;::WSAGetLastError();<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(dwErrorCode&nbsp;</span><span style="color: #000000">!=</span><span style="color: #000000">&nbsp;WSA_IO_PENDING)<br /><img id="Codehighlighter1_585_606_Open_Image" onclick="this.style.display='none'; Codehighlighter1_585_606_Open_Text.style.display='none'; Codehighlighter1_585_606_Closed_Image.style.display='inline'; Codehighlighter1_585_606_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_585_606_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_585_606_Closed_Text.style.display='none'; Codehighlighter1_585_606_Open_Image.style.display='inline'; Codehighlighter1_585_606_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_585_606_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_585_606_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">false</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">true</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span></div>请对照着MSDN看.<br />如果没看出来,那我来告诉你是为什么.<br />问题就在于WSARecvFrom的7个参数.<br />MSDN的描述:<br />
<dt style="widows: 2; text-transform: none; text-indent: 0px; font: 12px/16px 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: #000000; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><em>lpFromlen</em><span class="Apple-converted-space">&nbsp;</span>[in, out] 
</dt><dd style="widows: 2; text-transform: none; text-indent: 0px; font: 12px/16px 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: #000000; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">
<p style="padding-bottom: 15px; line-height: 18px; margin-top: 0px; margin-bottom: 0px; color: #2a2a2a">A pointer to the size, in bytes, of the "from" buffer required only if<span class="Apple-converted-space">&nbsp;</span><em>lpFrom</em><span class="Apple-converted-space">&nbsp;</span>is specified.<br /></p></dd>
<p style="widows: 2; text-transform: none; text-indent: 0px; font-family: 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif; font-style: normal; font-variant: normal; font-weight: normal; line-height: 16px; white-space: normal; orphans: 2; letter-spacing: normal; color: #000000; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; "><span style="font-size: 10pt; ">你会发现,这个参数是一个输入输出值.而WSARecvFrom投递的是一个异步的IOCP请求,故而,出了此方法(</span><span style="font-size: 12px;">CUDPRecvSendThread::postRecvRequest</span><span style="font-size: 10pt; ">)之后,nSenderAddrSize这个临时变量就会被回收.不出事才怪了.</span><br /><span style="font-size: 10pt; ">好吧,这事就是我干出来的.今年竟是做一些脑残的事情.肿么了我这是.T_T</span><br /><span style="font-size: 10pt; ">要解决这个问题,最好的办法就是把nSenderAddrSize作为CUdpOverLappedRecv的成员变量保存,这样生命周期可以得以保证.</span><br /><span style="font-size: 10pt; ">好吧,这件脑残事就这么结了. </span></p><img src ="http://www.cppblog.com/tx7do/aggbug/193298.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2012-10-15 11:42 <a href="http://www.cppblog.com/tx7do/archive/2012/10/15/193298.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>udp丢包 又是udp丢包</title><link>http://www.cppblog.com/tx7do/archive/2012/09/25/191901.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Mon, 24 Sep 2012 19:25:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2012/09/25/191901.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/191901.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2012/09/25/191901.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/191901.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/191901.html</trackback:ping><description><![CDATA[<strong style="color: red">转载自:</strong><a style="color: red" href="http://www.cnweblog.com/fly2700/archive/2011/09/19/317825.html"><strong>http://www.cnweblog.com/fly2700/archive/2011/09/19/317825.html</strong></a><br /><br />
<div style="widows: 2; text-transform: none; text-indent: 0px; font: 14px/21px Arial; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="postbody">
<p style="margin: 0px 0px 14px">什么会导致udp丢包呢，我这里列举了如下几点原因：</p>
<p style="margin: 0px 0px 14px">1.调用recv方法接收端收到数据后，处理数据花了一些时间，处理完后再次调用recv方法，在这二次调用间隔里,发过来的包可能丢失。对于这种情况可以修改接收端，将包接收后存入一个缓冲区，然后迅速返回继续recv。<br /><br />2.发送的包巨大丢包。虽然send方法会帮你做大包切割成小包发送的事情，但包太大也不行。例如超过30K的一个udp包，不切割直接通过send方法发送也会导致这个包丢失。这种情况需要切割成小包再逐个send。<br /><br />3.发送的包较大，超过mtu size数倍，几个大的udp包可能会超过接收者的缓冲，导致丢包。这种情况可以设置socket接收缓冲。以前遇到过这种问题，我把接收缓冲设置成64K就解决了。<br />int nRecvBuf=32*1024;//设置为32K<br />setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&amp;nRecvBuf,sizeof(int));<br /><br />4.发送的包频率太快，虽然每个包的大小都小于mtu size 但是频率太快，例如40多个mut size的包连续发送中间不sleep，也有可能导致丢包。这种情况也有时可以通过设置socket接收缓冲解决，但有时解决不了。<br /><br />5.发送的广播包或组播包在windws和linux下都接收正常，而arm上接收出现丢包。这个还不好解决，我的解决方法是大包切割成大小为1448的小包发送，每个包之间sleep 1毫秒，虽然笨，但有效。我这里mtu size为1500字节，减去udp包头8个字节，减去传输层几十个字节，实际数据位1448字节。<br />除此之外还可以试试设置arm操作系统缓冲：<br />//设置mtu size 1500最大<br />ifconfig eth0 mtu 1500<br />//查看接收缓冲最大和默认大小。<br />sysctl -A | grep rmem<br />//设置接收缓冲的最大大小<br />sysctl -w net.core.rmem_max=1048576<br />sysctl -w net.core.rmem_default=1048576<br />sysctl -w net.ipv4.udp_mem=1048576<br />sysctl -w net.ipv4.udp_rmem_min=1048576<br /><br />6,局域网内不丢包，公网上丢包。这个问题我也是通过切割小包并sleep发送解决的。如果流量太大，这个办法也不灵了。</p>
<p style="margin: 0px 0px 14px"><br />总之udp丢包总是会有的，如果出现了用我的方法解决不了，还有这个几个方法： 要么减小流量，要么换tcp协议传输，要么做丢包重传的工作</p></div><img src ="http://www.cppblog.com/tx7do/aggbug/191901.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2012-09-25 03:25 <a href="http://www.cppblog.com/tx7do/archive/2012/09/25/191901.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>糊涂窗口综合症和Nagle算法</title><link>http://www.cppblog.com/tx7do/archive/2012/09/25/191900.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Mon, 24 Sep 2012 19:08:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2012/09/25/191900.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/191900.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2012/09/25/191900.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/191900.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/191900.html</trackback:ping><description><![CDATA[<div><strong style="color: red">转载自:</strong><a style="color: red" href="http://www.cnblogs.com/zhaoyl/archive/2012/09/20/2695799.html"><strong>http://www.cnblogs.com/zhaoyl/archive/2012/09/20/2695799.html</strong></a><br /><br />
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; word-break: normal !important; padding-top: 0px" id="cnblogs_post_body">
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">　　前记：TCP/IP详解系列，毕竟不是一本教材，很多地方讲的不细致。比如SWS未说明是什么就开始介绍其避免方法，还和nagle扯在了一起，直觉告诉我二者一定有猫腻，边搜索一下，果然很有收获。今天贴在这里，分享给大家。&nbsp;</strong></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">&nbsp;</strong></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">第一部分：SWS</strong></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 黑体; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">何谓糊涂窗口综合症</strong></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px">　　当发送端应用进程产生数据很慢、或接收端应用进程处理接收缓冲区数据很慢，或二者兼而有之；就会使应用进程间传送的报文段很小，特别是有效载荷很小。 极端情况下，有效载荷可能只有1个字节；而传输开销有40字节(20字节的IP头+20字节的TCP头) 这种现象就叫糊涂窗口综合症。</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 黑体; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">发送端引起的SWS</strong></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px">　　如果发送端为产生数据很慢的应用程序服务(典型的有telnet应用)，例如，一次产生一个字节。这个应用程序一次将一个字节的数据写入发送端的TCP的缓存。如果发送端的TCP没有特定的指令，它就产生只包括一个字节数据的报文段。结果有很多41字节的IP数据报就在互连网中传来传去。解决的方法是防止发送端的TCP逐个字节地发送数据。必须强迫发送端的TCP收集数据，然后用一个更大的数据块来发送。发送端的TCP要等待多长时间呢？如果它等待过长，它就会使整个的过程产生较长的时延。如果它的等待时间不够长，它就可能发送较小的报文段，于是，Nagle找到了一个很好的解决方法，发明了Nagle算法。而他选择的等待时间是一个RTT,即下个ACK来到时。</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 黑体; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">接收端引起的SWS</strong></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px">　　接收端的TCP可能产生糊涂窗口综合症，如果它为消耗数据很慢的应用程序服务，例如，一次消耗一个字节。假定发送应用程序产生了1000字节的数据块，但接收应用程序每次只吸收1字节的数据。再假定接收端的TCP的输入缓存为4000字节。发送端先发送第一个4000字节的数据。接收端将它存储在其缓存中。现在缓存满了。它通知窗口大小为零，这表示发送端必须停止发送数据。接收应用程序从接收端的TCP的输入缓存中读取第一个字节的数据。在入缓存中现在有了1字节的空间。接收端的TCP宣布其窗口大小为1字节，这表示正渴望等待发送数据的发送端的TCP会把这个宣布当作一个好消息，并发送只包括一个字节数据的报文段。这样的过程一直继续下去。一个字节的数据被消耗掉，然后发送只包含一个字节数据的报文段。</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px">　　对于这种糊涂窗口综合症，即应用程序消耗数据比到达的慢，有两种建议的解决方法：<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" />　　1） Clark解决方法 Clark解决方法是只要有数据到达就发送确认，但宣布的窗口大小为零，直到或者缓存空间已能放入具有最大长度的报文段，或者缓存空间的一半已经空了。<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" />　　2 ）延迟确认 第二个解决方法是延迟一段时间后再发送确认。这表示当一个报文段到达时并不立即发送确认。接收端在确认收到的报文段之前一直等待，直到入缓存有足够的空间为止。延迟的确认防止了发送端的TCP滑动其窗口。当发送端的TCP发送完其数据后，它就停下来了。这样就防止了这种症状。迟延的确认还有另一个优点：它减少了通信量。接收端不需要确认每一个报文段。但它也有一个缺点，就是迟延的确认有可能迫使发送端重传其未被确认的报文段。可以用协议来平衡这个优点和缺点，例如现在定义了确认的延迟不能超过500毫秒。</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px">&nbsp;</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: arial; color: rgb(0,0,0); font-size: 13px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">第二部分：Nagle算法</strong></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: arial; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;TCP/IP协议中，无论发送多少数据，总是要在数据前面加上协议头，同时，对方接收到数据，也需要发送ACK表示确认。为了尽可能的利用网络带宽，TCP总是希望尽可能的发送足够大的数据。（一个连接会设置MSS参数，因此，TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据）。</span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">Nagle算法就是为了尽可能发送大块数据，避免网络中充斥着许多小数据块。</span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;<span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(128,0,128); font-size: 13px; padding-top: 0px">N</span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(128,0,128); font-size: 13px; padding-top: 0px">agle算法的基本定义是</span></span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(128,0,128); font-size: 13px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">任意时刻，最多只能有一个未被确认的小段</strong><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">。 所谓&#8220;小段&#8221;，指的是小于MSS尺寸的数据块，所谓&#8220;未被确认&#8221;，是指一个数据块发送出去后，没有收到对方发送的ACK确认该数据已收到</span></span></span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(128,0,128); font-size: 13px; padding-top: 0px">。</span><br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">&nbsp;&nbsp; &nbsp;<span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">&nbsp;&nbsp; &nbsp;Nagle算法的规则（可参考tcp_output.c文件里tcp_nagle_check函数注释）：</span></span></span></span>&nbsp;</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">&nbsp;&nbsp; &nbsp; &nbsp;（1）如果包长度达到MSS，则允许发送；</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">&nbsp;&nbsp; &nbsp; &nbsp;（2）如果该包含有FIN，则允许发送；</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">&nbsp;&nbsp; &nbsp; &nbsp;（3）设置了TCP_NODELAY选项，则允许发送；</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">&nbsp;&nbsp; &nbsp; &nbsp;（4）未设置TCP_CORK选项时，若所有发出去的小数据包（包长度小于MSS）均被确认，则允许发送；</span>&nbsp;</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">&nbsp;&nbsp; &nbsp; &nbsp;（5）上述条件都未满足，但发生了超时（一般为200ms），则立即发送。</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px">&nbsp;<span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(0,0,255); font-size: 13px; padding-top: 0px">Nagle算法只允许一个未被ACK的包存在于网络，它并不管包的大小，因此它事实上就是一个扩展的停-等协议，只不过它是基于包停-等的，而不是基于字节停-等的</span></span></span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(0,0,255); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">。</span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">Nagle算法完全由TCP协议的ACK机制决定，这会带来一些问题，比如如果对端ACK回复很快的话，Nagle事实上不会拼接太多的数据包，虽然避免了网络拥塞，网络总体的利用率依然很低。<span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(0,0,0); font-size: 13px; padding-top: 0px">另外，他是一个自适应的方法，读者可以自己按上述规则试验一下。</span></span></span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(0,0,255); font-size: 13px; padding-top: 0px">&nbsp;</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: arial; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;<span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(255,0,0); font-size: 13px; padding-top: 0px">&nbsp;Nagle算法是silly window syndrome(SWS)预防算法的一个半集。</span>SWS算法预防发送少量的数据，<span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">Nagle算法是其在发送方的实现，而接收方要做的时不要通告缓冲空间的很小增长，不通知小窗口，除非</span>缓冲区空间有显著的增长。这里显著的增长定义为完全大小的段（MSS）或增长到大于最大窗口的一半。</span><br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /><br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(0,0,255); font-size: 13px; padding-top: 0px">注意</span>：</span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">BSD的实现是允许在空闲链接上发送大的写操作剩下的最后的小段，也就是说，当超过1个MSS数据发送时，内核先依次发送完n个MSS的数据包，然后再发送尾部的小数据包，其间不再延时等待。（假设网络不阻塞且接收窗口足够大）</span></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 黑体; color: rgb(17,17,17); font-size: 14px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">TCP_NODELAY 选项</span></strong></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: arial; color: rgb(51,51,51); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;默认情况下，发送数据采用Negale 算法。这样虽然提高了网络吞吐量，但是实时性却降低了，在一些交互性很强的应用程序来说是不允许的，使用TCP_NODELAY选项可以禁</span>止Negale 算法。</span>&nbsp;</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: arial; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;此时，应用程序向内核递交的每个数据包都会立即发送出去。</span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(0,0,255); font-size: 13px; padding-top: 0px">需要注意的是，虽然禁止了Negale 算法，但网络的传输仍然受到TCP确认延迟机制的影响。</span><br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /><br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">TCP_CORK 选项</span></strong></span></span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">&nbsp;</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: arial; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;所谓的</span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">CORK</span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">就是塞子的意思，形象地理解就是用</span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">CORK</span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">将连接塞住，使得数据先不发出去，等到拔去塞子后再发出去。设置该选项后，内核会尽力把小数据包拼接成一个大的数据包（一个MTU）再发送出去，当然若一定时间后（一般为200ms，该值尚待确认），内核仍然没有组合成一个MTU时也必须发送现有的数据（不可能让数据一直等待吧）。</span><br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;然而，TCP_CORK的实现可能并不像你想象的那么完美，CORK并不会将连接完全塞住。内核其实并不知道应用层到底什么时候会发送第二批数据用于和第一批数据拼接以达到MTU的大小，因此内核会给出一个时间限制，在该时间内没有拼接成一个大包（努力接近MTU）的话，内核就会无条件发送。</span></span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(0,0,255); font-size: 13px; padding-top: 0px">也就是说若应用层程序发送小包数据的间隔不够短时，<span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">TCP_CORK就没有一点作用，反而失去了数据的实时性（每个小包数据都会延时一定时间再发送）。</span></span><br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /><br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">Nagle算法与</strong></span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: medium; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">CORK算法区别</span><br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /></strong></span><br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /></span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">　　Nagle算法和CORK算法非常类似，但是它们的着眼点不一样，</span><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(0,0,255); font-size: 13px; padding-top: 0px">Nagle算法主要避免网络因为太多的小包（协议头的比例非常之大）而拥塞，而CORK算法则是为了提高网络的利用率，使得总体上协议头占用的比例尽可能的小</span>。<span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">如此看来这二者在避免发送小包上是一致的，在用户控制的层面上，Nagle算法完全不受用户socket的控制，你只能简单的设置TCP_NODELAY而禁用它，CORK算法同样也是通过设置或者清除TCP_<span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px">CORK</span>使能或者禁用之，然而Nagle算法关心的是网络拥塞问题，只要所有的ACK回来则发包，而CORK算法却可以关心内容，在前后数据包发送间隔很短的前提下（很重要，否则内核会帮你将分散的包发出），即使你是分散发送多个小数据包，你也可以通过使能CORK算法将这些内容拼接在一个包内，如果此时用Nagle算法的话，则可能做不到这一点。</span></span></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: arial; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">&nbsp;</span></span></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 5px auto; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: arial; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(17,17,17); font-size: 13px; padding-top: 0px"><span style="padding-bottom: 0px; line-height: 1.8em; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(51,51,51); font-size: 13px; padding-top: 0px">参考：<a style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(0,102,204); text-decoration: underline; padding-top: 0px" href="http://www.cnblogs.com/ggjucheng/archive/2012/02/03/2337046.html">http://www.cnblogs.com/ggjucheng/archive/2012/02/03/2337046.html</a></span></span></span></p></div></div><img src ="http://www.cppblog.com/tx7do/aggbug/191900.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2012-09-25 03:08 <a href="http://www.cppblog.com/tx7do/archive/2012/09/25/191900.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UDP_CORK,TCP_CORK以及TCP_NODELAY</title><link>http://www.cppblog.com/tx7do/archive/2012/09/25/191899.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Mon, 24 Sep 2012 18:59:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2012/09/25/191899.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/191899.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2012/09/25/191899.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/191899.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/191899.html</trackback:ping><description><![CDATA[<div><strong style="color: red">转载自:</strong><a style="color: red" href="http://soft-app.iteye.com/blog/919784"><strong>http://soft-app.iteye.com/blog/919784</strong></a><br />
<br />
<div style="text-align: left; widows: 2; text-transform: none; text-indent: 0px; font: 14px/1.8em Helvetica, Tahoma, Arial, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" id="blog_content" class="blog_content">
<p style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">这三个选项十分有意思，并且困扰了很多人。特别是cork选项，它到底和nodelay有什么区别，到底怎样影响了Nagle算法。在tcp的实现中(特指linux内核的协议栈实现)，cork和nodelay非常让人看不出区别，这一块的实现非常复杂，看内核实现之前最好先明白它们大概在说什么，否则很容易迷失的。<br />
所谓的cork就是塞子的意思，形象地理解就是用cork将连接塞住，使得数据先不发出去，等到拔去塞子后再发出去，而nodelay事实上是为了禁用Nagle算法，Nagle算法为了增加了网络的吞吐量而牺牲了响应时间体验，这在有些应用中是不合适的，比如交互式应用(终端登录或者远程X应用 etc.)，因此有必要提供一个选项将它禁用掉，Nagle算法在RFC1122中有提及，它的实现实际上很简单，利用了tcp本身的一些特性，在算法描述中，关键的一点是&#8220;什么时候真实的发送数据&#8221;，这个问题的解答也是很简单，原则上只要发出的包都被对端ack了就可以发送了，这实际上也是一种权衡，Nagle算法最初的目的在于解决大量小包存在于网络从而造成网络拥塞的问题(一个小包可能只有几个字节，比如ls，cat等等，然而为每个小包封装几个协议头，其大小就不可忽视了，大量此类小包存在于网络势必会使得网络带宽的利用率大大下降)，如果包被ack了，说明包已经离开了网络进入了对端主机，这样就可以发送数据了，此时无需再等，有多少数据发送多少(当然要考虑窗口大小和MTU)，如果很极端地等待更多的数据，那么响应度会更低，换句话简单的说Nagle算法只允许一个未被ack的包存在于网络，它并不管包的大小，因此它事实上就是一个扩展的停-等协议，只不过它是基于包停-等的，而不是基于字节停-等的。<br />
可以看出，Nagle算法完全由tcp协议的ack机制决定，这会带来一些问题，比如如果对端ack回复很快的话，Nagle事实上不会拼接太多的数据包，虽然避免了网络拥塞，网络总体的利用率依然很低，Nagle真的做到了&#8220;只做好一件事&#8221;的原则，然而有没有另外一种算法，可以提高整体网络利用率呢？也就是说尽量以不能再多的数据发送，这里之所以说是尽量还是权衡导致的，某时可以发送数据的时候将会发送数据，即使当前数据再小也不再等待后续的可能拼接成更大包的数据的到来。<br />
实际上，这样的需求可以用TCP_CORK来实现，但是实现得可能并不像你想象的那么完美，cork并不会将连接完全塞住。内核其实并不知道应用层到底什么时候会发送第二批数据用于和第一批数据拼接以达到MTU的大小，因此内核会给出一个时间限制，在该时间内没有拼接成一个大包(努力接近MTU)的话，内核就会无条件发送，这里给出的只是一个大致的思想，真实的情况还要受到窗口大小以及拥塞情况的影响，因此tcp&#8220;何时发送数据&#8221;这个问题非常复杂。<br />
Nagle算法和CORK算法非常类似，但是它们的着眼点不一样，Nagle算法主要避免网络因为太多的小包(协议头的比例非常之大)而拥塞，而CORK算法则是为了提高网络的利用率，使得总体上协议头占用的比例尽可能的小。如此看来这二者在避免发送小包上是一致的，在用户控制的层面上，Nagle算法完全不受用户socket的控制，你只能简单的设置TCP_NODELAY而禁用它，CORK算法同样也是通过设置或者清除TCP_cork使能或者禁用之，然而Nagle算法关心的是网络拥塞问题，只要所有的ack回来则发包，而CORK算法却可以关心内容，在前后数据包发送间隔很短的前提下(很重要，否则内核会帮你将分散的包发出)，即使你是分散发送多个小数据包，你也可以通过使能CORK算法将这些内容拼接在一个包内，如果此时用Nagle算法的话，则可能做不到这一点。<br />
接下来看一下内核代码，然后给出一个测试程序来感性感受这些选项。tcp的发送函数是tcp_sendmsg，这个函数中存在一个大循环，用于将用户数据置入skb中，它的形式如下：<br />
int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,<br />
size_t size)<br />
{<br />
<br />
while (--iovlen &gt;= 0) {<br />
0.更新数据结构元数据；<br />
while (seglen &gt; 0) {<br />
int copy;<br />
skb = sk-&gt;sk_write_queue.prev;<br />
1.如果既有skb的长度过大或者根本还没有一个skb则分配一个skb；<br />
2.将数据拷贝到既有的skb或者新的skb中；<br />
3.更新skb和用户数据的元数据；<br />
//如果数据还没有达到mss，则继续，换句话就是如果数据已经达到mss了就接着往下走来权衡是否马上发送。<br />
if (skb-&gt;len != mss_now || (flags &amp; MSG_OOB))<br />
continue;<br />
4.权衡发送与否<br />
continue;<br />
}<br />
}<br />
out:<br />
//如果循环完成，所有数据都进入了skb，调用tcp_push来权衡是否发送<br />
tcp_push(sk, tp, flags, mss_now, tp-&gt;nonagle);<br />
}<br />
tcp_push很短但是很复杂，<br />
static inline void tcp_push(struct sock *sk, struct tcp_opt *tp, int flags,<br />
int mss_now, int nonagle)<br />
{<br />
if (sk-&gt;sk_send_head) {<br />
struct sk_buff *skb = sk-&gt;sk_write_queue.prev;<br />
...<br />
//如果有MSG_MORE，则当作cork来处理<br />
__tcp_push_pending_frames(sk, tp, mss_now,<br />
(flags &amp; MSG_MORE) ? TCP_NAGLE_CORK : nonagle);<br />
}<br />
}<br />
static __inline__ void __tcp_push_pending_frames(struct sock *sk,<br />
struct tcp_opt *tp,<br />
unsigned cur_mss,<br />
int nonagle)<br />
{<br />
struct sk_buff *skb = sk-&gt;sk_send_head;<br />
if (skb) {<br />
if (!tcp_skb_is_last(sk, skb)) //如果已经有了很多的skb，则尽量马上发送<br />
nonagle = TCP_NAGLE_PUSH;<br />
//只有tcp_snd_test返回1才会发送数据，该函数很复杂<br />
if (!tcp_snd_test(tp, skb, cur_mss, nonagle) ||<span class="Apple-converted-space">&nbsp;</span><br />
tcp_write_xmit(sk, nonagle))<br />
tcp_check_probe_timer(sk, tp);<span class="Apple-converted-space">&nbsp;</span><br />
}<br />
tcp_cwnd_validate(sk, tp);<br />
}<br />
static __inline__ int tcp_snd_test(struct tcp_opt *tp, struct sk_buff *skb,<br />
unsigned cur_mss, int nonagle)<br />
{<br />
//如果有TCP_NAGLE_PUSH标志(或者tcp_nagle_check同意发送)且未ack的数据够少且...则可以发送<br />
return (((nonagle&amp;TCP_NAGLE_PUSH) || tp-&gt;urg_mode<br />
|| !tcp_nagle_check(tp, skb, cur_mss, nonagle)) &amp;&amp;<br />
((tcp_packets_in_flight(tp) &lt; tp-&gt;snd_cwnd) ||<br />
(TCP_SKB_CB(skb)-&gt;flags &amp; TCPCB_FLAG_FIN)) &amp;&amp;<br />
!after(TCP_SKB_CB(skb)-&gt;end_seq, tp-&gt;snd_una + tp-&gt;snd_wnd));<br />
}<br />
tcp_nagle_check函数是一个很重要的函数，它基本决定了数据是否可以发送的80%，内核源码中对该函数有一条注释：<br />
-3. Or TCP_NODELAY was set.<br />
-4. Or TCP_CORK is not set, and all sent packets are ACKed.<br />
就是说如果TCP_NODELAY值为1就可以直接发送，或者cork被禁用的情况下所有发出的包都被ack了也可以发送数据，这里体现的就是Nagle算法和CORK算法的区别了，Nagle算法只要求所有的出发包都ack就可以发送，而不管当前包是否足够大(虽然它通过tcp_minshall_check保证了包不太小)，而如果启用cork的话，可能仅仅数据被ack就不够了，这就是为何在代码注释中说cork要比Nagle更stronger的原因，同时这段代码也说明了为何TCP_CORK和TCP_NODELAY不能一起使用的原因，它们有共同的东西，却在做着不同的事情。看看tcp_nagle_check：<br />
static __inline__ int<br />
tcp_nagle_check(struct tcp_opt *tp, struct sk_buff *skb, unsigned mss_now, int nonagle)<br />
{<br />
return (skb-&gt;len &lt; mss_now &amp;&amp;<br />
!(TCP_SKB_CB(skb)-&gt;flags &amp; TCPCB_FLAG_FIN) &amp;&amp;<br />
((nonagle&amp;TCP_NAGLE_CORK) ||<br />
(!nonagle &amp;&amp;<br />
tp-&gt;packets_out &amp;&amp;<br />
tcp_minshall_check(tp))));<br />
}<br />
看看__tcp_push_pending_frames的最后，有一个tcp_check_probe_timer调用，就是说在没有数据被发送的时候会调用这个函数。这个函数有两个作用，第一个是防止0窗口导致的死锁，另一个作用就是定时发送由于使能了CORK算法或者Nagle算法一直等待新数据拼接而没有机会发送的数据包。这个timer内置在重传timer之中，其时间间隔和rtt有关，一旦触发则会发送数据包或者窗口探测包。反过来可以理解，如果没有这个timer的话，启用cork的连接将几乎(可能根据实现的不同还会受别的因素影响，太复杂了)每次都发送mtu大小的数据包。该timer调用tcp_probe_timer函数：<br />
static void tcp_probe_timer(struct sock *sk)<br />
{<br />
struct tcp_opt *tp = tcp_sk(sk);<br />
int max_probes;<br />
//1.如果有数据在网络上，则期望马上回来ack，ack中会通告对端窗口<br />
//2.如果没有数据要发送，则无需关注对端窗口，即使为0也无所谓<br />
if (tp-&gt;packets_out || !sk-&gt;sk_send_head) {<br />
tp-&gt;probes_out = 0;<br />
return;<br />
}<br />
//这个sysctl_tcp_retries2是可以调整的<br />
max_probes = sysctl_tcp_retries2;<br />
if (tp-&gt;probes_out &gt; max_probes) {<br />
tcp_write_err(sk);<br />
} else {<br />
tcp_send_probe0(sk);<br />
}<br />
}<br />
tcp_send_probe0会调用tcp_write_wakeup函数，该函数会要么发送可以发送的数据，如果由于发送队列越过了发送窗口导致不能发送，则发送一个窗口探测包：<br />
int tcp_write_wakeup(struct sock *sk)<br />
{<br />
if (sk-&gt;sk_state != TCP_CLOSE) {<br />
struct tcp_opt *tp = tcp_sk(sk);<br />
struct sk_buff *skb;<br />
if ((skb = sk-&gt;sk_send_head) != NULL &amp;&amp;<br />
before(TCP_SKB_CB(skb)-&gt;seq, tp-&gt;snd_una+tp-&gt;snd_wnd)) {<br />
...//在sk_send_head队列上取出一个发送出去，其ack会带回对端通告窗口的大小<br />
err = tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));<br />
...<br />
return err;<br />
} else {<br />
...<br />
return tcp_xmit_probe_skb(sk, 0);<br />
}<br />
}<br />
return -1;<br />
}<br />
这个probe timer虽然一定程度阻碍了cork的满载发送，然而它却是必要的，这是由于tcp并不为纯的ack包(不带数据的ack包)提供确认，因此一旦这种ack包丢失，那么就有可能死锁，发送端的窗口无法更新，接收端由于已经发送了ack而等待接收数据，两端就这样僵持起来，因此需要一个timer，定期发送一个探测包，一个ack丢失，不能所有的ack都丢失吧，在timer到期时，如果本来发送队列上有数据要发送，则直接发送这些数据而不再发送探测包，因为发送了这些数据，所以它&#8220;破坏&#8221;了cork的承诺，不过也因此增强了响应度。<br />
在示出应用程序之前，总结一下内核在哪里会发送tcp包，在解释在哪里会发送tcp包之前，首先说明内核协议栈为了高效和低耦合设计，tcp_sendmsg并不一定真实发送数据，真实发送数据的地点在：<br />
1.tcp_sendmsg内部(废话！)，如果权衡的结果需要发送则发送；<br />
2.收到对端ack的时候会调用tcp_data_snd_check来发送，它同样完全按照cork策略来的；<br />
3.probe timer到期后作为窗口探测包发送一些数据，它&#8220;破坏&#8221;了cork，在塞子上捅破一个口子；<br />
4.连接断开或者进程退出时可能会将所有数据刷到对端；<br />
5.当禁用cork或者启用nodelay的时候会将pending的数据刷入对端。<br />
下面看一下应用层的测试程序：<br />
客户端程序：client<br />
#define BUFF_SIZE 500<span class="Apple-converted-space">&nbsp;</span><br />
#define REMOTE_PORT 6800<span class="Apple-converted-space">&nbsp;</span><br />
signed int len = 0;<span class="Apple-converted-space">&nbsp;</span><br />
int main(int argc, char *argv[])<br />
{<br />
int sock;<br />
struct sockaddr_in remote_addr;<br />
int on = 1;<br />
unsigned char buff[BUFF_SIZE];<br />
int i;<br />
if (argc != 5) {<br />
printf("usage: client server_ip on|off cork|nodelay usec\n");<br />
exit(-1);<br />
}<br />
int msd = atoi(argv[4]);<br />
if (!strcmp(argv[2], "on"))<br />
on = 1;<br />
else if (!strcmp(argv[2], "off"))<br />
on = 0;<br />
for (i = 0; i &lt; BUFF_SIZE; i++) {<br />
buff[i] = 'q';<span class="Apple-converted-space">&nbsp;</span><br />
}<br />
sock = socket(AF_INET, SOCK_STREAM, 0);<br />
if (!strcmp(argv[3], "nodelay")) {<br />
setsockopt(sock, SOL_TCP, TCP_NODELAY, &amp;dontroute, sizeof(dontroute));<br />
} else if (!strcmp(argv[3], "cork")) {<br />
setsockopt(sock, SOL_TCP, TCP_CORK, &amp;dontroute, sizeof(dontroute));<br />
}<br />
struct sockaddr_in sa;<br />
memset (&amp;sa, '\0', sizeof(sa));<br />
sa.sin_family = AF_INET;<br />
sa.sin_addr.s_addr = inet_addr (argv[1]);<span class="Apple-converted-space">&nbsp;</span><br />
sa.sin_port = htons(REMOTE_PORT);<span class="Apple-converted-space">&nbsp;</span><br />
connect(sock, (struct sockaddr*) &amp;sa, sizeof(sa));<br />
while(1) {<br />
len = send(sock, buff, BUFF_SIZE, MSG_MORE);<br />
if (len &lt; 0)<span class="Apple-converted-space">&nbsp;</span><br />
exit(-1);<br />
usleep(msd);<br />
}<br />
return (0);<br />
}<br />
服务器程序：server<br />
int main (int argc, char **argv)<br />
{<br />
int err;<br />
int listen_sd;<br />
int sd;<br />
struct sockaddr_in sa_serv;<br />
struct sockaddr_in sa_cli;<br />
size_t client_len;<br />
char* str;<br />
char buf [500];<br />
listen_sd = socket (AF_INET, SOCK_STREAM, 0);<span class="Apple-converted-space">&nbsp;</span><br />
memset (&amp;sa_serv, '\0', sizeof(sa_serv));<br />
sa_serv.sin_family = AF_INET;<br />
sa_serv.sin_addr.s_addr = INADDR_ANY;<br />
sa_serv.sin_port = htons (6800);<span class="Apple-converted-space">&nbsp;</span><br />
err = bind(listen_sd, (struct sockaddr*) &amp;sa_serv, sizeof (sa_serv));<span class="Apple-converted-space">&nbsp;</span><br />
err = listen (listen_sd, 5);<span class="Apple-converted-space">&nbsp;</span><br />
client_len = sizeof(sa_cli);<br />
while (1) {<br />
sd = accept (listen_sd, (struct sockaddr*) &amp;sa_cli, &amp;client_len);<br />
while (1) {<br />
err = read(sd, buf, sizeof(buf));<span class="Apple-converted-space">&nbsp;</span><br />
if (err &lt;= 0)<br />
break;<br />
}<br />
}<br />
close (sd);<br />
}<br />
运行之：<br />
client 192.168.x.y on cork 66000<br />
在我的机器上，第四个参数最大到66000时cork会满载发送，如果usleep的时间再长一些，probe timer就是&#8220;帮忙&#8221;发送数据了，给你的感觉是，启用了cork为何看起来没有什么用。这个时间在不同环境在有所不同，因为probe timer导致了cork的破坏，而probe timer和rtt有关，rtt又和网络环境有关...再进行一个测试，执行下列命令：sysctl -w net.ipv4.tcp_retries2=-1<br />
然后以比较高的时间间隔以及比较小的BUFF_SIZE在开启cork情况下运行client程序，我们发现第一个包还没发完进程就会退出，这是由于cork尽力在组包，间隔过大导致probe timer过期，然后tp-&gt;probes_out &gt; max_probes判断通过，导致超时退出，这个可以从/proc/net/netstat中的超时计数器中看出来，如果间隔比较短，每次新的数据pending到既有的skb上而不发送，重置probe timer，使得timer总是不过期，终于pending的数据到达了mtu的大小，cork的满载发送起作用进而发送之。<br />
还有一个概念是&#8220;糊涂窗口&#8221;，那就是接收端接收缓慢并不断确认，导致窗口一直很小，而发送端收到ack就再次发送小包，这样导致一直发送-确认很小的包...这个是可以通过应用层编程来避免的，另外也可以通过cork算法或者Nagle算法来减轻，但是无论怎样都逃不过一些timer自动帮你发送数据。<br />
最后，好像遗漏了UDP_CORK，很简单，udp没有连接，没有确认，因此也就不需要什么timer之类的复杂机制，也因此，它是真正承诺的cork，除非你在应用层手工拔掉塞子，否则数据将不会发出。</p>
</div>
</div><img src ="http://www.cppblog.com/tx7do/aggbug/191899.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2012-09-25 02:59 <a href="http://www.cppblog.com/tx7do/archive/2012/09/25/191899.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Chromium Embedded Framework中文文档之(基本使用)</title><link>http://www.cppblog.com/tx7do/archive/2012/08/10/186825.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 10 Aug 2012 06:34:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2012/08/10/186825.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/186825.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2012/08/10/186825.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/186825.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/186825.html</trackback:ping><description><![CDATA[<div><strong style="color: red">转载自:</strong><a style="color: red" href="http://www.cnblogs.com/think/archive/2011/10/06/CEF-genericUsage.html"><strong>http://www.cnblogs.com/think/archive/2011/10/06/CEF-genericUsage.html</strong></a><br /><br />
<h2 style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(221,221,221); text-indent: 0px; margin: 15px auto 2px; padding-left: 0px; padding-right: 0px; font: bold 21px/28px 微软雅黑, verdana, 'ms song', 宋体, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">一般用法</h2>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">使用CEF便捷的创建一个全功能的内建浏览器如下所示:</p><pre style="text-align: left; padding-bottom: 0.5em; overflow-x: auto; overflow-y: auto; widows: 2; text-transform: none; background-color: rgb(238,238,238); text-indent: 0px; margin: 0px; padding-left: 0.5em; padding-right: 0.5em; font: 12px/22px Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Lucida Console', monospace; max-width: 70em; word-wrap: break-word; white-space: pre-wrap; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0.5em; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(136,0,0); padding-top: 0px">// Define an instance of our CefHandler implementation. Various methods in the MyHandler</span> <span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(136,0,0); padding-top: 0px">// instance will be called to customize browser behavior. </span> <span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,0,102); padding-top: 0px">CefRefPtr</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,102,0); padding-top: 0px">&lt;</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,0,102); padding-top: 0px">CefHandler</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,102,0); padding-top: 0px">&gt;</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> handler</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,102,0); padding-top: 0px">(</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(0,0,136); padding-top: 0px">new</span> <span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,0,102); padding-top: 0px">MyHandler</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,102,0); padding-top: 0px">());</span> <span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(136,0,0); padding-top: 0px">// Provide information about the parent window, client rectangle, etc.</span> <span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,0,102); padding-top: 0px">CefWindowInfo</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> info </span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,102,0); padding-top: 0px">=</span> <span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,102,0); padding-top: 0px">{...};</span> <span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(136,0,0); padding-top: 0px">// Create the new browser window object, which eventually results in a call to</span> <span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(136,0,0); padding-top: 0px">// MyHandler::HandleAfterCreated().</span> <span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,0,102); padding-top: 0px">CefBrowser</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,102,0); padding-top: 0px">::</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,0,102); padding-top: 0px">CreateBrowser</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,102,0); padding-top: 0px">(</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">info</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,102,0); padding-top: 0px">,</span> <span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(0,0,136); padding-top: 0px">false</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,102,0); padding-top: 0px">,</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> handler</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,102,0); padding-top: 0px">,</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"> L</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(0,136,0); padding-top: 0px">"http://www.google.com"</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(102,102,0); padding-top: 0px">);</span></pre>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">在tests目录下有一个客户端程序的示例，叫cefclient。</p>
<h2 style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(221,221,221); text-indent: 0px; margin: 15px auto 2px; padding-left: 0px; padding-right: 0px; font: bold 21px/28px 微软雅黑, verdana, 'ms song', 宋体, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><a style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(162,177,195); cursor: pointer; text-decoration: none; padding-top: 0px" name="File_Structure"></a>文件结构</h2>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">CEF资料库结构如下：</p>
<ul style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); list-style-type: none; text-indent: 0px; margin: 0px 0px 0px 20px; padding-left: 25px; padding-right: 0px; font: 13px/22px arial, sans-serif; max-width: 62em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-break: break-all; word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">include</strong>&nbsp;-- 包括用于CEF客户端程序的include文件。</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">libcef</strong>&nbsp;-- libcef实现。</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">libcef_dll</strong>&nbsp;-- libcef C API 和 DLL 实现.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">tests</strong>&nbsp;-- 测试程序.</li>
<ul style="padding-bottom: 0px; list-style-type: none; margin: 0px 0px 0px 20px; padding-left: 25px; padding-right: 0px; max-width: 62em; word-break: break-all; padding-top: 0px"><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">cefclient</strong>&nbsp;-- CEF客户端应用程序示例。</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">unittests</strong>&nbsp;-- CEF接口单元测试。</li></ul></ul>
<h2 style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(221,221,221); text-indent: 0px; margin: 15px auto 2px; padding-left: 0px; padding-right: 0px; font: bold 21px/28px 微软雅黑, verdana, 'ms song', 宋体, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><a style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(162,177,195); cursor: pointer; text-decoration: none; padding-top: 0px" name="Browser_Notifications"></a>浏览器通知</h2>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">浏览器通知是通过注册的委托接口由浏览器发到客户端程序的通知， CefHandler是最主要的委托接口, CefJSHandler则用于实现自定义的Javascript对象。</p>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">CefHandler支持以下接口：</p>
<ul style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); list-style-type: none; text-indent: 0px; margin: 0px 0px 0px 20px; padding-left: 25px; padding-right: 0px; font: 13px/22px arial, sans-serif; max-width: 62em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-break: break-all; word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">窗口创建之前 (HandleBeforeCreated)，客户端可用之取消与定制浏览器窗口创建过程。</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">窗口创建之后(HandleAfterCreated). 可用于创建自定义的CefJSHandler对象。</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">地址栏更新(HandleAddressChange). 将地址栏更改为指定的字符串，通知发生于导航提交后与页面加载前。</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">标题更新(HandleTitleChange). 将标题更改为指定的字符串，发生在页面加载中。</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">浏览前(HandleBeforeBrowse). 可用于取消导航，该事件的信息包括URL，Post数据，请求头.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">开始加载(HandleLoadStart).&nbsp;</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">加载结束 (HandleLoadEnd).&nbsp;</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">加载错误(HandleLoadError). 加载过程中遇到错误，应用程序可提供自定义的错误页面.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">资源加载前 (HandleBeforeResourceLoad). 应用程序可提供替代的数据源 (比如内存中的缓存)或者取消加载.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">显示菜单前(HandleBeforeMenu). 可用于取消上下文菜单显示或定制菜单,默认情况下，浏览器根据上下文显示基本的菜单.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">获取菜单标签(HandleGetMenuLabel).在默认菜单显示前，每个菜单项调用一次，可用于将英文默认内容改为其它语言.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">菜单动作(HandleMenuAction). 用户从默认上下文菜单选择了一个选项，可用自己的方式来处理动作。</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">打印选项(HandlePrintOptions). 打印设置对话框显示前调用，可用于定制页面大小、方向与边距等.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">打印页眉页脚 (HandlePrintHeaderFooter). 在页面视图输出到打印上下文，但是页面结束前，可在预定义的6个位置（上左、上中、上右、下左，下中，下右）插入自定义的页眉、页脚字符串。该事件附带的信息包括当前URL、标题、页码、总页数、打印上下文、页边距与DPI拉伸比.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">JavaScript警告 (HandleJSAlert). 应用程序可自定义Javascript Alert窗口.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">JavaScrip确认 (HandleJSConfirm).&nbsp;<span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font-size: 13px; padding-top: 0px">应用程序可自定义Javascript Comfirm窗口</span></li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">JavaScrip提示 (HandleJSPrompt).&nbsp;<span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font-size: 13px; padding-top: 0px">应用程序可自定义Javascript Prompt窗口</span></li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">JavaScript Window 对象绑定 (HandleJSBinding). 应用程序将用户定义的方法和变量附加到frame的window对象上</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">Window关闭前 (HandleBeforeWindowClose). 窗口关闭前</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">获得焦点(HandleTakeFocus). 浏览器组件失去焦点前调用</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">设置焦点(HandleSetFocus). 浏览器组件请求焦点前调用</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">键盘事件(HandleKeyEvent). 浏览器组件接收到键盘事件时</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">提示 (HandleTooltip). 用于修改tooltip文字</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">控制台消息 (HandleConsoleMessage). 用于显示控制台消息.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">查询结果(HandleFindResult).用于自定义查找结果显示处理</li></ul>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">CefV8Handler支持以下通知：</p>
<ul style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); list-style-type: none; text-indent: 0px; margin: 0px 0px 0px 20px; padding-left: 25px; padding-right: 0px; font: 13px/22px arial, sans-serif; max-width: 62em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-break: break-all; word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">执行事件(Execute). 应用程序执行指定的函数，该事件提供所有的Javascript参数，而且应用程序能指定返回值</li></ul>
<h2 style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(221,221,221); text-indent: 0px; margin: 15px auto 2px; padding-left: 0px; padding-right: 0px; font: bold 21px/28px 微软雅黑, verdana, 'ms song', 宋体, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><a style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(162,177,195); cursor: pointer; text-decoration: none; padding-top: 0px" name="Browser_Events"></a>浏览器事件</h2>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">浏览器事件由客户端应用程序通过CefBrowser和CefFrame的函数发送给浏览器:</p>
<ul style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); list-style-type: none; text-indent: 0px; margin: 0px 0px 0px 20px; padding-left: 25px; padding-right: 0px; font: 13px/22px arial, sans-serif; max-width: 62em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-break: break-all; word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">后退、前进、重新加载与停止加载，用于控制浏览器导航.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">撤消、重做、剪切、复制、粘贴、删除、全选，用于控制目标区域内容.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">打印. 打印目标框架.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">查看源代码. 将目标框架的HTML源代码保存到临时文件，并用默认的文本查看程序打开之</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">加载URL. 在指定框架中加载指定URL</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">载入字符串. 根据一个假URL在指定框架中加载某个字符串</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">加载流. 根据一个假URL，在指定框架中加载二进制数据</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">加载请求. 在指定框架中加载请求(URL, method, request data 与 headers) .</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px">执行脚本. 在目标框架中执行任意Javascript命令</li></ul>
<h2 style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(221,221,221); text-indent: 0px; margin: 15px auto 2px; padding-left: 0px; padding-right: 0px; font: bold 21px/28px 微软雅黑, verdana, 'ms song', 宋体, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><a style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(162,177,195); cursor: pointer; text-decoration: none; padding-top: 0px" name="Embedded_NPAPI_Plugins"></a>内嵌 NPAPI 插件</h2>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">CEF支持创建Netscape-style内嵌插件，使用相同 NPAPI的内嵌插件和标准的DLL插件行为相同,但是，相对于使用独立的DLL，内嵌插件由容器应用程序创建，并通过调用CefRegisterPlugin()注册到系统，如果要直接使用这一功能，需要include cef_nplugin.h .</p>
<h2 style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(221,221,221); text-indent: 0px; margin: 15px auto 2px; padding-left: 0px; padding-right: 0px; font: bold 21px/28px 微软雅黑, verdana, 'ms song', 宋体, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><a style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(162,177,195); cursor: pointer; text-decoration: none; padding-top: 0px" name="Extensions"></a>JavaScript扩展</h2>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">CEF支持可以和原生应用程序代码交互的Javascript扩展，参见cef.h的CefRegisterExtension() 函数和cefclient示例程序的"JavaScript Extension Handler" 以及 "UI App Example" 测试 .</p>
<h2 style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(221,221,221); text-indent: 0px; margin: 15px auto 2px; padding-left: 0px; padding-right: 0px; font: bold 21px/28px 微软雅黑, verdana, 'ms song', 宋体, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><a style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(162,177,195); cursor: pointer; text-decoration: none; padding-top: 0px" name="Custom_Schemes"></a>自定义Schemes</h2>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">CEF支持注册与处理自定义scheme,类似于myscheme://mydomain。参见cef.h中的CefRegisterScheme()函数与示例应用程序cefclient中的 "Scheme Handler" 测试.</p>
<h2 style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(221,221,221); text-indent: 0px; margin: 15px auto 2px; padding-left: 0px; padding-right: 0px; font: bold 21px/28px 微软雅黑, verdana, 'ms song', 宋体, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><a style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(162,177,195); cursor: pointer; text-decoration: none; padding-top: 0px" name="Framework_Implementation_Overview"></a>框架实现概览</h2>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">CEF所有的类以Cef为前缀.</p>
<h3 style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(221,221,221); text-indent: 0px; margin: 15px auto 2px; padding-left: 0px; padding-right: 0px; font: bold 17px/28px 微软雅黑, verdana, 'ms song', 宋体, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><a style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(162,177,195); cursor: pointer; text-decoration: none; padding-top: 0px" name="Framework_Setup_and_Tear_Down"></a>框架准备与拆卸</h3>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">UI消息循环由框架创建的一个单独线程处理,客户端程序应负责通过分别调用CefInitialize()和CefShutdown() 来为每个进程准备与关闭这一线程。</p>
<h3 style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(221,221,221); text-indent: 0px; margin: 15px auto 2px; padding-left: 0px; padding-right: 0px; font: bold 17px/28px 微软雅黑, verdana, 'ms song', 宋体, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><a style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(162,177,195); cursor: pointer; text-decoration: none; padding-top: 0px" name="Reference_Counting"></a>引用计数</h3>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">所有实现了CefBase接口的框架类与对象指针都由CefRefPtr智能指针实现来处理，通过调用AddRef()和Release()自动处理引用计数。</p>
<h3 style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(221,221,221); text-indent: 0px; margin: 15px auto 2px; padding-left: 0px; padding-right: 0px; font: bold 17px/28px 微软雅黑, verdana, 'ms song', 宋体, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><a style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(162,177,195); cursor: pointer; text-decoration: none; padding-top: 0px" name="Platform_Neutrality"></a>平台无关</h3>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">CEF框架被设计成平台无关，需要当前我们仅支持windows平台，但是我们计划将来支持其它平台。为了尽可能减少双平台支持带来的麻烦，框架定义了一系列实现无关的接口与类型定义包装跨平台的行为。</p>
<h3 style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(221,221,221); text-indent: 0px; margin: 15px auto 2px; padding-left: 0px; padding-right: 0px; font: bold 17px/28px 微软雅黑, verdana, 'ms song', 宋体, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><a style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(162,177,195); cursor: pointer; text-decoration: none; padding-top: 0px" name="Thread_Safety"></a>线程安全</h3>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">框架的所有接口实现必须是跨线程访问安全的，CefThreadSafeBase 模版提供原子的AddRef() 和 Release() 实现，还提供Lock() 和 Unlock()方法以同步方式访问代码块.</p>
<h3 style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(221,221,221); text-indent: 0px; margin: 15px auto 2px; padding-left: 0px; padding-right: 0px; font: bold 17px/28px 微软雅黑, verdana, 'ms song', 宋体, Arial, Helvetica, sans-serif; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><a style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: rgb(162,177,195); cursor: pointer; text-decoration: none; padding-top: 0px" name="Framework_Interfaces"></a>框架接口</h3>
<p style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; font: 13px/1.25em arial, sans-serif; max-width: 64em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px">框架定义了如下接口：</p>
<ul style="text-align: left; padding-bottom: 0px; widows: 2; text-transform: none; background-color: rgb(255,255,255); list-style-type: none; text-indent: 0px; margin: 0px 0px 0px 20px; padding-left: 25px; padding-right: 0px; font: 13px/22px arial, sans-serif; max-width: 62em; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(102,102,102); word-break: break-all; word-spacing: 0px; padding-top: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefBrowser</strong>&nbsp;是主要的浏览器host类，通过它的静态方法CefBrowser::CreateBrowser()方法创建新浏览器窗口.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefFrame</strong>&nbsp;表示浏览器窗口里的一个框架（frame），每个浏览器窗口都有一个顶级的主框架，可通过CefBrowser::GetMainFrame()方法访问之.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefHandler</strong>&nbsp;是传给CefBrowser::CreateBrowser()方法的最主要委托接口.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefRequest</strong>&nbsp;表示请求数据，比如url, method, post data 和 headers.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefPostData</strong>&nbsp;和&nbsp;<strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefPostDataElement</strong>&nbsp;表示可能是请求一部分的post数据.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefSchemeHandlerFactory</strong>&nbsp;和&nbsp;<strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefSchemeHandler</strong>&nbsp;用于处理像myscheme://mydomain这样的自定义scheme.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefStreamReader</strong>,&nbsp;<strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefStreamWriter</strong>,&nbsp;<strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefReadHandler</strong>&nbsp;和&nbsp;<strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefWriteHandler</strong>&nbsp;读写数据的简单的接口.</li><li style="padding-bottom: 0px; list-style-type: disc; margin: 0px 0px 0.3em; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefV8Handler</strong>&nbsp;和&nbsp;<strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">CefV8Value</strong>&nbsp;用于创建和访问Javascript对象.</li></ul></div><img src ="http://www.cppblog.com/tx7do/aggbug/186825.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2012-08-10 14:34 <a href="http://www.cppblog.com/tx7do/archive/2012/08/10/186825.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Windows下编译最新版本的Libjingle</title><link>http://www.cppblog.com/tx7do/archive/2012/07/18/184081.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Wed, 18 Jul 2012 09:02:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2012/07/18/184081.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/184081.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2012/07/18/184081.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/184081.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/184081.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转载自:http://mysuperbaby.iteye.com/blog/908866&nbsp;Libjingle版本: 0.5.2操作系统: Windows XP&nbsp;编译器: Microsoft Visual C++ 2008 Express&nbsp;具体可以参考README:&nbsp;http://code.google.com/p/libjingle/source/brows...&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/archive/2012/07/18/184081.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/184081.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2012-07-18 17:02 <a href="http://www.cppblog.com/tx7do/archive/2012/07/18/184081.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>IOCP包裹类</title><link>http://www.cppblog.com/tx7do/archive/2012/07/16/183777.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Mon, 16 Jul 2012 10:38:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2012/07/16/183777.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/183777.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2012/07/16/183777.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/183777.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/183777.html</trackback:ping><description><![CDATA[头文件：<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000">/*</span><span style="color: #008000">*********************************************************************<br />*&nbsp;Copyright&nbsp;(C)&nbsp;2008&nbsp;-&nbsp;&nbsp;-&nbsp;All&nbsp;Rights&nbsp;Reserved<br />*<br />*&nbsp;文件名称:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IOCP.h<br />*&nbsp;摘&nbsp;&nbsp;&nbsp;&nbsp;要:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IOCP包裹类<br />*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />*&nbsp;作&nbsp;&nbsp;&nbsp;&nbsp;者:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yanglinbo,&nbsp;<br />*&nbsp;修&nbsp;&nbsp;&nbsp;&nbsp;改:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;查看文件最下方.<br />*&nbsp;<br />**********************************************************************</span><span style="color: #008000">*/</span><br /><br />#ifndef&nbsp;__IOCP_H__<br /><span style="color: #0000ff">#define</span>&nbsp;__IOCP_H__<br /><br /><br />#include&nbsp;&lt;assert.h&gt;<br />#include&nbsp;&lt;WinSock2.h&gt;<br /><br /><br /><span style="color: #808080">////////////////////////////////////////////////////////////////////////</span><span style="color: #008000">//<br /></span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;IOCP包装类，完成IOCP创建，关联等动作<br /></span><span style="color: #808080">////////////////////////////////////////////////////////////////////////</span><span style="color: #008000">//</span><span style="color: #808080"><br /></span><span style="color: #0000ff">class</span>&nbsp;CIOCP<br />{<br /><span style="color: #0000ff">public</span>:<br />&nbsp;&nbsp;&nbsp;&nbsp;CIOCP(<span style="color: #0000ff">int</span>&nbsp;nMaxConcurrency&nbsp;=&nbsp;-1);<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">virtual</span>&nbsp;~CIOCP(<span style="color: #0000ff">void</span>);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;CIOCP&amp;&nbsp;<span style="color: #0000ff">operator</span>&nbsp;=&nbsp;(<span style="color: #0000ff">const</span>&nbsp;CIOCP&amp;&nbsp;rht);<br />&nbsp;&nbsp;&nbsp;&nbsp;CIOCP&amp;&nbsp;<span style="color: #0000ff">operator</span>&nbsp;=&nbsp;(<span style="color: #0000ff">const</span>&nbsp;HANDLE&amp;&nbsp;rht);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">operator</span>&nbsp;HANDLE()&nbsp;<span style="color: #0000ff">const</span>;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #808080">///</span><span style="color: #008000">&nbsp;创建IOCP<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;@param&nbsp;[in]&nbsp;nMaxConcurrency&nbsp;最大线程数</span><span style="color: #808080"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;Create(<span style="color: #0000ff">int</span>&nbsp;nMaxConcurrency);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #808080">///</span><span style="color: #008000">&nbsp;销毁IOCP</span><span style="color: #808080"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;Destroy();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #808080">///</span><span style="color: #008000">&nbsp;完全端口是否有效</span><span style="color: #808080"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;IsValid()&nbsp;<span style="color: #0000ff">const</span>;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #808080">///</span><span style="color: #008000">&nbsp;关联指定SOCKET及参数到IOCP<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;@param&nbsp;[in]&nbsp;socket<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;@param&nbsp;[in]&nbsp;CompKey</span><span style="color: #808080"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;AssociateSocket(SOCKET&nbsp;socket,&nbsp;ULONG_PTR&nbsp;CompKey);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #808080">///</span><span style="color: #008000">&nbsp;发送通知到IOCP<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;@param&nbsp;[in]&nbsp;CompKey<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;@param&nbsp;[in]&nbsp;dwNumBytes<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;@param&nbsp;[in]&nbsp;po</span><span style="color: #808080"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;PostStatus(ULONG_PTR&nbsp;CompKey,&nbsp;DWORD&nbsp;dwNumBytes&nbsp;=&nbsp;0,&nbsp;OVERLAPPED*&nbsp;po&nbsp;=&nbsp;NULL);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #808080">///</span><span style="color: #008000">&nbsp;取得IOCP状态<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;@param&nbsp;[in]&nbsp;pCompKey<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;@param&nbsp;[in]&nbsp;pdwNumBytes<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;@param&nbsp;[in]&nbsp;ppo<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;@param&nbsp;[in]&nbsp;dwMilliseconds</span><span style="color: #808080"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;GetStatus(ULONG_PTR*&nbsp;pCompKey,&nbsp;PDWORD&nbsp;pdwNumBytes,&nbsp;OVERLAPPED**&nbsp;ppo,&nbsp;DWORD&nbsp;dwMilliseconds&nbsp;=&nbsp;INFINITE);<br /><br /><span style="color: #0000ff">private</span>:<br />&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_hIOCP;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #808080">///</span><span style="color: #808080">&lt;&nbsp;IOCP句柄<br /></span><span style="color: #008000">};</span><span style="color: #808080"><br /></span><br /><br /><span style="color: #0000ff">#endif</span></div><br /><br />cpp文件：<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img id="Codehighlighter1_0_281_Open_Image" onclick="this.style.display='none'; Codehighlighter1_0_281_Open_Text.style.display='none'; Codehighlighter1_0_281_Closed_Image.style.display='inline'; Codehighlighter1_0_281_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_0_281_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_0_281_Closed_Text.style.display='none'; Codehighlighter1_0_281_Open_Image.style.display='inline'; Codehighlighter1_0_281_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_0_281_Closed_Text">/**/</span><span id="Codehighlighter1_0_281_Open_Text"><span style="color: #008000">/*</span><span style="color: #008000">*********************************************************************<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />*&nbsp;Copyright&nbsp;(C)&nbsp;2008&nbsp;-&nbsp;&nbsp;-&nbsp;All&nbsp;Rights&nbsp;Reserved<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />*<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />*&nbsp;文件名称:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IOCP.cpp<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />*&nbsp;摘&nbsp;&nbsp;&nbsp;&nbsp;要:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IOCP包裹类<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />*&nbsp;作&nbsp;&nbsp;&nbsp;&nbsp;者:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yanglinbo,&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />*&nbsp;修&nbsp;&nbsp;&nbsp;&nbsp;改:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;查看文件最下方.<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />*&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />**********************************************************************</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />#include&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">StdAfx.h</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />#include&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">IOCP.h</span><span style="color: #000000">"</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img id="Codehighlighter1_359_366_Open_Image" onclick="this.style.display='none'; Codehighlighter1_359_366_Open_Text.style.display='none'; Codehighlighter1_359_366_Closed_Image.style.display='inline'; Codehighlighter1_359_366_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_359_366_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_359_366_Closed_Text.style.display='none'; Codehighlighter1_359_366_Open_Image.style.display='inline'; Codehighlighter1_359_366_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif">CIOCP::CIOCP(&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;nMaxConcurrency&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_359_366_Closed_Text">/**/</span><span id="Codehighlighter1_359_366_Open_Text"><span style="color: #008000">/*</span><span style="color: #008000">=&nbsp;-1</span><span style="color: #008000">*/</span></span><span style="color: #000000">&nbsp;)<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />:&nbsp;m_hIOCP(INVALID_HANDLE_VALUE)<br /><img id="Codehighlighter1_402_465_Open_Image" onclick="this.style.display='none'; Codehighlighter1_402_465_Open_Text.style.display='none'; Codehighlighter1_402_465_Closed_Image.style.display='inline'; Codehighlighter1_402_465_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_402_465_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_402_465_Closed_Text.style.display='none'; Codehighlighter1_402_465_Open_Image.style.display='inline'; Codehighlighter1_402_465_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_402_465_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_402_465_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(nMaxConcurrency&nbsp;</span><span style="color: #000000">!=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">1</span><span style="color: #000000">)<br /><img id="Codehighlighter1_433_463_Open_Image" onclick="this.style.display='none'; Codehighlighter1_433_463_Open_Text.style.display='none'; Codehighlighter1_433_463_Closed_Image.style.display='inline'; Codehighlighter1_433_463_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_433_463_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_433_463_Closed_Text.style.display='none'; Codehighlighter1_433_463_Open_Image.style.display='inline'; Codehighlighter1_433_463_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_433_463_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_433_463_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create(nMaxConcurrency);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />CIOCP::</span><span style="color: #000000">~</span><span style="color: #000000">CIOCP(&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;)<br /><img id="Codehighlighter1_490_504_Open_Image" onclick="this.style.display='none'; Codehighlighter1_490_504_Open_Text.style.display='none'; Codehighlighter1_490_504_Closed_Image.style.display='inline'; Codehighlighter1_490_504_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_490_504_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_490_504_Closed_Text.style.display='none'; Codehighlighter1_490_504_Open_Image.style.display='inline'; Codehighlighter1_490_504_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_490_504_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_490_504_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;Destroy();<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />CIOCP</span><span style="color: #000000">&amp;</span><span style="color: #000000">&nbsp;CIOCP::</span><span style="color: #0000ff">operator</span><span style="color: #000000">=</span><span style="color: #000000">(&nbsp;</span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;CIOCP</span><span style="color: #000000">&amp;</span><span style="color: #000000">&nbsp;rht&nbsp;)<br /><img id="Codehighlighter1_551_592_Open_Image" onclick="this.style.display='none'; Codehighlighter1_551_592_Open_Text.style.display='none'; Codehighlighter1_551_592_Closed_Image.style.display='inline'; Codehighlighter1_551_592_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_551_592_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_551_592_Closed_Text.style.display='none'; Codehighlighter1_551_592_Open_Image.style.display='inline'; Codehighlighter1_551_592_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_551_592_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_551_592_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;m_hIOCP&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;rht.m_hIOCP;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #0000ff">this</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />CIOCP</span><span style="color: #000000">&amp;</span><span style="color: #000000">&nbsp;CIOCP::</span><span style="color: #0000ff">operator</span><span style="color: #000000">=</span><span style="color: #000000">(&nbsp;</span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;HANDLE</span><span style="color: #000000">&amp;</span><span style="color: #000000">&nbsp;rht&nbsp;)<br /><img id="Codehighlighter1_640_673_Open_Image" onclick="this.style.display='none'; Codehighlighter1_640_673_Open_Text.style.display='none'; Codehighlighter1_640_673_Closed_Image.style.display='inline'; Codehighlighter1_640_673_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_640_673_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_640_673_Closed_Text.style.display='none'; Codehighlighter1_640_673_Open_Image.style.display='inline'; Codehighlighter1_640_673_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_640_673_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_640_673_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;m_hIOCP&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;rht;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #0000ff">this</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />CIOCP::</span><span style="color: #0000ff">operator</span><span style="color: #000000">&nbsp;HANDLE()&nbsp;</span><span style="color: #0000ff">const</span><span style="color: #000000"><br /><img id="Codehighlighter1_707_758_Open_Image" onclick="this.style.display='none'; Codehighlighter1_707_758_Open_Text.style.display='none'; Codehighlighter1_707_758_Closed_Image.style.display='inline'; Codehighlighter1_707_758_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_707_758_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_707_758_Closed_Text.style.display='none'; Codehighlighter1_707_758_Open_Image.style.display='inline'; Codehighlighter1_707_758_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_707_758_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_707_758_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;(HANDLE)(</span><span style="color: #0000ff">this</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;NULL&nbsp;</span><span style="color: #000000">?</span><span style="color: #000000">&nbsp;NULL&nbsp;:&nbsp;m_hIOCP);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />BOOL&nbsp;CIOCP::Create(&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;nMaxConcurrency&nbsp;)<br /><img id="Codehighlighter1_803_929_Open_Image" onclick="this.style.display='none'; Codehighlighter1_803_929_Open_Text.style.display='none'; Codehighlighter1_803_929_Closed_Image.style.display='inline'; Codehighlighter1_803_929_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_803_929_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_803_929_Closed_Text.style.display='none'; Codehighlighter1_803_929_Open_Image.style.display='inline'; Codehighlighter1_803_929_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_803_929_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_803_929_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;m_hIOCP&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;::CreateIoCompletionPort(INVALID_HANDLE_VALUE,&nbsp;NULL,&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">,&nbsp;nMaxConcurrency);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;ASSERT(IsValid());<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;IsValid();<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />BOOL&nbsp;CIOCP::Destroy()<br /><img id="Codehighlighter1_954_1086_Open_Image" onclick="this.style.display='none'; Codehighlighter1_954_1086_Open_Text.style.display='none'; Codehighlighter1_954_1086_Closed_Image.style.display='inline'; Codehighlighter1_954_1086_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_954_1086_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_954_1086_Closed_Text.style.display='none'; Codehighlighter1_954_1086_Open_Image.style.display='inline'; Codehighlighter1_954_1086_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_954_1086_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_954_1086_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(IsValid()&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;FALSE)&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;TRUE;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;bClosed&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;::CloseHandle(m_hIOCP);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;m_hIOCP&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;INVALID_HANDLE_VALUE;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;bClosed;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />BOOL&nbsp;CIOCP::AssociateSocket(&nbsp;SOCKET&nbsp;socket,&nbsp;ULONG_PTR&nbsp;CompKey&nbsp;)<br /><img id="Codehighlighter1_1153_1291_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1153_1291_Open_Text.style.display='none'; Codehighlighter1_1153_1291_Closed_Image.style.display='inline'; Codehighlighter1_1153_1291_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_1153_1291_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1153_1291_Closed_Text.style.display='none'; Codehighlighter1_1153_1291_Open_Image.style.display='inline'; Codehighlighter1_1153_1291_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1153_1291_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_1153_1291_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;ASSERT(IsValid());<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(&nbsp;IsValid()&nbsp;== FALSE )&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;FALSE;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;(::CreateIoCompletionPort((HANDLE)socket,&nbsp;m_hIOCP,&nbsp;CompKey,&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">)&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;m_hIOCP);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img id="Codehighlighter1_1354_1360_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1354_1360_Open_Text.style.display='none'; Codehighlighter1_1354_1360_Closed_Image.style.display='inline'; Codehighlighter1_1354_1360_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_1354_1360_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1354_1360_Closed_Text.style.display='none'; Codehighlighter1_1354_1360_Open_Image.style.display='inline'; Codehighlighter1_1354_1360_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif">BOOL&nbsp;CIOCP::PostStatus(&nbsp;ULONG_PTR&nbsp;CompKey,&nbsp;DWORD&nbsp;dwNumBytes&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1354_1360_Closed_Text">/**/</span><span id="Codehighlighter1_1354_1360_Open_Text"><span style="color: #008000">/*</span><span style="color: #008000">=&nbsp;0</span><span style="color: #008000">*/</span></span><span style="color: #000000">,&nbsp;OVERLAPPED</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;po&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1378_1387_Closed_Text">/**/</span><span id="Codehighlighter1_1378_1387_Open_Text"><span style="color: #008000">/*</span><span style="color: #008000">=&nbsp;NULL</span><span style="color: #008000">*/</span></span><span style="color: #000000">&nbsp;)<br /><img id="Codehighlighter1_1391_1517_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1391_1517_Open_Text.style.display='none'; Codehighlighter1_1391_1517_Closed_Image.style.display='inline'; Codehighlighter1_1391_1517_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_1391_1517_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1391_1517_Closed_Text.style.display='none'; Codehighlighter1_1391_1517_Open_Image.style.display='inline'; Codehighlighter1_1391_1517_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1391_1517_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_1391_1517_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;ASSERT(IsValid());<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(&nbsp;IsValid()&nbsp;== FALSE&nbsp;)&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;FALSE;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;::PostQueuedCompletionStatus(m_hIOCP,&nbsp;dwNumBytes,&nbsp;CompKey,&nbsp;po);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img id="Codehighlighter1_1623_1636_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1623_1636_Open_Text.style.display='none'; Codehighlighter1_1623_1636_Closed_Image.style.display='inline'; Codehighlighter1_1623_1636_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_1623_1636_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1623_1636_Closed_Text.style.display='none'; Codehighlighter1_1623_1636_Open_Image.style.display='inline'; Codehighlighter1_1623_1636_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif">BOOL&nbsp;CIOCP::GetStatus(&nbsp;ULONG_PTR</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;pCompKey,&nbsp;PDWORD&nbsp;pdwNumBytes,&nbsp;OVERLAPPED</span><span style="color: #000000">**</span><span style="color: #000000">&nbsp;ppo,&nbsp;DWORD&nbsp;dwMilliseconds&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1623_1636_Closed_Text">/**/</span><span id="Codehighlighter1_1623_1636_Open_Text"><span style="color: #008000">/*</span><span style="color: #008000">=&nbsp;INFINITE</span><span style="color: #008000">*/</span></span><span style="color: #000000">&nbsp;)<br /><img id="Codehighlighter1_1640_1784_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1640_1784_Open_Text.style.display='none'; Codehighlighter1_1640_1784_Closed_Image.style.display='inline'; Codehighlighter1_1640_1784_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_1640_1784_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1640_1784_Closed_Text.style.display='none'; Codehighlighter1_1640_1784_Open_Image.style.display='inline'; Codehighlighter1_1640_1784_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1640_1784_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_1640_1784_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;ASSERT(IsValid());<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(&nbsp;IsValid()&nbsp;== FALSE&nbsp;)&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;FALSE;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;::GetQueuedCompletionStatus(m_hIOCP,&nbsp;pdwNumBytes,&nbsp;pCompKey,&nbsp;ppo,&nbsp;dwMilliseconds);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />BOOL&nbsp;CIOCP::IsValid()&nbsp;</span><span style="color: #0000ff">const</span><span style="color: #000000"><br /><img id="Codehighlighter1_1815_1881_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1815_1881_Open_Text.style.display='none'; Codehighlighter1_1815_1881_Closed_Image.style.display='inline'; Codehighlighter1_1815_1881_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_1815_1881_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_1815_1881_Closed_Text.style.display='none'; Codehighlighter1_1815_1881_Open_Image.style.display='inline'; Codehighlighter1_1815_1881_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_1815_1881_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_1815_1881_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;(m_hIOCP&nbsp;</span><span style="color: #000000">!=</span><span style="color: #000000">&nbsp;NULL)&nbsp;</span><span style="color: #000000">&amp;&amp;</span><span style="color: #000000">&nbsp;(m_hIOCP&nbsp;</span><span style="color: #000000">!=</span><span style="color: #000000">&nbsp;INVALID_HANDLE_VALUE);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></span></div><img src ="http://www.cppblog.com/tx7do/aggbug/183777.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2012-07-16 18:38 <a href="http://www.cppblog.com/tx7do/archive/2012/07/16/183777.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于使用libcurl的注意事项</title><link>http://www.cppblog.com/tx7do/archive/2012/02/20/166048.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Mon, 20 Feb 2012 03:39:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2012/02/20/166048.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/166048.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2012/02/20/166048.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/166048.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/166048.html</trackback:ping><description><![CDATA[<strong style="font-size: 18pt">libcurl与CLOSE_WAIT</strong><br /><span style="color: red">转载自：</span><a href="http://blog.sunshow.net/2010/03/libcurl-and-close-wait/"><span style="color: red">http://blog.sunshow.net/2010/03/libcurl-and-close-wait/</span></a><br /><span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 15px/21px Georgia, Times, 'Times New Roman', serif; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span">
<p style="border-bottom-style: none; padding-bottom: 0px; background-color: transparent; margin: 0px 0px 21px; outline-style: none; outline-color: ; border-left-style: none; padding-left: 0px; padding-right: 0px; border-top-style: none; border-right-style: none; font-size: 15px; vertical-align: baseline; text-decoration: none; padding-top: 0px; background-origin: initial; background-clip: initial">调用libcurl下载，然后使用netstat查看发现有大量的TCP连接保持在CLOSE_WAIT状态<br />查看libcurl的文档说明，有这样一个选项：</p>
<blockquote style="border-bottom-style: none; padding-bottom: 0px; background-color: transparent; font-style: italic; margin: 0px 2.5em; outline-style: none; outline-color: ; border-left-style: none; padding-left: 0px; padding-right: 0px; border-top-style: none; color: rgb(85,85,85); border-right-style: none; font-size: 15px; vertical-align: baseline; quotes: none; text-decoration: none; padding-top: 0px; background-origin: initial; background-clip: initial">
<p style="border-bottom-style: none; padding-bottom: 0px; background-color: transparent; margin: 0px 0px 21px; outline-style: none; outline-color: ; border-left-style: none; padding-left: 0px; padding-right: 0px; border-top-style: none; border-right-style: none; font-size: 15px; vertical-align: baseline; text-decoration: none; padding-top: 0px; background-origin: initial; background-clip: initial">CURLOPT_FORBID_REUSE</p>
<p style="border-bottom-style: none; padding-bottom: 0px; background-color: transparent; margin: 0px 0px 21px; outline-style: none; outline-color: ; border-left-style: none; padding-left: 0px; padding-right: 0px; border-top-style: none; border-right-style: none; font-size: 15px; vertical-align: baseline; text-decoration: none; padding-top: 0px; background-origin: initial; background-clip: initial">Pass a long. Set to 1 to make the next transfer explicitly close the connection when done. Normally, libcurl keeps all connections alive when done with one transfer in case a succeeding one follows that can re-use them. This option should be used with caution and only if you understand what it does. Set to 0 to have libcurl keep the connection open for possible later re-use (default behavior).</p></blockquote>
<p style="border-bottom-style: none; padding-bottom: 0px; background-color: transparent; margin: 0px 0px 21px; outline-style: none; outline-color: ; border-left-style: none; padding-left: 0px; padding-right: 0px; border-top-style: none; border-right-style: none; font-size: 15px; vertical-align: baseline; text-decoration: none; padding-top: 0px; background-origin: initial; background-clip: initial">也就是说，默认情况下libcurl完成一个任务以后，出于重用连接的考虑不会马上关闭<br />如果没有新的TCP请求来重用这个连接，那么只能等到CLOSE_WAIT超时，这个时间默认在7200秒甚至更高，太多的CLOSE_WAIT连接会导致性能问题</p>
<p style="border-bottom-style: none; padding-bottom: 0px; background-color: transparent; margin: 0px 0px 21px; outline-style: none; outline-color: ; border-left-style: none; padding-left: 0px; padding-right: 0px; border-top-style: none; border-right-style: none; font-size: 15px; vertical-align: baseline; text-decoration: none; padding-top: 0px; background-origin: initial; background-clip: initial">解决方法：</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><span style="color: #000000">curl_easy_setopt(curl,&nbsp;CURLOPT_FORBID_REUSE,&nbsp;</span><span style="color: #000000">1</span><span style="color: #000000">);</span></div>
<p style="border-bottom-style: none; padding-bottom: 0px; background-color: transparent; margin: 0px 0px 21px; outline-style: none; outline-color: ; border-left-style: none; padding-left: 0px; padding-right: 0px; border-top-style: none; border-right-style: none; font-size: 15px; vertical-align: baseline; text-decoration: none; padding-top: 0px; background-origin: initial; background-clip: initial"><span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 15px/21px Georgia, Times, 'Times New Roman', serif; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span">&nbsp;最好再修改一下TCP参数调低CLOSE_WAIT和TIME_WAIT的超时时间</p>
<div style="border-bottom-style: none; padding-bottom: 0px; background-color: transparent; margin: 0px; outline-style: none; outline-color: ; border-left-style: none; padding-left: 0px; padding-right: 0px; border-top-style: none; border-right-style: none; clear: both; font-size: 15px; vertical-align: baseline; text-decoration: none; padding-top: 0px; background-origin: initial; background-clip: initial"></div>
<p style="border-bottom-style: none; padding-bottom: 0px; background-color: transparent; margin: 0px 0px 21px; outline-style: none; outline-color: ; border-left-style: none; padding-left: 0px; padding-right: 0px; border-top-style: none; border-right-style: none; font-size: 15px; vertical-align: baseline; text-decoration: none; padding-top: 0px; background-origin: initial; background-clip: initial"></span><br /><br /><br /><strong style="font-size: 18pt">libcurl 使用笔记</strong><br /><span style="color: red">转载自：</span><a href="http://gcoder.blogbus.com/logs/54871550.html"><span style="color: red">http://gcoder.blogbus.com/logs/54871550.html</span></a><br /></p>
<p>libcurl 是一个很不错的库，支持http，ftp等很多的协议。使用库最大的心得就是，不仔细看文档，仅仅看着例子就写程序，是一件危险的事情。我的程序崩溃了，我怀疑是自己代码写的问题，后来发现是库没用对。不仔细看文档（有时候文档本身也比较差劲，这时除了看仔细外，还要多动脑子，考虑它是怎么实现的），后果很严重。不加思索的使用别人的库或者代码，有时候很惬意，但是出问题时，却是寝食难安的。</p>
<p>1. CURLcode curl_global_init(long flags); 在多线程应用中，需要在主线程中调用这个函数。这个函数设置libcurl所需的环境。通常情况，如果不显式的调用它，第一次调用curl_easy_init()时，curl_easy_init 会调用 curl_global_init，在单线程环境下，这不是问题。但是多线程下就不行了，因为curl_global_init不是线程安全的。在多个线程中调用curl_easy_int，然后如果两个线程同时发现curl_global_init还没有被调用，同时调用curl_global_init，悲剧就发生了。这种情况发生的概率很小，但可能性是存在的。</p>
<p>2. libcurl 有个很好的特性，它甚至可以控制域名解析的超时。但是在默认情况下，它是使用alarm + siglongjmp 实现的。用alarm在多线程下做超时，本身就几乎不可能。如果只是使用alarm，并不会导致程序崩溃，但是，再加上siglongjmp，就要命了（程序崩溃的很可怕，core中几乎看不出有用信息），因为其需要一个sigjmp_buf型的全局变量，多线程修改它。（通常情况下，可以每个线程一个 sigjmp_buf 型的变量，这种情况下，多线程中使用 siglongjmp 是没有问题的，但是libcurl只有一个全局变量，所有的线程都会用）。</p>
<p>&nbsp; 具体是类似 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L) 的超时设置，导致alarm的使用（估计发生在域名解析阶段），如前所述，这在多线程中是不行的。解决方式是禁用掉alarm这种超时， curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L)。</p>
<p>&nbsp; 这样，多线程中使用超时就安全了。但是域名解析就没了超时机制，碰到很慢的域名解析，也很麻烦。文档的建议是 Consider building libcurl with c-ares support to enable asynchronous DNS lookups, which enables nice timeouts for name resolves without signals.&nbsp; c-ares 是异步的 DNS 解决方案。</p>
<p><br /><br class="Apple-interchange-newline" /></span><br />&nbsp;<span style="font-size: 18pt"><strong>libcurl 多线程使用注意事项</strong></span><br /><span style="color: red">转载自:</span><a href="http://blog.csdn.net/jaylong35/article/details/6439549"><span style="color: red">http://blog.csdn.net/jaylong35/article/details/6439549</span></a><br /><span style="text-align: left; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 14px/25px Arial; white-space: normal; orphans: 2; color: rgb(51,51,51); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"> </p>
<p>1、问题来源，多线程使用Libcurl导致程序跑一段时间后自己退出，没有明显的异常。找不到合适的BUG。</p>
<p>&nbsp;最后通过查看资料和网上找的一些文章，发现，原来是信号处理的问题：</p>
<p><span class="nroffip"><strong>CURLOPT_NOSIGNAL</strong></span></p>
<p class="level0"><span class="nroffip"><strong></strong></span></p>
<p class="level1">Pass a long. If it is 1, libcurl will not use any functions that install signal handlers or any functions that cause signals to be sent to the process.<span class="Apple-converted-space">&nbsp;</span><span style="font-family: mceinline">This option is mainly here to allow multi-threaded unix applications to still set/use all timeout options etc, without risking getting signals.<span class="Apple-converted-space">&nbsp;</span></span>(Added in 7.10)</p>
<p class="level1">If this option is set and libcurl has been built with the standard name resolver, timeouts will not occur while the name resolve takes place. Consider building libcurl with c-ares support to enable asynchronous DNS lookups, which enables nice timeouts for name resolves without signals.</p>
<p class="level1">Setting<span class="Apple-converted-space">&nbsp;</span><a style="color: rgb(51,102,153); text-decoration: none" class="emphasis" href="http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTNOSIGNAL">CURLOPT_NOSIGNAL</a><span class="Apple-converted-space">&nbsp;</span>to 1 makes libcurl NOT ask the system to ignore SIGPIPE signals, which otherwise are sent by the system when trying to send data to a socket which is closed in the other end. libcurl makes an effort to never cause such SIGPIPEs to trigger, but some operating systems have no way to avoid them and even on those that have there are some corner cases when they may still happen, contrary to our desire.&nbsp;</p>
<p class="level1">就是当多个线程都使用超时处理的时候，同时主线程中有sleep或是wait等操作。如果不设置这个选项，libcurl将会发信号打断这个wait从而导致程序退出。</p>
<p class="level1">所以，在使用的时候把这个选项设置成1就可以了.</p>
<p class="level1">curl_setopt(curl,&nbsp;CURLOPT_NOSIGNAL, 1L);</p>
<p class="level1"><br />2、关于libcurl库的初始化和关闭：curl_global_init()和curl_global_cleanup()</p>
<p class="level1">这两个函数并不是线程安全的。所以只能在主线程中进行一次的初始化和清除。</p>
<p class="level1">虽然这个不是一定就会有问题，但是如果不这样处理还是有概率发生的。</span></p><img src ="http://www.cppblog.com/tx7do/aggbug/166048.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2012-02-20 11:39 <a href="http://www.cppblog.com/tx7do/archive/2012/02/20/166048.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>wininet 和“锟斤拷”</title><link>http://www.cppblog.com/tx7do/archive/2012/02/19/166014.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Sun, 19 Feb 2012 15:07:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2012/02/19/166014.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/166014.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2012/02/19/166014.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/166014.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/166014.html</trackback:ping><description><![CDATA[转载自：<a href="http://www.superfection.com/blog/?p=43">http://www.superfection.com/blog/?p=43</a><br /><br />
<p>魔爪的作者Djunny曾经说过，下载的主要问题是要熟悉各个网络的不同特点（比中文确切的英文单词应该是whimsicalness）。这点我现在是深有体会。比如大部分网站的url是基于utf8的，但是有些却是基于GB2312的，这些网站wininet可能不能正确处理。</p>
<p>其实ie是能正确处理的，但是微软却没有把相应的功能放到wininet里面，这目的只有一个，微软想使得ie的功能比wininet多一点，也就是故意要让程序员麻烦一些。何苦？你让人家难受，人家自然要找你的漏洞。</p>
<p>为何不放弃wininet而用liburl之类的程序，毕竟后者若干年的开发，久经考验。原因：做个简单的工具虽然可以用libcurl，但是发布uread这样的应用就不好，要至少多一个dll，麻烦。</p>
<p>好，下面谈谈&#8220;锟斤拷&#8221;的问题。其实这个问题已经有人谈过，参见 <a href="http://hooopo.javaeye.com/blog/352451">http://hooopo.javaeye.com/blog/352451</a>. 但是这里是由wininet引起的。采用简单的wininet调用，访问：</p>
<p><a href="http://www.sjtxt.com/soft/download.asp?softid=21519&amp;downid=2&amp;id=21525">http://www.sjtxt.com/soft/download.asp?softid=21519&amp;downid=2&amp;id=21525</a></p>
<p>你会发现重定向到一个网址：</p>
<p><a href="http://down1.sjtxt.com/2010-2/">http://down1.sjtxt.com/2010-2/</a>锟斤拷士锟斤拷陆.rar</p>
<p>为什么这里显示&#8220;锟斤拷&#8221;，就是wininet没有正确地解码，把这个网站返回的gb码当成utf8, 先转为utf16,然后又转成utf8,最后按照gb显示出来就变成了&#8220;锟斤拷&#8221;了（实际的转向地址为<a href="http://down1.sjtxt.com/2010-2/">http://down1.sjtxt.com/2010-2/</a>斗士大陆.rar，感兴趣的可以把这个&#8220;锟斤拷&#8221;如何出来的详细推演一下）。</p>
<p>处理这个问题的办法是不要让wininet进行自动重定向（301 302之类），自己进行处理。这下更麻烦了，本来用wininet就是为了省事，没想到却要多写若干代码。</p>
<p>还有一个可笑的事情是，wininet的ansi版本和unicode版本不同，后者自动地把url的path部分当成utf8处理，而前者不会。我有些工具是用delphi7写的，有些是用delphi 2010写的，对某些网站，后者则要调用以下这样的函数</p>
<p>InternetSetOption(hSession, 100{INTERNET_OPTION_CODEPAGE_PATH}, @CP_CHINA, sizeof(CP_CHINA));</p>
<p>其中最新的常量，Delphi中还没有定义（CP_CHINA = 936）。</p>
<p>这些问题的解决，只是把工具做的好一些。实际上没有什么意义，都是微软没有把事情做好。你做好点，大家就可以做些有意义的事情是不？</p>
<p>&nbsp;</p><img src ="http://www.cppblog.com/tx7do/aggbug/166014.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2012-02-19 23:07 <a href="http://www.cppblog.com/tx7do/archive/2012/02/19/166014.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>libcurl教程</title><link>http://www.cppblog.com/tx7do/archive/2012/02/19/166011.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Sun, 19 Feb 2012 14:53:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2012/02/19/166011.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/166011.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2012/02/19/166011.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/166011.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/166011.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转载自：http://jishi.cntv.cn/xingyuaidejueze/classpage/video/20120212/100600.shtml &nbsp;&nbsp;&nbsp; 原文地址：http://curl.haxx.se/libcurl/c/libcurl-tutorial.html&nbsp;&nbsp;&nbsp; 译者：JGood(http://blog....&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/archive/2012/02/19/166011.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/166011.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2012-02-19 22:53 <a href="http://www.cppblog.com/tx7do/archive/2012/02/19/166011.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>YouTube架构</title><link>http://www.cppblog.com/tx7do/archive/2012/01/13/164131.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 13 Jan 2012 10:15:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2012/01/13/164131.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/164131.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2012/01/13/164131.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/164131.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/164131.html</trackback:ping><description><![CDATA[<div><strong style="color: red">原文链接：</strong><a style="color: red" href="http://www.highscalability.com/youtube-architecture"><strong>http://www.highscalability.com/youtube-architecture</strong></a><br style="color: red" /><strong style="color: red">译文链接：</strong><a style="color: red" href="http://hideto.iteye.com/blog/129726"><strong>http://hideto.iteye.com/blog/129726</strong></a><br /><br /><span style="text-align: left; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 14px/25px Helvetica, Tahoma, Arial, sans-serif; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span">原文:<span class="Apple-converted-space">&nbsp;</span><a style="color: rgb(0,102,153); text-decoration: underline" href="http://www.highscalability.com/youtube-architecture" target="_blank">YouTube Architecture</a><span class="Apple-converted-space">&nbsp;</span><br /><br />YouTube发展迅速，每天超过1亿的视频点击量，但只有很少人在维护站点和确保伸缩性。<span class="Apple-converted-space">&nbsp;</span><br /><br /><strong style="font-weight: bold">平台</strong><span class="Apple-converted-space">&nbsp;</span><br />Apache<span class="Apple-converted-space">&nbsp;</span><br />Python<span class="Apple-converted-space">&nbsp;</span><br />Linux(SuSe)<span class="Apple-converted-space">&nbsp;</span><br />MySQL<span class="Apple-converted-space">&nbsp;</span><br />psyco，一个动态的Python到C的编译器<span class="Apple-converted-space">&nbsp;</span><br />lighttpd代替Apache做视频查看<span class="Apple-converted-space">&nbsp;</span><br /><br /><strong style="font-weight: bold">状态</strong><span class="Apple-converted-space">&nbsp;</span><br />支持每天超过1亿的视频点击量<span class="Apple-converted-space">&nbsp;</span><br />成立于2005年2月<span class="Apple-converted-space">&nbsp;</span><br />于2006年3月达到每天3千万的视频点击量<span class="Apple-converted-space">&nbsp;</span><br />于2006年7月达到每天1亿的视频点击量<span class="Apple-converted-space">&nbsp;</span><br />2个系统管理员，2个伸缩性软件架构师<span class="Apple-converted-space">&nbsp;</span><br />2个软件开发工程师，2个网络工程师，1个DBA<span class="Apple-converted-space">&nbsp;</span><br /><br /><strong style="font-weight: bold">处理飞速增长的流量</strong><span class="Apple-converted-space">&nbsp;
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #0000ff">while</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">true</span><span style="color: #000000">)<br /><img id="Codehighlighter1_13_98_Open_Image" onclick="this.style.display='none'; Codehighlighter1_13_98_Open_Text.style.display='none'; Codehighlighter1_13_98_Closed_Image.style.display='inline'; Codehighlighter1_13_98_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_13_98_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_13_98_Closed_Text.style.display='none'; Codehighlighter1_13_98_Open_Image.style.display='inline'; Codehighlighter1_13_98_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_13_98_Closed_Text"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_13_98_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;identify_and_fix_bottlenecks();<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;drink();<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;sleep();<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;notice_new_bottleneck();<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span></div></span><span style="text-align: left; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 12px/18px Helvetica, Tahoma, Arial, sans-serif; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"> 
<div style="line-height: 1.8em; font-size: 14px" id="blog_content" class="blog_content">每天运行该循环多次<span class="Apple-converted-space">&nbsp;</span><br /><br /><strong style="font-weight: bold">Web服务器</strong><span class="Apple-converted-space">&nbsp;</span><br />1，NetScaler用于负载均衡和静态内容缓存<span class="Apple-converted-space">&nbsp;</span><br />2，使用mod_fast_cgi运行Apache<span class="Apple-converted-space">&nbsp;</span><br />3，使用一个Python应用服务器来处理请求的路由<span class="Apple-converted-space">&nbsp;</span><br />4，应用服务器与多个数据库和其他信息源交互来获取数据和格式化html页面<span class="Apple-converted-space">&nbsp;</span><br />5，一般可以通过添加更多的机器来在Web层提高伸缩性<span class="Apple-converted-space">&nbsp;</span><br />6，Python的Web层代码通常不是性能瓶颈，大部分时间阻塞在RPC<span class="Apple-converted-space">&nbsp;</span><br />7，Python允许快速而灵活的开发和部署<span class="Apple-converted-space">&nbsp;</span><br />8，通常每个页面服务少于100毫秒的时间<span class="Apple-converted-space">&nbsp;</span><br />9，使用psyco(一个类似于JIT编译器的动态的Python到C的编译器)来优化内部循环<span class="Apple-converted-space">&nbsp;</span><br />10，对于像加密等密集型CPU活动，使用C扩展<span class="Apple-converted-space">&nbsp;</span><br />11，对于一些开销昂贵的块使用预先生成并缓存的html<span class="Apple-converted-space">&nbsp;</span><br />12，数据库里使用行级缓存<span class="Apple-converted-space">&nbsp;</span><br />13，缓存完整的Python对象<span class="Apple-converted-space">&nbsp;</span><br />14，有些数据被计算出来并发送给各个程序，所以这些值缓存在本地内存中。这是个使用不当的策略。应用服务器里最快的缓存将预先计算的值发送给所有服务器也花不了多少时间。只需弄一个代理来监听更改，预计算，然后发送。<span class="Apple-converted-space">&nbsp;</span><br /><br /><strong style="font-weight: bold">视频服务</strong><span class="Apple-converted-space">&nbsp;</span><br />1，花费包括带宽，硬件和能源消耗<span class="Apple-converted-space">&nbsp;</span><br />2，每个视频由一个迷你集群来host，每个视频被超过一台机器持有<span class="Apple-converted-space">&nbsp;</span><br />3，使用一个集群意味着：<span class="Apple-converted-space">&nbsp;</span><br />-更多的硬盘来持有内容意味着更快的速度<span class="Apple-converted-space">&nbsp;</span><br />-failover。如果一台机器出故障了，另外的机器可以继续服务<span class="Apple-converted-space">&nbsp;</span><br />-在线备份<span class="Apple-converted-space">&nbsp;</span><br />4，使用lighttpd作为Web服务器来提供视频服务：<span class="Apple-converted-space">&nbsp;</span><br />-Apache开销太大<span class="Apple-converted-space">&nbsp;</span><br />-使用epoll来等待多个fds<span class="Apple-converted-space">&nbsp;</span><br />-从单进程配置转变为多进程配置来处理更多的连接<span class="Apple-converted-space">&nbsp;</span><br />5，大部分流行的内容移到CDN：<span class="Apple-converted-space">&nbsp;</span><br />-CDN在多个地方备份内容，这样内容离用户更近的机会就会更高<span class="Apple-converted-space">&nbsp;</span><br />-CDN机器经常内存不足，因为内容太流行以致很少有内容进出内存的颠簸<span class="Apple-converted-space">&nbsp;</span><br />6，不太流行的内容(每天1-20浏览次数)在许多colo站点使用YouTube服务器<span class="Apple-converted-space">&nbsp;</span><br />-长尾效应。一个视频可以有多个播放，但是许多视频正在播放。随机硬盘块被访问<span class="Apple-converted-space">&nbsp;</span><br />-在这种情况下缓存不会很好，所以花钱在更多的缓存上可能没太大意义。<span class="Apple-converted-space">&nbsp;</span><br />-调节RAID控制并注意其他低级问题<span class="Apple-converted-space">&nbsp;</span><br />-调节每台机器上的内存，不要太多也不要太少<span class="Apple-converted-space">&nbsp;</span><br /><br /><strong style="font-weight: bold">视频服务关键点</strong><span class="Apple-converted-space">&nbsp;</span><br />1，保持简单和廉价<span class="Apple-converted-space">&nbsp;</span><br />2，保持简单网络路径，在内容和用户间不要有太多设备<span class="Apple-converted-space">&nbsp;</span><br />3，使用常用硬件，昂贵的硬件很难找到帮助文档<span class="Apple-converted-space">&nbsp;</span><br />4，使用简单而常见的工具，使用构建在Linux里或之上的大部分工具<span class="Apple-converted-space">&nbsp;</span><br />5，很好的处理随机查找(SATA，tweaks)<span class="Apple-converted-space">&nbsp;</span><br /><br /><strong style="font-weight: bold">缩略图服务</strong><span class="Apple-converted-space">&nbsp;</span><br />1，做到高效令人惊奇的难<span class="Apple-converted-space">&nbsp;</span><br />2，每个视频大概4张缩略图，所以缩略图比视频多很多<span class="Apple-converted-space">&nbsp;</span><br />3，缩略图仅仅host在几个机器上<span class="Apple-converted-space">&nbsp;</span><br />4，持有一些小东西所遇到的问题：<span class="Apple-converted-space">&nbsp;</span><br />-OS级别的大量的硬盘查找和inode和页面缓存问题<span class="Apple-converted-space">&nbsp;</span><br />-单目录文件限制，特别是Ext3，后来移到多分层的结构。内核2.6的最近改进可能让Ext3允许大目录，但在一个文件系统里存储大量文件不是个好主意<span class="Apple-converted-space">&nbsp;</span><br />-每秒大量的请求，因为Web页面可能在页面上显示60个缩略图<span class="Apple-converted-space">&nbsp;</span><br />-在这种高负载下Apache表现的非常糟糕<span class="Apple-converted-space">&nbsp;</span><br />-在Apache前端使用squid，这种方式工作了一段时间，但是由于负载继续增加而以失败告终。它让每秒300个请求变为20个<span class="Apple-converted-space">&nbsp;</span><br />-尝试使用lighttpd但是由于使用单线程它陷于困境。遇到多进程的问题，因为它们各自保持自己单独的缓存<span class="Apple-converted-space">&nbsp;</span><br />-如此多的图片以致一台新机器只能接管24小时<span class="Apple-converted-space">&nbsp;</span><br />-重启机器需要6-10小时来缓存<span class="Apple-converted-space">&nbsp;</span><br />5，为了解决所有这些问题YouTube开始使用Google的BigTable，一个分布式数据存储：<span class="Apple-converted-space">&nbsp;</span><br />-避免小文件问题，因为它将文件收集到一起<span class="Apple-converted-space">&nbsp;</span><br />-快，错误容忍<span class="Apple-converted-space">&nbsp;</span><br />-更低的延迟，因为它使用分布式多级缓存，该缓存与多个不同collocation站点工作<span class="Apple-converted-space">&nbsp;</span><br />-更多信息参考<a style="color: rgb(0,102,153); text-decoration: underline" href="http://highscalability.com/google-architecture" target="_blank">Google Architecture</a>，<a style="color: rgb(0,102,153); text-decoration: underline" href="http://highscalability.com/googletalk-architecture" target="_blank">GoogleTalk Architecture</a>和<a style="color: rgb(0,102,153); text-decoration: underline" href="http://highscalability.com/tags/bigtable" target="_blank">BigTable</a><span class="Apple-converted-space">&nbsp;</span><br /><br /><strong style="font-weight: bold">数据库</strong><span class="Apple-converted-space">&nbsp;</span><br />1，早期<span class="Apple-converted-space">&nbsp;</span><br />-使用MySQL来存储元数据，如用户，tags和描述<span class="Apple-converted-space">&nbsp;</span><br />-使用一整个10硬盘的RAID 10来存储数据<span class="Apple-converted-space">&nbsp;</span><br />-依赖于信用卡所以YouTube租用硬件<span class="Apple-converted-space">&nbsp;</span><br />-YouTube经过一个常见的革命：单服务器，然后单master和多read slaves，然后数据库分区，然后sharding方式<span class="Apple-converted-space">&nbsp;</span><br />-痛苦与备份延迟。master数据库是多线程的并且运行在一个大机器上所以它可以处理许多工作，slaves是单线程的并且通常运行在小一些的服务器上并且备份是异步的，所以slaves会远远落后于master<span class="Apple-converted-space">&nbsp;</span><br />-更新引起缓存失效，硬盘的慢I/O导致慢备份<span class="Apple-converted-space">&nbsp;</span><br />-使用备份架构需要花费大量的money来获得增加的写性能<span class="Apple-converted-space">&nbsp;</span><br />-YouTube的一个解决方案是通过把数据分成两个集群来将传输分出优先次序：一个视频查看池和一个一般的集群<span class="Apple-converted-space">&nbsp;</span><br />2，后期<span class="Apple-converted-space">&nbsp;</span><br />-数据库分区<span class="Apple-converted-space">&nbsp;</span><br />-分成shards，不同的用户指定到不同的shards<span class="Apple-converted-space">&nbsp;</span><br />-扩散读写<span class="Apple-converted-space">&nbsp;</span><br />-更好的缓存位置意味着更少的IO<span class="Apple-converted-space">&nbsp;</span><br />-导致硬件减少30%<span class="Apple-converted-space">&nbsp;</span><br />-备份延迟降低到0<span class="Apple-converted-space">&nbsp;</span><br />-现在可以任意提升数据库的伸缩性<span class="Apple-converted-space">&nbsp;</span><br /><br /><strong style="font-weight: bold">数据中心策略</strong><span class="Apple-converted-space">&nbsp;</span><br />1，依赖于信用卡，所以最初只能使用受管主机提供商<span class="Apple-converted-space">&nbsp;</span><br />2，受管主机提供商不能提供伸缩性，不能控制硬件或使用良好的网络协议<span class="Apple-converted-space">&nbsp;</span><br />3，YouTube改为使用colocation arrangement。现在YouTube可以自定义所有东西并且协定自己的契约<span class="Apple-converted-space">&nbsp;</span><br />4，使用5到6个数据中心加CDN<span class="Apple-converted-space">&nbsp;</span><br />5，视频来自任意的数据中心，不是最近的匹配或其他什么。如果一个视频足够流行则移到CDN<span class="Apple-converted-space">&nbsp;</span><br />6，依赖于视频带宽而不是真正的延迟。可以来自任何colo<span class="Apple-converted-space">&nbsp;</span><br />7，图片延迟很严重，特别是当一个页面有60张图片时<span class="Apple-converted-space">&nbsp;</span><br />8，使用BigTable将图片备份到不同的数据中心，代码查看谁是最近的<span class="Apple-converted-space">&nbsp;</span><br /><br /><strong style="font-weight: bold">学到的东西</strong><span class="Apple-converted-space">&nbsp;</span><br />1，Stall for time。创造性和风险性的技巧让你在短期内解决问题而同时你会发现长期的解决方案<span class="Apple-converted-space">&nbsp;</span><br />2，Proioritize。找出你的服务中核心的东西并对你的资源分出优先级别<span class="Apple-converted-space">&nbsp;</span><br />3，Pick your battles。别怕将你的核心服务分出去。YouTube使用CDN来分布它们最流行的内容。创建自己的网络将花费太多时间和太多money<span class="Apple-converted-space">&nbsp;</span><br />4，Keep it simple！简单允许你更快的重新架构来回应问题<span class="Apple-converted-space">&nbsp;</span><br />5，Shard。Sharding帮助隔离存储，CPU，内存和IO，不仅仅是获得更多的写性能<span class="Apple-converted-space">&nbsp;</span><br />6，Constant iteration on bottlenecks：<span class="Apple-converted-space">&nbsp;</span><br />-软件：DB，缓存<span class="Apple-converted-space">&nbsp;</span><br />-OS：硬盘I/O<span class="Apple-converted-space">&nbsp;</span><br />-硬件：内存，RAID<span class="Apple-converted-space">&nbsp;</span><br />7，You succeed as a team。拥有一个跨越条律的了解整个系统并知道系统内部是什么样的团队，如安装打印机，安装机器，安装网络等等的人。With a good team all things are possible。</div>
<div style="display: block" id="bottoms" class="clearfix"></span><br class="Apple-interchange-newline" /></div><br /></span></div><img src ="http://www.cppblog.com/tx7do/aggbug/164131.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2012-01-13 18:15 <a href="http://www.cppblog.com/tx7do/archive/2012/01/13/164131.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang风格的并行（Erlang Style Concurrency）</title><link>http://www.cppblog.com/tx7do/archive/2011/12/29/163128.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Thu, 29 Dec 2011 10:02:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2011/12/29/163128.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/163128.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2011/12/29/163128.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/163128.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/163128.html</trackback:ping><description><![CDATA[<div>转载自：<a href="http://cplusplus.wikidot.com/cn:erlang-style-concurrency">http://cplusplus.wikidot.com/cn:erlang-style-concurrency</a><br /><br /><span style="widows: 2; text-transform: none; text-indent: 0px; letter-spacing: normal; font: 13px verdana, arial, helvetica, sans-serif; white-space: normal; orphans: 2; color: rgb(34,34,34); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"> 
<div id="page-content">
<p>我们常常能在 Erlang 的文档和源码之中看到<a style="color: rgb(3,3,144)" onclick="window.open(this.href, '_blank'); return false;" href="http://ulf.wiger.net/weblog/">Ulf Wiger</a>这个名字，他是 Erlang 最初的开发者之一。最近他写了一篇博客《<a style="color: rgb(3,3,144)" onclick="window.open(this.href, '_blank'); return false;" href="http://ulf.wiger.net/weblog/?p=10">What is Erlang-Style Concurrency?</a>》对于&#8220;<strong>Erlang风格的并行</strong>&#8221;发表了自己的看法，粗浅译来，给大家共享。</p>
<p>原文：<a style="color: rgb(3,3,144)" onclick="window.open(this.href, '_blank'); return false;" href="http://ulf.wiger.net/weblog/?p=10">http://ulf.wiger.net/weblog/?p=10</a><br />译文：<a style="color: rgb(3,3,144)" onclick="window.open(this.href, '_blank'); return false;" href="http://erlang-china.org/news/erlang-style_concurrency.html">http://erlang-china.org/news/erlang-style_concurrency.html</a><br />译者：jackyz</p>
<p>现下时不时都能看到&#8220;用 language X 来做 Erlang 风格的并行&#8221;这样的博客文章。我想这是好事，这表明大家都开始认真研究有关并行的问题了。</p>
<p>然而，对于&#8220;Erlang 风格的并行&#8221;这一术语，仍然缺乏一个权威的定义。我在这里尝试给出自己的定义。</p>
<p>Joe Armstrong在他的《Programming Erlang》中写了这么一段话：</p>
<div style="border-bottom: rgb(221,221,221) 1px dashed; border-left: rgb(221,221,221) 1px dashed; padding-bottom: 0px; overflow-x: auto; overflow-y: auto; background-color: rgb(247,247,247); margin: 0.4em 0px; padding-left: 1em; padding-right: 1em; font-family: 'Andale Mono', 'Courier New', Courier, monospace; border-top: rgb(221,221,221) 1px dashed; border-right: rgb(221,221,221) 1px dashed; padding-top: 0px" class="code"><pre style="font-family: 'Andale Mono', 'Courier New', Courier, monospace"><code style="font-family: 'Andale Mono', 'Courier New', Courier, monospace">&#8220;在Erlang中：
      进程的创建和销毁非常迅速
      进程之间传递消息非常迅速
      进程的行为独立于操作系统
      进程可以有大规模使用
      进程之间彻底独立不共享内存
      进程之间交互的唯一途径就是消息传递&#8221;</code>
</pre></div>
<p>可以将这看作是一个&#8220;权威定义&#8221;，但稍嫌不够完整。</p>
<p>我想再加上这么几条：</p>
<ul><li>消息传递是异步的</li><li>进程可以彼此监控</li><li>可以选择性的接收消息</li><li>远程进程和本地进程基本保持一致</li></ul>
<p>上面的这些条目概略的描述了 Erlang 中并行的工作方式。那么，对于&#8220;Erlang 风格的并行&#8221;，是否这些条目全都是不可或缺呢？也许并非如此。</p>
<p>我想下面的这些特性都是必须的：</p>
<ul><li>迅速的进程创建和销毁</li><li>不费力的支持至少10K以上的并行进程</li><li>迅速的异步消息传递</li><li>复制的消息传递机制(无共享的并行)</li><li>进程监控</li><li>选择性的消息接收机制</li></ul>
<p>稍作解释：</p>
<h1 style="border-bottom: rgb(170,170,170) 1px dotted; font-family: Georgia, 'Times New Roman', times, serif; color: rgb(68,68,68); font-size: 25px; font-weight: normal" id="toc0"><span>速度和伸缩性</span></h1>
<p>要让并行成为一种具有实用价值的基本建模手段，必须要让程序员能放心的创建解决问题所需的大量进程，而无需担心会因此而影响效率。若要以一句话来概况&#8220;Erlang 风格并行&#8221;的精髓，那就是&#8212;&#8212;<strong>它让你可以按照问题自身内在的并行模式来构建应用。</strong>如果认为创建进程代价高昂，程序员就会尽量重用已有的进程；如果认为消息传递代价高昂，就会发明出其它的技术以避免传递消息。而这些手段通常是有害的(对于并行来说)。</p>
<p>凡事都有自己的局限。Erlang 被设计用来于做&#8220;代理风格&#8221;的并行，而不是大数据量的并行。在 Erlang 中你&#8220;只能&#8221;有约 120M 个并行进程，如果内存足够的话。我本人试过，在 20M 个并发进程时，Erlang 仍然保持一贯的性能(我当时没有更多的内存可以继续尝试)。对于某些极端应用来说，(约5-10微秒)创建一个进程的代价仍嫌昂贵，但相比UNIX进程或 POSIX线程，至少&#8220;廉价&#8221;了几个数量级。&#8220;Erlang 风格的并行&#8221;在进程的粒度上，应与 Erlang 大体保持一致。</p>
<h1 style="border-bottom: rgb(170,170,170) 1px dotted; font-family: Georgia, 'Times New Roman', times, serif; color: rgb(68,68,68); font-size: 25px; font-weight: normal" id="toc1"><span>异步消息传递</span></h1>
<p>对于异步或者同步的消息传递，孰优孰劣曾经有过争论。的确，同步消息传递更易于理解。但在分布式的环境下，异步通讯(也就是所谓的&#8220;发送-祈祷&#8221;)则更符合直觉。基于同步消息传递的系统，在分布式的环境下也必须诉诸于某种形式的异步通讯机制，方可完成任务。尽管仍然存在争议，但无论如何异步消息传递仍是 &#8220;Erlang 风格并行&#8221;的一个特征。</p>
<h1 style="border-bottom: rgb(170,170,170) 1px dotted; font-family: Georgia, 'Times New Roman', times, serif; color: rgb(68,68,68); font-size: 25px; font-weight: normal" id="toc2"><span>复制机制</span></h1>
<p>注意，这里的并不意味着说在所有的情况下都必须要完全复制所有的消息，重点不在方式，而在效果。这很重要，</p>
<p>主要原因如下：</p>
<ul><li>从可靠性角度考虑，进程不能共享内存</li><li>在分布的环境下，复制不可避免，我们尽可能的在本地和远程的消息传递中都保持相同的机制</li></ul>
<p>要求进程之间不能共享任何东西，这可能太过严格，很有可能会将大部分的编程语言都被排除在&#8220;Erlang 风格的并行&#8221;之外(甚至连Scala这样的语言都预留了在进程之间共享数据的可能)。那么好吧，我们至少应该说，Erlang 风格使得用非共享的方式来实现并行要比共享方式更为容易。</p>
<h1 style="border-bottom: rgb(170,170,170) 1px dotted; font-family: Georgia, 'Times New Roman', times, serif; color: rgb(68,68,68); font-size: 25px; font-weight: normal" id="toc3"><span>进程监控</span></h1>
<p>这是&#8220;边界外&#8221;错误处理机制的根基。在 Erlang 中，典型的错误处理哲学是&#8212;&#8212;让它崩溃。其要义就在于，你的程序只处理正常情况，出现异常的情况则交由监控进程来负责处理。这么做的结果是，在大型系统中，能漂亮的实现容错。</p>
<h1 style="border-bottom: rgb(170,170,170) 1px dotted; font-family: Georgia, 'Times New Roman', times, serif; color: rgb(68,68,68); font-size: 25px; font-weight: normal" id="toc4"><span>选择性的消息接收</span></h1>
<p>有N中方法可以实现选择性的消息接收，但对于复杂的多路并行而言，你必须至少要支持其中的一种。在达致并发的路上，这一点很容易被忽视。简单的程序之中，你也不会很明显的感到它的必要，但若当你真正发现它的价值，你很可能已经被&#8220;复杂性爆炸&#8221;折磨很久了。</p>
<p>我建议将选择性的消息接收机制列为 Erlang 风格并发的一个充分条件。它可以通过对单一消息队列进行匹配的方式(Erlang, OSE Delta)来实现，也可以通过多邮箱/频道的方式(Haskell, .Net, UNIX 套接字)来实现。选一个，找个合适的例子，演练它，体验它。如果你愿意，可以参照我的&#8220;<a style="color: rgb(3,3,144)" onclick="window.open(this.href, '_blank'); return false;" href="http://www.erlang.se/euc/05/1500Wiger.ppt">Structured Network Programming</a>&#8221;演示。</p>
<p>&#8212;朴素的分隔线&#8212;</p>
<p>注：跟随<a style="color: rgb(3,3,144)" onclick="window.open(this.href, '_blank'); return false;" href="http://www.google.com/search?q=Erlang-style+concurrency+in">这个链接</a>你会发现&#8220;Erlang-Style Concurrency&#8221;正在迅速变成一个&#8220;即将臭大街&#8221;的名词，也许正是担心这种状况的出现，Ulf Wiger 发表了这篇博客，对于一些声称自己是 Erlang-Style 的 tricky ，划出了一道明确的标准，以正视听。只是后续的发展到底如何，还需继续观察。</p>
<p>译后 blah ：</p>
<p>记得曾在 maillist 见到 Joe Armstrong 说过&#8220;Erlang(语言) 的力量不在语言，Erlang 是很浅显的语言，而是在于语言和虚拟机之间的高度适配&#8221;。spawn一个进程，选择性的从队列中取出一条消息，或者以copy的方式发送一个异步消息，这些都不难做到，基本上哪个语言都能做到；难的部分就在于将这些部分在虚拟机中不断打磨，以&#8220;极廉价的操作&#8221;为目标来高度优化，让其走出珠宝店，进入菜市场，成为编写程序时的一个可选常规工具；我们所使用的工具，它的特性，会反过来影响我们看待问题的方式。当它改变我们对系统建模的思维方式，并形成自己的一套思维模式时，即由此延生出了所谓的 COP 思想。这就是 Erlang 或者说 COP 所走过的路。类似 Scala 或其它以并发为设计目的之一的语言，若想达致 COP 的实用境界，很可能也必须要历经这个痛苦锻造过程的各个阶段。而对于 COP 思想来说，也将会增加一个新的具有实用价值的实践平台。</p></div></span><br class="Apple-interchange-newline" /></div><img src ="http://www.cppblog.com/tx7do/aggbug/163128.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2011-12-29 18:02 <a href="http://www.cppblog.com/tx7do/archive/2011/12/29/163128.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Squid for Windows</title><link>http://www.cppblog.com/tx7do/archive/2011/11/21/160642.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Mon, 21 Nov 2011 07:29:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2011/11/21/160642.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/160642.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2011/11/21/160642.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/160642.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/160642.html</trackback:ping><description><![CDATA[<span style="widows: 2; text-transform: none; background-color: rgb(206,220,203); text-indent: 0px; letter-spacing: normal; font: bold 14px verdana, 宋体; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span">Squid for Windows 简介</span><br /><span style="widows: 2; text-transform: none; background-color: rgb(247,251,244); text-indent: 0px; letter-spacing: normal; font: 14px/21px verdana, 宋体; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span">
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">是大家也许不知道，Squid有一个for Windows的版本，下载地址为:<a style="line-height: 1.5em !important; font-family: Verdana, 宋体; color: rgb(25,77,65); text-decoration: none" href="http://www.acmeconsulting.it/pagine/opensource/squid/SquidNT.htm">http://www.acmeconsulting.it/pagine/opensource/squid/SquidNT.htm</a><br style="line-height: 1.5em !important" />&nbsp;&nbsp;&nbsp; 先来说一下Squid for Windows的安装，需求：你要拥有一台可联网的、运行着Windows NT/2000/XP/Server 2003的计算机，还要有Squid</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">for windows的软件包。从网上下载的Squid for windows的二进制文件是压缩到zip文件里的，首先来解压缩这个文件，加压后会生成一个</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">Squid的文件夹，将此文件夹拷贝到C:\，至此Squid for Windows算是被&#8220;安装&#8221;到你的Windows计算机了。（备注:Squid for windows的默认</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">安装是在C:\squid下，当然，可以把Squid放到其他的路径，但是需要大量的配置squid配置文件中的路径信息，那样会比较麻烦）<br style="line-height: 1.5em !important" />&nbsp;&nbsp;&nbsp; Unix Like的操作系统下的大部分软件都是基于命令行的，使用文本文件进行配置，这样虽说对一些用惯了Windows下软件的朋友们会有些</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">复杂的感觉，但是这样的软件还是有好处的，毕竟其没有Gui会有更高的性能，配置文件的编写更具灵活性，下面我们来看一下具体怎么配置</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">squid for windows。首先，单击[开始]，选择&#8220;运行&#8221;，输入 cmd 打开Windows的&#8220;命令提示符&#8221; 窗口，在命令提示符窗口内输入以下命令:<br style="line-height: 1.5em !important" />C:\&gt;cd c:\squid\etc<br style="line-height: 1.5em !important" />C:\squid\etc&gt;copy squid.conf.default squid.conf&nbsp;&nbsp; **将Squid的默认配置文件复制一份并起名为squid.conf<br style="line-height: 1.5em !important" />C:\squid\etc&gt;copy mime.conf.default mime.conf&nbsp;&nbsp;&nbsp;&nbsp; **将mime.conf.default复制一份并起名为mime.conf</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">下面，我们可以使用任意文本编辑器对squid.conf(配置文件)进行编辑，修改squid的配置语句，文件中的#后的文本表示注释。<br style="line-height: 1.5em !important" />首先，我们找到TAG: acl段，这里是定义访问Squid的IP地址及其对应的名称<br style="line-height: 1.5em !important" />我们在此段acl Safe_ports port 777 #multiling http后增加一个新行，写 &#8220;acl 名称 src IP地址&#8221;</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">示例:acl name1 src 192.168.100.0 #定义所有来自192.168.100.*的机器对应的名称为name1</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">然后我们找到TAG: http_access段，这里是定义允许访问squid的列表<br style="line-height: 1.5em !important" />我们在此段http_access deny CONNECT !SSL_ports后增加一个新行，写&#8220;http_access allow/deny 名称&#8221;，allow表示允许访问，deny表示拒</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">绝访问。</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">示例:http_access allow name1 #定义所有标识为name1(192.168.100.*)的机器允许访问squid代理服务器</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">并且在后面再增加一行 http_access deny all。</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">任何一个网络应用都会对应一个或N个端口，squid的默认端口是3128，如果要更改，找到 #http_port 3128 这里，删掉前面的#号，并且修改</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">后面的端口号。</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">示例:http_port 7777 #将squid的服务端口改为7777</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">由于Squid是基于Cache(缓存)的代理服务器，所以设置缓存的大小对优化服务器的性能是有必要的，下面来看一下如何设置cache的大小。<br style="line-height: 1.5em !important" />找到#cache_mem 8 MB这句 删掉前面的#号 将默认的8修改到需要的大小，这里的数值应视具体的机器可用内存而定，应在内存允许的情况下尽</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">量地设置的大一些以提高代理服务器性能，但不能让代理服务器的缓存大小影响本机器的性能。</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">示例:cache_mem 200 MB #设置squid使用200MB的内存当做代理服务器缓存</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">最后我们还要有一个步骤，否则在启动squid服务的时候会报错，那就是配置TAG: visible_hostname段，找到此段，再后面添加</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">visible_hostname 机器名（随便起） 这么一行，就搞定了。</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">示例:visible_hostname supersrv #将hostname设置为supersrv</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">至此，可以保存squid.conf并且退出文本编辑器了，简单的Squid for Windows的配置已经完成。</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">下面我们回到命令行，输入以下命令：<br style="line-height: 1.5em !important" />c:\&gt;cd c:\squid\sbin<br style="line-height: 1.5em !important" />C:\squid\sbin&gt;squid -i&nbsp;&nbsp;&nbsp; (注册Squid为Windows的服务，默认的服务名为SquidNT，可以使用&#8220;管理工具&#8221;中的&#8220;服务&#8221;来启动／停用服务)<br style="line-height: 1.5em !important" />C:\squid\sbin&gt;squid -z&nbsp;&nbsp;&nbsp; (生成高速缓存的目录)<br style="line-height: 1.5em !important" />C:\squid\sbin&gt;squid&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (启动squid服务，另一种比较好的方法是在&#8220;管理工具&#8221;，&#8220;服务&#8221;中选择SquidNT，然后选择启动服务)</p>
<p style="padding-bottom: 0px; line-height: 21px; margin: 0px 0px 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">&nbsp;&nbsp;&nbsp; 以上简明说明了squid for Windows的安装，配置，启动，此文应用在Unix/Linux下的对Squid的简单配置也是可行的。</p></span><strong>转载自：</strong><a href="http://wxunion.blog.hexun.com/7629100_d.html">http://wxunion.blog.hexun.com/7629100_d.html<br /></a><br /><br /><span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: bold 15px/19px verdana, arial, sans-serif; white-space: normal; orphans: 2; color: rgb(53,94,160); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"><a style="color: rgb(100,100,100); text-decoration: none" id="ctl02_TitleUrl" class="postTitle2" href="http://www.cnblogs.com/daizhj/articles/1605363.html">window server 2003 下安装squid</a></span><br /><span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 12px/19px verdana, Arial, helvetica, sans-seriff; white-space: normal; orphans: 2; color: rgb(75,75,75); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"> 
<p style="text-indent: 0px; margin: 5px auto">安装系统要求：<br /><strong><u>windows server2003 service pack2</u></strong>&nbsp;&nbsp; 注:不能是r2版，否则squid服务启动会出错</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto">1．把squid-2.6.STABLE13-bin.zip解压缩，把里面的squid文件夹拷到c:\下(squid默认的是c:\squid)</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto">2．squid\etc目录下把&nbsp;</p>
<div style="border-bottom: rgb(204,204,204) 1px solid; border-left: rgb(204,204,204) 1px solid; padding-bottom: 5px; overflow-x: auto; overflow-y: auto; background-color: rgb(245,245,245); padding-left: 5px; padding-right: 5px; font-family: 'Courier New'; font-size: 12px; word-break: break-all; border-top: rgb(204,204,204) 1px solid; border-right: rgb(204,204,204) 1px solid; padding-top: 5px" class="cnblogs_code"><span style="line-height: 1.5; font-family: 'Courier New'; color: rgb(0,0,0); font-size: 12px">&nbsp;&nbsp;&nbsp;squid.conf.default拷贝一份重新命名为squid.conf<br />&nbsp;&nbsp;&nbsp;cachemgr.conf.default拷贝一份重新命名为cachemgr.conf<br />&nbsp;&nbsp;&nbsp;mime.conf.default拷贝一份重新命名为mime.conf</span></div>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto">3．用文本编辑器打开squid.conf，需要修改的地方：</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp; 找到#http_port 3128在后面增加一行</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp;<span class="Apple-converted-space">&nbsp;</span><font color="#ff0000">http_port 81 transparent&nbsp;&nbsp; #某些机器上80端口已被占用，所以这里用81&nbsp;&nbsp;&nbsp; 完成配置后可使用netstat -a来查看该端口是否启用</font></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp; 找到#cache_peer 在后面增加一行</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp;<span class="Apple-converted-space">&nbsp;</span><font color="#ff0000">cache_peer 10.0.2.137 parent 7001 0 no-query originserver</font></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp; 找到# TAG: visible_hostname在后面增加一行</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp;<span class="Apple-converted-space">&nbsp;</span><font color="#ff0000">visible_hostname volcano(任意命名)</font></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp; 找到#tag http_access ，然后在#Default：增加一行&nbsp;&nbsp;&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp;<span class="Apple-converted-space">&nbsp;</span><font color="#ff0000">http_access allow all&nbsp;&nbsp; # 允许所有用户访问</font></p>
<p style="text-indent: 0px; margin: 5px auto"><font color="#ff0000"></font>&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto">4．从命令行到c:\squid\sbin目录下执行</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><font color="#ff0000">squid -i</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注：squid -i -n dnt_squid (命名squid服务的新名称)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; squid -r -n dnt_squid (删除指定名称的服务)</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><font color="#ff0000">squid -z</font></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp; &nbsp; &nbsp; 安装完成</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto">5．从服务里启动squid&nbsp;&nbsp; 或在cmd下： net start dnt_squid （启动）, net stop dnt_squid （关闭）</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp; 访问squid服务器:<a style="color: rgb(111,188,76)" href="http://10.0.2.137:81/" target="_blank"></a><a style="color: rgb(111,188,76)" href="http://10.0.2.137:7001/" target="_blank"></a></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp; http://10.0.2.137:81/ (你的squid服务器IP地址)，这时squid会指向 http://10.0.2.137:7001&nbsp; (web服务器地址:即产品dnt的站点地址)</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp; 如果把#http_access deny all打开把http_access allow all注释掉，你的访问就会被拒绝</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp; 相关链接：<a style="color: rgb(111,188,76)" href="http://blog.csdn.net/changesway/archive/2008/10/22/3124919.aspx" target="_blank">http://blog.csdn.net/changesway/archive/2008/10/22/3124919.aspx</a></p>
<p style="text-indent: 0px; margin: 5px auto"><strong></strong>&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto"><strong>其它squid.conf配置</strong>：</p>
<p style="text-indent: 0px; margin: 5px auto"># 主机文件路径<span class="Apple-converted-space">&nbsp;</span><br /><font color="#ff0000">hosts_file c:/windows/system32/drivers/etc/hosts</font>&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto"># 设置日志目录和日志格式<span class="Apple-converted-space">&nbsp;</span><br /><font color="#ff0000">access_log d:/squid/var/logs/access.log squid<span class="Apple-converted-space">&nbsp;</span><br />cache_log d:/squid/var/logs/cache.log<span class="Apple-converted-space">&nbsp;</span><br />cache_store_log d:/squid/var/logs/store.log emulate_httpd_log on</font>&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto"># 缓存管理员<span class="Apple-converted-space">&nbsp;</span><br /><font color="#ff0000">cache_mgr webmaster@example.com</font></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto"># cache目录和大小的设置，1GB硬盘空间和256M内存<span class="Apple-converted-space">&nbsp;</span><br /><font color="#ff0000">cache_dir ufs d:/squid/var/cache 1024 16 256 cache_mem 256 MB</font></p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto"># 设置上级根服务器的地址，当然cache_peer还可以设置兄弟节点、上级cache服务器等等，这里这设置了源服务器地址<span class="Apple-converted-space">&nbsp;</span><br /><font color="#ff0000">cache_peer 电信服务器IP parent 80 0 no-query originserver</font></p></span><strong>转载自：</strong><a href="http://www.cnblogs.com/daizhj/articles/1605363.html">http://www.cnblogs.com/daizhj/articles/1605363.html</a><br /><br /><br /><strong style="color: red">Squid For Windows 官方网站地址：<span style="text-align: left; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 14px/26px Arial; white-space: normal; orphans: 2; color: rgb(51,51,51); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span">http://squid.acmeconsulting.it</span></strong><br /><br /><img src ="http://www.cppblog.com/tx7do/aggbug/160642.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2011-11-21 15:29 <a href="http://www.cppblog.com/tx7do/archive/2011/11/21/160642.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FTP传输Port模式和 Passive模式</title><link>http://www.cppblog.com/tx7do/archive/2011/11/20/160547.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Sun, 20 Nov 2011 03:57:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2011/11/20/160547.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/160547.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2011/11/20/160547.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/160547.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/160547.html</trackback:ping><description><![CDATA[<div><strong style="color: red">转载自：</strong><a style="color: red" href="http://hi.baidu.com/czad_008/blog/item/a923fe7eaf7be13f0dd7da57.html"><strong>http://hi.baidu.com/czad_008/blog/item/a923fe7eaf7be13f0dd7da57.html</strong></a><br /><br /></div>
<p>当你对一个FTP问题进行排错时候，你首先要问的一个问题是使用的是port模式的还是passive模式。因为这两种行为迥异，所以这两种模式引起的问题也不同；在过去，客户端缺省为active(port)模式；近来，由于Port模式的安全问题，许多客户端的FTP应用缺省为Passive模式。</p>
<p>数据传输的连接：<br />&nbsp;&nbsp;&nbsp;&nbsp; port模式是服务器用20端口主动连接客户端的临时端口。<br />&nbsp;&nbsp;&nbsp; Passive模式是客户端用临时分配的端口要要求服务器也分配一个临时端口来回应它。<br />&nbsp;&nbsp;&nbsp; 模式体现在服务器是主动还是被动。</p>
<p>&nbsp;</p>
<p><strong>FTP Port模式</strong></p>
<p>Port模式的FTP步骤如下：<br />1、 客户端发送一个TCP SYN（TCP同步）包给服务器段众所周知的FTP控制端口21，客户端使用暂时的端口作为它的源端口；<br />2、 服务器端发送SYN ACK（同步确认）包给客户端，源端口为21，目的端口为客户端上使用的暂时端口；<br />3、 客户端发送一个ACK（确认）包；客户端使用这个连接来发送FTP命令，服务器端使用这个连接来发送FTP应答；<br />4、 当用户请求一个列表(List)请求或者发起一个要求发送或者接受文件的请求，客户端软件使用PORT命令，这个命令包含了一个暂时的端口，客户端希望服务器在打开一个数据连接时候使用这个暂时端口；PORT命令也包含了一个IP地址，这个IP地址通常是客户自己的IP地址，而且FTP也支持第三方（third-party）模式，第三方模式是客户端告诉服务器端打开与另台主机的连接；<br />5、 服务器端发送一个SYN包给客户端的暂时端口，源端口为20，暂时端口为客户端在PORT命令中发送给服务器端的暂时端口号；<br />6、 客户端以源端口为暂时端口，目的端口为20发送一个SYN ACK包；<br />7、 服务器端发送一个ACK包；<br />8、 发送数据的主机以这个连接来发送数据，数据以TCP段(注：segment，第4层的PDU)形式发送（一些命令，如STOR表示客户端要发送数据，RETR表示服务器段发送数据），这些TCP段都需要对方进行ACK确认（注：因为TCP协议是一个面向连接的协议）<br />9、 当数据传输完成以后，发送数据的主机以一个FIN命令来结束数据连接，这个FIN命令需要另一台主机以ACK确认，另一台主机也发送一个FIN命令，这个FIN命令同样需要发送数据的主机以ACK确认；<br />10、 客户端能在控制连接上发送更多的命令，这可以打开和关闭另外的数据连接；有时候客户端结束后，客户端以FIN命令来关闭一个控制连接，服务器端以ACK包来确认客户端的FIN，服务器同样也发送它的FIN，客户端用ACK来确认。</p>
<p>FTP Port模式会给网络管理人员在许多方面带来很多问题，首先，在PORT命令消息中的IP地址和端口号的编码不是直白地显示。另外，应用层的协议命令理论上不应该包含网络地址信息（注：IP地址），因为这打破了协议层的原则并且可能导致协同性和安全性方面的问题。<br />使用FTP时候，网络中的防火墙必须要声明相应的端口，防火墙必须要跟踪FTP对话然后检查PORT命令，防火墙必须要参与从服务器端到客户端在PORT命令中指定的端口连接的建立过程。<br />如果网络中使用了NAT（注：网络地址翻译），那么NAT的网关同样也需要声明相应的端口，网关需要把在PORT命令中指定的IP地址翻译成分配给客户的地址，然后重新计算TCP的Checksum；如果网关没有正确地执行这个操作，FTP就失败了。</p>
<p><br /><strong>FTP Passive模式</strong></p>
<p>下面的列表描述了Passive模式的FTP的步骤，步骤1到3和Port模式FTP相同，步骤9到11同样与Port模式FTP最后三步相同。<br />1、客户端发送一个TCP SYN（TCP同步）包给服务器段众所周知的FTP控制端口21，客户端使用暂时的端口作为它的源端口；<br />2、服务器端发送SYN ACK（同步确认）包给客户端，源端口为21，目的端口为客户端上使用的暂时端口；<br />3、客户端发送一个ACK（确认）包；客户端使用这个连接来发送FTP命令，服务器端使用这个连接来发送FTP应答；<br />4、当用户请求一个列表(List)或者发送或接收文件时候，客户端软件发送PASV命令给服务器端表明客户端希望进入Passive模式；<br />5、服务器端进行应答，应答包括服务器的IP地址和一个暂时的端口，这个暂时的端口是客户端在打开数据传输连接时应该使用的端口；<br />6、客户端发送一个SYN包，源端口为客户端自己选择的一个暂时端口，目的端口为服务器在PASV应答命令中指定的暂时端口号；<br />7、服务器端发送SYN ACK包给客户端，目的端口为客户端自己选择的暂时端口，源端口为PASV应答中指定的暂时端口号；<br />8、客户端发送一个ACK包；<br />9、发送数据的主机以这个连接来发送数据，数据以TCP段(注：segment，第4层的PDU)形式发送（一些命令，如STOR表示客户端要发送数据，RETR表示服务器段发送数据），这些TCP段都需要对方进行ACK确认；<br />10、当数据传输完成以后，发送数据的主机以一个FIN命令来结束数据连接，这个FIN命令需要另一台主机以ACK确认，另一台主机也发送一个FIN命令，这个FIN命令同样需要发送数据的主机以ACK确认；<br />11、客户端能在控制连接上发送更多的命令，这可以打开和关闭另外的数据连接；有时候客户端结束后，客户端以FIN命令来关闭一个控制连接，服务器端以ACK包来确认客户端的FIN，服务器同样也发送它的FIN，客户端用ACK来确认。</p>
<p>一个PASV请求要求服务器在服务器选择的一个新的端口上接受数据连接，PASV命令没有任何参数，服务器端的回应只是一行显示服务器IP地址和服务器接受连接的TCP端口号。<br /><br /><br /><strong style="color: red">由于PORT模式仅仅是发送端口给服务器，由服务器连回客户端，如果客户端有防火墙，这样的连接会被认为是外部主机试图连接内部的主机， 通常情况下是不允许的。 <br />为了解决这个问题， 引入了PASV模式</strong><br /><br /></p><img src ="http://www.cppblog.com/tx7do/aggbug/160547.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2011-11-20 11:57 <a href="http://www.cppblog.com/tx7do/archive/2011/11/20/160547.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>nchar，char，varchar与nvarchar区别</title><link>http://www.cppblog.com/tx7do/archive/2011/09/14/155754.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Wed, 14 Sep 2011 06:56:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2011/09/14/155754.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/155754.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2011/09/14/155754.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/155754.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/155754.html</trackback:ping><description><![CDATA[<span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 12px Verdana, Arial, Helvetica, sans-serif, 宋体; white-space: normal; orphans: 2; color: rgb(50,52,50); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"> 
<p style="padding-bottom: 8px; line-height: 22px; list-style-type: none; margin: 0px; padding-left: 15px; padding-right: 15px; font-size: 14px; padding-top: 10px"><a href="http://www.builder.com.cn/2007/0730/438663.shtml">http://www.builder.com.cn/2007/0730/438663.shtml</a><br /><br />1、CHAR。<span><font face="Verdana">CHAR存储定长数据很方便，CHAR字段上的索引效率级高，比如定义char(10)，那么不论你存储的数据是否达到了10个字节，都要占去10个字节的空间,不足的自动用空格填充。</font></span></p>
<p style="padding-bottom: 8px; line-height: 22px; list-style-type: none; margin: 0px; padding-left: 15px; padding-right: 15px; font-size: 14px; padding-top: 10px"><span></span><span><font face="Verdana">2、VARCHAR。存储变长数据，但存储效率没有CHAR高。</font><font face="宋体, Simsun">如果一个字段可能的值是不固定长度的，我们只知道它不可能超过10个字符，把它定义为 VARCHAR(10)是最合算的。VARCHAR类型的实际长度是它的值的实际长度+1。为什么&#8220;+1&#8221;呢？这一个字节用于保存实际使用了多大的长度。</font></span><span><font face="宋体">从空间上考虑，用varchar合适；<span>从效率上考虑，用char合适，关键是根据实际情况找到权衡点。</span></font></span></p>
<p style="padding-bottom: 8px; line-height: 22px; list-style-type: none; margin: 0px; padding-left: 15px; padding-right: 15px; font-size: 14px; padding-top: 10px"><span><font face="Verdana">3、TEXT。text存储可变长度的非Unicode数据，最大长度为2^31-1(2,147,483,647)个字符。</font></span></p>
<p style="padding-bottom: 8px; line-height: 22px; list-style-type: none; margin: 0px; padding-left: 15px; padding-right: 15px; font-size: 14px; padding-top: 10px"><span></span><span><font face="Verdana">4、NCHAR、NVARCHAR、NTEXT。这三种从名字上看比前面三种多了个&#8220;N&#8221;。它表示存储的是Unicode数据类型的字符。我们知道字符中，英文字符只需要一个字节存储就足够了，但汉字众多，需要两个字节存储，英文与汉字同时存在时容易造成混乱，Unicode字符集就是为了解决字符集这种不兼容的问题而产生的，它所有的字符都用两个字节表示，即英文字符也是用两个字节表示。nchar、nvarchar的长度是在1到4000之间。和char、varchar比较起来，nchar、nvarchar则最多存储4000个字符，不论是英文还是汉字；而char、varchar最多能存储8000个英文，4000个汉字。可以看出使用nchar、nvarchar数据类型时不用担心输入的字符是英文还是汉字，较为方便，但在存储英文时数量上有些损失。</font></span></span></p><br /><a href="http://www.cnblogs.com/lichang1987/archive/2009/03/04/1403166.html">http://www.cnblogs.com/lichang1987/archive/2009/03/04/1403166.html</a><br /><br /><span style="widows: 2; text-transform: none; text-indent: 0px; letter-spacing: normal; font: 14px/21px verdana; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"> 
<div style="margin: 0px; font: 12px/18px verdana" id="cnblogs_post_body">
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最近在公司里做项目，遇到一个问题，建的数据库里的中文字符和音标显示为乱码，组里的人所有字符都用varchar表示，所以出现上诉问题，当改为Nvarchar后，问题得到解决。所以有必要把他们的区别再重新复习一遍。</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char类型：&nbsp;对英文(ASCII)字符占用1个字节，对一个汉字占用2个字节，CHAR存储定长数据很方便，CHAR字段上的索引效率级高，比如定义char(10)，那么不论你存储的数据是否达到了10个字节，都要占去10个字节的空间。因为是固定长度，所以速度效率高。&nbsp;</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Varchar类型：Varchar 的类型不以空格填满，比如varchar(100)，但它的值只是"qian",则它的值就是"qian"<br />而char 不一样，比如char(100),它的值是"qian"，而实际上它在数据库中是"qian "(qian后共有96个空格，就是把它填满为100个字节)。<span class="Apple-converted-space">&nbsp;</span><br /><br /><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于char是以固定长度的，所以它的速度会比varchar快得多!但程序处理起来要麻烦一点，要用trim之类的函数把两边的空格去掉!</span></p>
<p style="text-indent: 0px; margin: 5px auto"><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="Apple-converted-space">&nbsp;</span></span>VARCHAR存储变长数据，但存储效率没有CHAR高。如果一个字段可能的值是不固定长度的，我们只知道它不可能超过10个字符，把它定义为 VARCHAR(10)是最合算的。VARCHAR类型的实际长度是它的值的实际长度+1。为什么&#8220;+1&#8221;呢？这一个字节用于保存实际使用了多大的长度。</p>
<p style="text-indent: 0px; margin: 5px auto">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Nchar类型和Nvarchar类型是怎么一回事呢？为了与其他多种字符的转换，如中文，音标等，对每个英文(ASCII)字符都占用2个字节，对一个汉字也占用两个字节，所有的字符都占用2个字节。</p>
<p style="text-indent: 0px; margin: 5px auto">例如</p>
<blockquote style="background-image: none; border-bottom: rgb(239,239,239) 2px solid; border-left: rgb(239,239,239) 2px solid; padding-bottom: 5px; margin: 10px 0px 10px 25px; padding-left: 10px; padding-right: 10px; color: rgb(51,51,51); border-top: rgb(239,239,239) 2px solid; border-right: rgb(239,239,239) 2px solid; padding-top: 5px; background-origin: initial; background-clip: initial" dir="ltr">
<p style="text-indent: 0px; margin: 5px auto">varchar(n):变长型字符数据类型，存储最长长度为8,000 个字符。<br /><br />举个例子：<br />insert a select '木子a'<br />--- 存储长度为5个字节，余下的3个字节全部释放<br />insert a select '木神易<br />----存储长度为6个字节，余下的2个字节全部释放<br />---意思是varchar变长字符数据类型与存储数据的实际长度是一致的<br /><br />nvarchar(n):可变长度 Unicode 数据，其最大长度为 4,000 字符。<br />字节的存储大小是所输入字符个数的两倍，<br />就是说它是双字节来存储数据的。<br />如果存储数据如果存在单字节时，它也是以双字节来占用存储<nobr style="border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; color: rgb(102,0,255); text-decoration: underline" target="_blank">空间</nobr>的。</p>
<p style="text-indent: 0px; margin: 5px auto">varchar一般适用于英文和数字，Nvarchar适用中文和其他字符，其中<span style="color: rgb(0,0,0)">N表示Unicode常量，可以解决多语言字符集之间的转换问题</span></p></blockquote></div>
<div style="margin: 20px 0px 0px; font: 12px/18px verdana" id="blog_post_info_block"></span><br class="Apple-interchange-newline" /></div><img src ="http://www.cppblog.com/tx7do/aggbug/155754.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2011-09-14 14:56 <a href="http://www.cppblog.com/tx7do/archive/2011/09/14/155754.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MS SQL SERVER 主从数据库的实现</title><link>http://www.cppblog.com/tx7do/archive/2011/08/12/153155.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 12 Aug 2011 02:55:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2011/08/12/153155.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/153155.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2011/08/12/153155.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/153155.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/153155.html</trackback:ping><description><![CDATA[<div><strong style="color: red">转载自：</strong><a style="color: red" href="http://blog.csdn.net/zhouliang0806/article/details/6284266"><strong>http://blog.csdn.net/zhouliang0806/article/details/6284266</strong></a><br /><br /><span style="text-align: left; widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 14px/26px Arial; white-space: normal; orphans: 2; color: rgb(51,51,51); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"> 
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;<span style="text-decoration: underline"><span class="Apple-converted-space">&nbsp;</span><strong>主从库是两台服务器上的两个数据库，主库以最快的速度做增删改操作+最新数据的查询操作;从库负责查询较旧数据，做一些对实效性要求较小的分析，报表生成的工作。这样做将数据库的压力分担到两台服务器上从而保证整个系统响应的及时性。</strong></span></span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SQL Server提供了复制机制来帮我们实现主从库的机制。</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp; 实践前需要新创建一个Test的数据库，这个库中建一个测试表。</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp; 1. 打开sql server企业管理器，在对象资源管理器里面选择复制-&gt;本地发布，右键选择新建发布；</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. 打开新建发布向导，点下一步，选择发布数据的数据库；</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp; 3. 我们选择Test数据库，并点击下一步，选择发布类型；</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注：&nbsp;这里我们选择的是事务性发布，事务性发布保证数据在做更新之后尽可能快的分发到订阅服务器上。有关其他几种发布类型的使用场景请参考msdn</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp; 4. 点击下一步，选择要发布的对象，这里我们只对表进行发布；</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp; 5.点击下一步进入筛选数据设置，这里我们要复制表的所有数据所以不做设置；</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6. 点击下一步，指定何时运行快照，我们选择初始话数据，并选择默认的运行快照频率；</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp; 7. 继续下一步，设置快照代理的运行账户，我们选择sql server agent账户；</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8. 点击下一步选择创建发布，再次点击下一步设置发布的名称；</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp; 9. 点击完成，完成发布的设置，并创建发布，现在在本地发布出新添加了我们创建的发布。</span></p>
<p>&nbsp;</p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在成功创建了发布，我们还需要创建订阅：在本地订阅文件夹上右击新建订阅，通过向导可以很容易的创建订阅，创建订阅时可以选择以发布者推送或者订阅者主动的方式创建。具体步骤如下：</span></p>
<p><span style="font-size: small">　　1. 通过右键菜单打开新建订阅，点击下一步，选择我们刚刚创建的发布作为订阅源；</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. 选择是以推送还是以主动请求的方式同步数据，我们选择主动订阅；</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. 设置执行分发代理的账户；</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4. 设置代理请求同步的频率；</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5. 设定是否立即做数据的初始化操作</span></p>
<p><span style="font-size: small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6. 完成创建订阅</span></p>
<p>&nbsp;</p>
<p><span style="font-size: small">　　创建完成之后，我们可以通过在主库表中插入n条数据，然后在从库中查询的方式验证复制是否成功。</span></p>
<p><span style="font-size: small">　　在Sql server2005中的复制创建起来很简单，我们需要根据业务需要设定复制的类型和同步的频率。</span></p></span></div><img src ="http://www.cppblog.com/tx7do/aggbug/153155.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2011-08-12 10:55 <a href="http://www.cppblog.com/tx7do/archive/2011/08/12/153155.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最简单的TCP网络封包解包(补充)-序列化</title><link>http://www.cppblog.com/tx7do/archive/2011/05/07/145865.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 06 May 2011 17:33:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2011/05/07/145865.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/145865.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2011/05/07/145865.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/145865.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/145865.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 如若描述或者代码当中有谬误之处，还望指正。将数据能够在TCP中进行传输的两种方法1.直接拷贝struct就可以了；2.序列化。拷贝Struct存在的问题1.不能应付可变长类型的数据，比如STL中的那些容器，他们的长度都是不确定的。当然，STL的容器归根到底就是一个class；2.内存对齐的问题，Windows默认的对齐是4字节，如果不去刻意关闭掉对齐的话，那么可能会多出不少没必要的字节数，有时候，...&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/archive/2011/05/07/145865.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/145865.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2011-05-07 01:33 <a href="http://www.cppblog.com/tx7do/archive/2011/05/07/145865.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux 下定时器的实现方式分析</title><link>http://www.cppblog.com/tx7do/archive/2011/05/05/145718.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Thu, 05 May 2011 02:25:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2011/05/05/145718.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/145718.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2011/05/05/145718.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/145718.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/145718.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转载自：https://www.ibm.com/developerworks/cn/linux/l-cn-timers/概论定时器属于基本的基础组件，不管是用户空间的程序开发，还是内核空间的程序开发，很多时候都需要有定时器作为基础组件的支持，但使用场景的不同，对定时器的实现考虑也不尽相同，本文讨论了在 Linux 环境下，应用层和内核层的定时器的各种实现方法，并分析了各种实现方法的利弊以及...&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/archive/2011/05/05/145718.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/145718.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2011-05-05 10:25 <a href="http://www.cppblog.com/tx7do/archive/2011/05/05/145718.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Socket的阻塞模式和非阻塞模式</title><link>http://www.cppblog.com/tx7do/archive/2010/06/11/117609.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Thu, 10 Jun 2010 17:02:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2010/06/11/117609.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/117609.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2010/06/11/117609.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/117609.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/117609.html</trackback:ping><description><![CDATA[<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: rgb(0,0,0); WORD-SPACING: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class=Apple-style-span><span style="TEXT-ALIGN: left; LINE-HEIGHT: 18px; FONT-FAMILY: verdana, sans-serif; FONT-SIZE: 12px" class=Apple-style-span><span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: rgb(0,0,0); WORD-SPACING: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class=Apple-style-span><strong>来源:</strong><a href="http://blog.csdn.net/VCSockets/"><strong>http://blog.csdn.net/VCSockets/</strong></a><br><br><br><br><strong>阻塞模式</strong><br>
<p>　　Windows套接字在阻塞和非阻塞两种模式下执行I/O操作。在阻塞模式下，在I/O操作完成前，执行的操作函数一直等候而不会立即返回，该函数所在的线程会阻塞在这里。相反，在非阻塞模式下，套接字函数会立即返回，而不管I/O是否完成，该函数所在的线程会继续运行。</p>
<p>在阻塞模式的套接字上，调用任何一个Windows Sockets API都会耗费不确定的等待时间。图所示，在调用recv()函数时，发生在内核中等待数据和复制数据的过程。</p>
<p>当调用recv()函数时，系统首先查是否有准备好的数据。如果数据没有准备好，那么系统就处于等待状态。当数据准备好后，将数据从系统缓冲区复制到用户空间，然后该函数返回。在套接应用程序中，当调用recv()函数时，未必用户空间就已经存在数据，那么此时recv()函数就会处于等待状态。</p>
<img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/tx7do/Socket_Block.jpg" width=402 height=394><br>&nbsp;&nbsp;&nbsp; Windows套接字程序使用&#8220;生产者-消费者&#8221;模式来解决上述问题。在程序中，&#8220;生产者&#8221;读入数据，&#8220;消费者&#8221;根据需求对读入数据进行处理。通常&#8220;生产者&#8221;和&#8220;消费者&#8221;存在于两个线程中，当&#8220;生产者&#8221;完成读入数据时，使用线程同步机制，例如设置一个事件通知&#8220;消费者&#8221;，&#8220;消费者&#8221;接收到这个事件后对读入的数据进行处理。<br>
<p>　　当使用socket()函数和WSASocket()函数创建套接字时，默认的套接字都是阻塞的。这意味着当调用Windows Sockets API不能立即完成时，线程处于等待状态，直到操作完成。</p>
<p>并不是所有Windows Sockets API以阻塞套接字为参数调用都会发生阻塞。例如，以阻塞模式的套接字为参数调用bind()、listen()函数时，函数会立即返回。将可能阻塞套接字的Windows Sockets API调用分为以下四种:</p>
<p>1．输入操作</p>
<p>recv()、recvfrom()、WSARecv()和WSARecvfrom()函数。以阻塞套接字为参数调用该函数接收数据。如果此时套接字缓冲区内没有数据可读，则调用线程在数据到来前一直睡眠。</p>
<p>2．输出操作</p>
<p>send()、sendto()、WSASend()和WSASendto()函数。以阻塞套接字为参数调用该函数发送数据。如果套接字缓冲区没有可用空间，线程会一直睡眠，直到有空间。</p>
<p>3．接受连接</p>
<p>accept()和WSAAcept()函数。以阻塞套接字为参数调用该函数，等待接受对方的连接请求。如果此时没有连接请求，线程就会进入睡眠状态。</p>
<p>4．外出连接</p>
<p>connect()和WSAConnect()函数。对于TCP连接，客户端以阻塞套接字为参数，调用该函数向服务器发起连接。该函数在收到服务器的应答前，不会返回。这意味着TCP连接总会等待至少到服务器的一次往返时间。</p>
<p>　　使用阻塞模式的套接字，开发网络程序比较简单，容易实现。当希望能够立即发送和接收数据，且处理的套接字数量比较少的情况下，使用阻塞模式来开发网络程序比较合适。</p>
<p>阻塞模式套接字的不足表现为，在大量建立好的套接字线程之间进行通信时比较困难。当使用&#8220;生产者-消费者&#8221;模型开发网络程序时，为每个套接字都分别分配一个读线程、一个处理数据线程和一个用于同步的事件，那么这样无疑加大系统的开销。其最大的缺点是当希望同时处理大量套接字时，将无从下手，其扩展性很差。</p>
<br><br><br><br><strong>非阻塞模式</strong><br>&nbsp; 把套接字设置为非阻塞模式，即通知系统内核：在调用Windows Sockets API时，不要让线程睡眠，而应该让函数立即返回。在返回时，该函数返回一个错误代码。图所示，一个非阻塞模式套接字多次调用recv()函数的过程。前三次调用recv()函数时，内核数据还没有准备好。因此，该函数立即返回WSAEWOULDBLOCK错误代码。第四次调用recv()函数时，数据已经准备好，被复制到应用程序的缓冲区中，recv()函数返回成功指示，应用程序开始处理数据。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/tx7do/Socket_UnBlock.jpg" width=404 height=388><br>　　当使用socket()函数和WSASocket()函数创建套接字时，默认都是阻塞的。在创建套接字之后，通过调用ioctlsocket()函数，将该套接字设置为非阻塞模式。Linux下的函数是:fcntl().<br>&nbsp;&nbsp;&nbsp; 套接字设置为非阻塞模式后，在调用Windows Sockets API函数时，调用函数会立即返回。大多数情况下，这些函数调用都会调用&#8220;失败&#8221;，并返回WSAEWOULDBLOCK错误代码。说明请求的操作在调用期间内没有时间完成。通常，应用程序需要重复调用该函数，直到获得成功返回代码。<br>
<p>&nbsp;&nbsp;&nbsp; 需要说明的是并非所有的Windows Sockets API在非阻塞模式下调用，都会返回WSAEWOULDBLOCK错误。例如，以非阻塞模式的套接字为参数调用bind()函数时，就不会返回该错误代码。当然，在调用WSAStartup()函数时更不会返回该错误代码，因为该函数是应用程序第一调用的函数，当然不会返回这样的错误代码。</p>
<p>&nbsp;&nbsp;&nbsp; 要将套接字设置为非阻塞模式，除了使用ioctlsocket()函数之外，还可以使用WSAAsyncselect()和WSAEventselect()函数。当调用该函数时，套接字会自动地设置为非阻塞方式。<br></p>
<p>　　由于使用非阻塞套接字在调用函数时，会经常返回WSAEWOULDBLOCK错误。所以在任何时候，都应仔细检查返回代码并作好对&#8220;失败&#8221;的准备。应用程序连续不断地调用这个函数，直到它返回成功指示为止。上面的程序清单中，在While循环体内不断地调用recv()函数，以读入1024个字节的数据。这种做法很浪费系统资源。</p>
<p>&nbsp;&nbsp;&nbsp; 要完成这样的操作，有人使用MSG_PEEK标志调用recv()函数查看缓冲区中是否有数据可读。同样，这种方法也不好。因为该做法对系统造成的开销是很大的，并且应用程序至少要调用recv()函数两次，才能实际地读入数据。较好的做法是，使用套接字的&#8220;I/O模型&#8221;来判断非阻塞套接字是否可读可写。</p>
<p>&nbsp;&nbsp;&nbsp; 非阻塞模式套接字与阻塞模式套接字相比，不容易使用。使用非阻塞模式套接字，需要编写更多的代码，以便在每个Windows Sockets API函数调用中，对收到的WSAEWOULDBLOCK错误进行处理。因此，非阻塞套接字便显得有些难于使用。</p>
<p>&nbsp;&nbsp;&nbsp; 但是，非阻塞套接字在控制建立的多个连接，在数据的收发量不均，时间不定时，明显具有优势。这种套接字在使用上存在一定难度，但只要排除了这些困难，它在功能上还是非常强大的。通常情况下，可考虑使用套接字的&#8220;I/O模型&#8221;，它有助于应用程序通过异步方式，同时对一个或多个套接字的通信加以管理。</span></span></span></p>
<img src ="http://www.cppblog.com/tx7do/aggbug/117609.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2010-06-11 01:02 <a href="http://www.cppblog.com/tx7do/archive/2010/06/11/117609.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows 下的最简单的TCP服务器客户端</title><link>http://www.cppblog.com/tx7do/archive/2010/06/10/117591.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Thu, 10 Jun 2010 13:57:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2010/06/10/117591.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/117591.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2010/06/10/117591.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/117591.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/117591.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 他们是短连接的,服务器接受客户端之后,马上发送一个消息,发送完以后立即将客户端断开掉,然后继续等待下一个连接.使用Winsocket2必须要引用到的头文件和需要包含到的链接库文件:#include&nbsp;&lt;WinSock2.h&gt;#pragma&nbsp;comment(&nbsp;lib,&nbsp;"ws2_32.lib"&nbsp;)以下代码是Winsocket2的系统...&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/archive/2010/06/10/117591.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/117591.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2010-06-10 21:57 <a href="http://www.cppblog.com/tx7do/archive/2010/06/10/117591.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>AIX上的aio(转贴) </title><link>http://www.cppblog.com/tx7do/archive/2006/07/07/9530.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 07 Jul 2006 04:04:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2006/07/07/9530.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/9530.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2006/07/07/9530.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/9530.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/9530.html</trackback:ping><description><![CDATA[
		<p>
				<a href="http://www.loveunix.net/discuz/viewthread.php?tid=51746&amp;extra=page%3D1">
						<font color="#000080">http://www.loveunix.net/discuz/viewthread.php?tid=51746&amp;extra=page%3D1</font>
				</a>
				<br />
		</p>
		<p>
		</p>
		<table style="TABLE-LAYOUT: fixed; WORD-WRAP: break-word" height="100%" cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td valign="top">
										<span style="FONT-SIZE: 13px">
												<b>Asynchronous I/O Subsystem</b>
												<br />
												<br />Synchronous I/O occurs while you wait. Applications processing cannot continue until the I/O operation is complete.<br /><br />In contrast, asynchronous I/O operations run in the background and do not block user applications. This improves performance, because I/O operations and applications processing can run simultaneously.<br /><br />Using asynchronous I/O will usually improve your I/O throughput, especially when you are storing data in raw logical volumes (as opposed to Journaled file systems). The actual performance, however, depends on how many server processes are running that will handle the I/O requests.<br /><br />Many applications, such as databases and file servers, take advantage of the ability to overlap processing and I/O. These asynchronous I/O operations use various kinds of devices and files. Additionally, multiple asynchronous I/O operations can run at the same time on one or more devices or files.<br /><br />Each asynchronous I/O request has a corresponding control block in the application's address space. When an asynchronous I/O request is made, a handle is established in the control block. This handle is used to retrieve the status and the return values of the request.<br /><br />Applications use the aio_read and aio_write subroutines to perform the I/O. Control returns to the application from the subroutine, as soon as the request has been queued. The application can then continue processing while the disk operation is being performed.<br /><br />A kernel process (kproc), called a server, is in charge of each request from the time it is taken off the queue until it completes. The number of servers limits the number of disk I/O operations that can be in progress in the system simultaneously.<br /><br />The default values are minservers=1 and maxservers=10. In systems that seldom run applications that use asynchronous I/O, this is usually adequate. For environments with many disk drives and key applications that use asynchronous I/O, the default is far too low. The result of a deficiency of servers is that disk I/O seems much slower than it should be. Not only do requests spend inordinate lengths of time in the queue, but the low ratio of servers to disk drives means that the seek-optimization algorithms have too few requests to work with for each drive.<br /><br /><b>Note:</b><br />Asynchronous I/O will not work if the control block or buffer is created using mmap (mapping segments).<br /><br />In AIX 5.2 there are two Asynchronous I/O Subsystems. The original AIX AIO, now called LEGACY AIO, has the same function names as the posix compliant POSIX AIO. The major differences between the two involve different parameter passing. Both subsytems are defined in the /usr/include/sys/aio.h file. The _AIO_AIX_SOURCE macro is used to distinguish between the two versions.<br /><br /><b>Note:</b><br />The _AIO_AIX_SOURCE macro used in the /usr/include/sys/aio.h file must be defined when using this file to compile an aio application with the LEGACY AIO function definitions. The default compile using the aio.h file is for an application with the new POSIX AIO definitions. To use the LEGACY AIO function defintions do the following in the source file: <br />#define _AIO_AIX_SOURCE <br />#include &lt;sys/aio.h&gt;<br />or when compiling on the command line, type the following: <br />xlc ... -D_AIO_AIX_SOURCE ... classic_aio_program.c<br /><br />For each aio function there is a legacy and a posix definition. LEGACY AIO has an additional aio_nwait function, which although not a part of posix definitions has been included in POSIX AIO to help those who want to port from LEGACY to POSIX definitions. POSIX AIO has an additional aio_fsync function, which is not included in LEGACY AIO. For a list of these functions, see Asynchronous I/O Subroutines.<br /><br /><b>How Do I Know if I Need to Use AIO?</b><br /><br />Using the vmstat command with an interval and count value, you can determine if the CPU is idle waiting for disk I/O. The wa column details the percentage of time the CPU was idle with pending local disk I/O.<br /><br />If there is at least one outstanding I/O to a local disk when the wait process is running, the time is classified as waiting for I/O. Unless asynchronous I/O is being used by the process, an I/O request to disk causes the calling process to block (or sleep) until the request has been completed. Once a process's I/O request completes, it is placed on the run queue.<br /><br />A wa value consistently over 25 percent may indicate that the disk subsystem is not balanced properly, or it may be the result of a disk-intensive workload.<br /><br /><b>Note:</b><br />AIO will not relieve an overly busy disk drive. Using the iostat command with an interval and count value, you can determine if any disks are overly busy. Monitor the %tm_act column for each disk drive on the system. On some systems, a %tm_act of 35.0 or higher for one disk can cause noticeably slower performance. The relief for this case could be to move data from more busy to less busy disks, but simply having AIO will not relieve an overly busy disk problem.<br /><br /><b>SMP Systems</b><br />For SMP systems, the us, sy, id and wa columns are only averages over all processors. But keep in mind that the I/O wait statistic per processor is not really a processor-specific statistic; it is a global statistic. An I/O wait is distinguished from idle time only by the state of a pending I/O. If there is any pending disk I/O, and the processor is not busy, then it is an I/O wait time. Disk I/O is not tracked by processors, so when there is any I/O wait, all processors get charged (assuming they are all equally idle).<br /><br /><b>How Many AIO Servers Am I Currently Using?</b><br />To determine you how many Posix AIO Servers (aios) are currently running, type the following on the command line:<br />pstat -a | grep posix_aioserver | wc -l <br /><br /><b>Note:</b><br />You must run this command as the root user.<br />To determine you how many Legacy AIO Servers (aios) are currently running, type the following on the command line:<br />pstat -a | egrep ' aioserver' | wc -l  <br />Note:<br />You must run this command as the root user.<br />If the disk drives that are being accessed asynchronously are using either the Journaled File System (JFS) or the Enhanced Journaled File System (JFS2), all I/O will be routed through the aios kprocs.<br />If the disk drives that are being accessed asynchronously are using a form of raw logical volume management, then the disk I/O is not routed through the aios kprocs. In that case the number of servers running is not relevant.<br /><br />However, if you want to confirm that an application that uses raw logic volumes is taking advantage of AIO, you can disable the fast path option via SMIT. When this option is disabled, even raw I/O will be forced through the aios kprocs. At that point, the pstat command listed in preceding discussion will work. You would not want to run the system with this option disabled for any length of time. This is simply a suggestion to confirm that the application is working with AIO and raw logical volumes.<br />At releases earlier than AIX 4.3, the fast path is enabled by default and cannot be disabled.<br />How Many AIO Servers Do I Need?<br />Here are some suggested rules of thumb for determining what value to set maximum number of servers to:<br />1.        The first rule of thumb suggests that you limit the maximum number of servers to a number equal to ten times the number of disks that are to be used concurrently, but not more than 80. The minimum number of servers should be set to half of this maximum number. <br />2.        Another rule of thumb is to set the maximum number of servers to 80 and leave the minimum number of servers set to the default of 1 and reboot. Monitor the number of additional servers started throughout the course of normal workload. After a 24-hour period of normal activity, set the maximum number of servers to the number of currently running aios + 10, and set the minimum number of servers to the number of currently running aios - 10. <br />In some environments you may see more than 80 aios KPROCs running. If so, consider the third rule of thumb.<br />3.        A third suggestion is to take statistics using vmstat -s before any high I/O activity begins, and again at the end. Check the field iodone. From this you can determine how many physical I/Os are being handled in a given wall clock period. Then increase the maximum number of servers and see if you can get more iodones in the same time period.<br />Prerequisites<br />To make use of asynchronous I/O the following fileset must be installed:<br />bos.rte.aio<br />To determine if this fileset is installed, use:<br />lslpp -l bos.rte.aio<br />You must also make the aio0 or posix_aio0 device available using SMIT.<br />smit chgaio<br />smit chgposixaio<br /><br />STATE to be configured at system restart available<br />or<br />smit aio<br />smit posixaio<br /><br />Configure aio now<br />Functions of Asynchronous I/O<br />Functions provided by the asynchronous I/O facilities are:<br />•        Large File-Enabled Asynchronous I/O <br />•        Nonblocking I/O <br />•        Notification of I/O completion <br />•        Cancellation of I/O requests<br />Large File-Enabled Asynchronous I/O<br />The fundamental data structure associated with all asynchronous I/O operations is struct aiocb. Within this structure is the aio_offset field which is used to specify the offset for an I/O operation.<br />Due to the signed 32-bit definition of aio_offset, the default asynchronous I/O interfaces are limited to an offset of 2G minus 1. To overcome this limitation, a new aio control block with a signed 64-bit offset field and a new set of asynchronous I/O interfaces has been defined. These 64–bit definitions end with "64".<br />The large offset-enabled asynchronous I/O interfaces are available under the _LARGE_FILES compilation environment and under the _LARGE_FILE_API programming environment. For further information, see Writing Programs That Access Large Files in AIX 5L Version 5.3 General Programming Concepts: Writing and Debugging Programs.<br />Under the _LARGE_FILES compilation environment, asynchronous I/O applications written to the default interfaces see the following redefinitions:<br />Item        Redefined To Be        Header File<br />struct aiocb        struct aiocb64        sys/aio.h<br />aio_read()        aio_read64()        sys/aio.h<br />aio_write()        aio_write64()        sys/aio.h<br />aio_cancel()        aio_cancel64()        sys/aio.h<br />aio_suspend()        aio_suspend64()        sys/aio.h<br />aio_listio()        aio_listio64()        sys/aio.h<br />aio_return()        aio_return64()        sys/aio.h<br />aio_error()        aio_error64()        sys/aio.h<br />For information on using the _LARGE_FILES environment, see Porting Applications to the Large File Environment in AIX 5L Version 5.3 General Programming Concepts: Writing and Debugging Programs<br />In the _LARGE_FILE_API environment, the 64-bit API interfaces are visible. This environment requires recoding of applications to the new 64-bit API name. For further information on using the _LARGE_FILE_API environment, see Using the 64-Bit File System Subroutines in AIX 5L Version 5.3 General Programming Concepts: Writing and Debugging Programs<br />Nonblocking I/O<br />After issuing an I/O request, the user application can proceed without being blocked while the I/O operation is in progress. The I/O operation occurs while the application is running. Specifically, when the application issues an I/O request, the request is queued. The application can then resume running before the I/O operation is initiated.<br />To manage asynchronous I/O, each asynchronous I/O request has a corresponding control block in the application's address space. This control block contains the control and status information for the request. It can be used again when the I/O operation is completed.<br />Notification of I/O Completion<br />After issuing an asynchronous I/O request, the user application can determine when and how the I/O operation is completed. This information is provided in three ways:<br />•        The application can poll the status of the I/O operation. <br />•        The system can asynchronously notify the application when the I/O operation is done. <br />•        The application can block until the I/O operation is complete.<br />Polling the Status of the I/O Operation<br />The application can periodically poll the status of the I/O operation. The status of each I/O operation is provided in the application's address space in the control block associated with each request. Portable applications can retrieve the status by using the aio_error subroutine.The aio_suspend subroutine suspends the calling process until one or more asynchronous I/O requests are completed.<br />Asynchronously Notifying the Application When the I/O Operation Completes<br />Asynchronously notifying the I/O completion is done by signals. Specifically, an application may request that a SIGIO signal be delivered when the I/O operation is complete. To do this, the application sets a flag in the control block at the time it issues the I/O request. If several requests have been issued, the application can poll the status of the requests to determine which have actually completed.<br />Blocking the Application until the I/O Operation Is Complete<br />The third way to determine whether an I/O operation is complete is to let the calling process become blocked and wait until at least one of the I/O requests it is waiting for is complete. This is similar to synchronous style I/O. It is useful for applications that, after performing some processing, need to wait for I/O completion before proceeding.<br />Cancellation of I/O Requests<br />I/O requests can be canceled if they are cancelable. Cancellation is not guaranteed and may succeed or not depending upon the state of the individual request. If a request is in the queue and the I/O operations have not yet started, the request is cancellable. Typically, a request is no longer cancelable when the actual I/O operation has begun.<br />Asynchronous I/O Subroutines<br /><b>Note:</b>The 64-bit APIs are as follows:<br />The following subroutines are provided for performing asynchronous I/O:<br />Subroutine        Purpose<br />aio_cancel or aio_cancel64<br />Cancels one or more outstanding asynchronous I/O requests.<br />aio_error or aio_error64<br />Retrieves the error status of an asynchronous I/O request.<br />aio_fsync<br />Synchronizes asynchronous files.<br />lio_listio or lio_listio64<br />Initiates a list of asynchronous I/O requests with a single call.<br />aio_nwait<br />Suspends the calling process until n asynchronous I/O requests are completed.<br />aio_read or aio_read64<br />Reads asynchronously from a file.<br />aio_return or aio_return64<br />Retrieves the return status of an asynchronous I/O request.<br />aio_suspend or aio_suspend64<br />Suspends the calling process until one or more asynchronous I/O requests is completed.<br />aio_write or aio_write64<br />Writes asynchronously to a file.<br />Order and Priority of Asynchronous I/O Calls<br /><br />An application may issue several asynchronous I/O requests on the same file or device. However, because the I/O operations are performed asynchronously, the order in which they are handled may not be the order in which the I/O calls were made. The application must enforce ordering of its own I/O requests if ordering is required.<br /><br />Priority among the I/O requests is not currently implemented. The aio_reqprio field in the control block is currently ignored.<br /><br />For files that support seek operations, seeking is allowed as part of the asynchronous read or write operations. The whence and offset fields are provided in the control block of the request to set the seek parameters. The seek pointer is updated when the asynchronous read or write call returns.<br />Subroutines Affected by Asynchronous I/O<br /><br />The following existing subroutines are affected by asynchronous I/O:<br />•        The close subroutine <br />•        The exit subroutine <br />•        The exec subroutine <br />•        The fork subroutine<br /><br />If the application closes a file, or calls the _exit or exec subroutines while it has some outstanding I/O requests, the requests are canceled. If they cannot be canceled, the application is blocked until the requests have completed. When a process calls the fork subroutine, its asynchronous I/O is not inherited by the child process.<br /><br />One fundamental limitation in asynchronous I/O is page hiding. When an unbuffered (raw) asynchronous I/O is issued, the page that contains the user buffer is hidden during the actual I/O operation. This ensures cache consistency. However, the application may access the memory locations that fall within the same page as the user buffer. This may cause the application to block as a result of a page fault. To alleviate this, allocate page aligned buffers and do not touch the buffers until the I/O request using it has completed.<br /><br /><b>Changing Attributes for Asynchronous I/O</b><br />You can change attributes relating to asynchronous I/O using the chdev command or SMIT. Likewise, you can use SMIT to configure and remove (unconfigure) asynchronous I/O. (Alternatively, you can use the mkdev and rmdev commands to configure and remove asynchronous I/O). To start SMIT at the main menu for asynchronous I/O, enter smit aio or smit posixaio.<br /><br /><b>MINIMUM number of servers </b><br />Indicates the minimum number of kernel processes dedicated to asynchronous I/O processing. Because each kernel process uses memory, this number should not be large when the amount of asynchronous I/O expected is small. <br /><br /><b>MAXIMUM number of servers per cpu </b><br />Indicates the maximum number of kernel processes per cpu that are dedicated to asynchronous I/O processing. This number when multiplied by the number of cpus indicates the limit on I/O requests in progress at one time, and represents the limit for possible I/O concurrency. <br /><br /><b>Maximum number of REQUESTS </b><br />Indicates the maximum number of asynchronous I/O requests that can be outstanding at one time. This includes requests that are in progress as well as those that are waiting to be started. The maximum number of asynchronous I/O requests cannot be less than the value of AIO_MAX, as defined in the /usr/include/sys/limits.h file, but it can be greater. It would be appropriate for a system with a high volume of asynchronous I/O to have a maximum number of asynchronous I/O requests larger than AIO_MAX. <br /><br /><b>Server PRIORITY </b><br />Indicates the priority level of kernel processes dedicated to asynchronous I/O. The lower the priority number is, the more favored the process is in scheduling. Concurrency is enhanced by making this number slightly less than the value of PUSER, the priority of a normal user process. It cannot be made lower than the values of PRI_SCHED. <br />Because the default priority is (40+nice), these daemons will be slightly favored with this value of (39+nice). If you want to favor them more, make changes slowly. A very low priority can interfere with the system process that require low priority.<br />Attention: Raising the server PRIORITY (decreasing this numeric value) is not recommended because system hangs or crashes could occur if the priority of the AIO servers is favored too much. There is little to be gained by making big priority changes.<br />PUSER and PRI_SCHED are defined in the /usr/include/sys/pri.h file.<br /><br /><b>STATE to be configured at system restart </b><br />Indicates the state to which asynchronous I/O is to be configured during system initialization. The possible values are: <br />•        defined, which indicates that the asynchronous I/O will be left in the defined state and not available for use <br />•        available, which indicates that asynchronous I/O will be configured and available for use<br /><br /><b>STATE of FastPath </b><br />The AIO Fastpath is used only on character devices (raw logical volumes) and sends I/O requests directly to the underlying device. The file system path used on block devices uses the aio kprocs to send requests through file system routines provided to kernel extensions. Disabling this option forces all I/O activity through the aios kprocs, including I/O activity that involves raw logical volumes. In AIX 4.3 and earlier, the fast path is enabled by default and cannot be disabled. <br /><br /><b>64-bit Enhancements</b><br />Asynchronous I/O (AIO) has been enhanced to support 64-bit enabled applications. On 64-bit platforms, both 32-bit and 64-bit AIO can occur simultaneously.<br />The struct aiocb, the fundamental data structure associated with all asynchronous I/O operation, has changed. The element of this struct, aio_return, is now defined as ssize_t. Previously, it was defined as an int. AIO supports large files by default. An application compiled in 64-bit mode can do AIO to a large file without any additional #define or special opening of those files.</span>
										<br />
										<br />
										<br />
								</td>
						</tr>
						<tr>
								<td style="HEIGHT: 20em" valign="bottom">
										<img src="http://www.loveunix.net/discuz/images/common/sigline.gif" />
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<span style="FONT-SIZE: 13px">看来很久之前的以讹传讹是在是影响太厉害了。<br />1、aio server不是进程，是kernel threading，所以效率才高，要不不如用用户态的thread或者processor实现AIO算了。<br />2  and 3 显然find使用的syscall是read而不是aio_read，所以只能用阻塞IO，就算你配置了AIO ENABLE也不可能出现你说的3的情况。<br />4、最大的以讹传讹，AIO可以用于RAW DEVICE，而且效果更好。因为大多数的UNIX的AIO实现是这样的，如果对RAW DEVICE用aio_read aio_write是，是用kernel threading，效率最高；但是对于FS，只能用lwp 或者thread模拟，效率低很多。所以在使用INFORMIX DB2等等DBMS的时候，要充分发挥aio的效果，应该用raw device做数据容器。<br />5、再次强调，aio server是kernel threading，和用户自己创建的thread或者process都不同。当然AIO SERVER没有必要配置的太多，要根据 应用和使用的磁盘控制器数量等决定。<br /></span>
		</p>
<img src ="http://www.cppblog.com/tx7do/aggbug/9530.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-07-07 12:04 <a href="http://www.cppblog.com/tx7do/archive/2006/07/07/9530.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>iocp进行SOCKET通信(转载) </title><link>http://www.cppblog.com/tx7do/archive/2006/07/07/9529.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 07 Jul 2006 04:03:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2006/07/07/9529.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/9529.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2006/07/07/9529.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/9529.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/9529.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转载于hxzb7215191 的BLOG		当然TCP方式的模型还有事件选择模型。就是把所有的网络事件和我们的一个程序里定义的事件梆定。这个有它的好处，可能可以让我们更好的写一个线程来管理接收与发送。现在来讲一下一个完成端口模型。		  完成端口   一个完成端口其实就是一个通知队列，由操作系统把已经完成的重叠I/O请求的通知 放入其中。当某项I/O操作一旦完成，某个可以对该操作结果进行处...&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/archive/2006/07/07/9529.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/9529.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-07-07 12:03 <a href="http://www.cppblog.com/tx7do/archive/2006/07/07/9529.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>IOCP , kqueue , epoll ... 有多重要？</title><link>http://www.cppblog.com/tx7do/archive/2006/07/07/9528.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 07 Jul 2006 04:02:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2006/07/07/9528.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/9528.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2006/07/07/9528.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/9528.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/9528.html</trackback:ping><description><![CDATA[

		<div class="entry-body">
				<p><span  style="background-color: rgb(255, 255, 255); "><a href="http://blog.codingnow.com/2006/04/iocp_kqueue_epoll.html" style="color: rgb(0, 44, 153); text-decoration: none; "><strong><span style="COLOR:red">来源:http://blog.codingnow.com/2006/04/iocp_kqueue_epoll.html</span></strong></a></span></p><p><br></p><p>设计 mmo 服务器，我听过许多老生常谈，说起处理大量连接时， select 是多么低效。我们应该换用 iocp (windows), kqueue(freebsd), 或是 epoll(linux) 。的确，处理大量的连接的读写，select 是够低效的。因为 kernel 每次都要对 select 传入的一组 socket 号做轮询，那次在上海，以陈榕的说法讲，这叫鬼子进村策略。一遍遍的询问&#8220;鬼子进村了吗？&#8221;，&#8220;鬼子进村了吗？&#8221;... 大量的 cpu 时间都耗了进去。（更过分的是在 windows 上，还有个万恶的 64 限制。）</p>
				<p>使用 kqueue 这些，变成了派一些个人去站岗，鬼子来了就可以拿到通知，效率自然高了许多。不过最近我在反思，真的需要以这些为基础搭建服务器吗？</p>
		</div>
		<div class="entry-more" id="more">
				<p>刚形成的一个思路是这样的：</p>
				<p>我们把处理外部连接和处理游戏逻辑分摊到两个服务器上处理，为了后文容易表述，暂时不太严谨的把前者称为连接服务器，后者叫做逻辑服务器。</p>
				<p>连接服务器做的事情可以非常简单，只是把多个连接上的数据汇集到一起。假设同时连接总数不超过 65536 个，我们只需要把每个连接上的数据包加上一个两字节的数据头就可以表识出来。这个连接服务器再通过单个连接和逻辑服务器通讯就够了。</p>
				<p>那么连接服务器尽可以用最高效的方式处理数据，它的逻辑却很简单，代码量非常的小。而逻辑服务器只有一个外部连接，无论用什么方式处理都不会慢了。</p>
				<p>进一步，我们可以把这个方法扩展开。假定我们逻辑以 10Hz 的频率处理逻辑。我们就让连接服务器以 10Hz 的脉冲把汇总的数据周期性的发送过去，先发一个长度信息再发数据包。即使一个脉冲没有外部数据，也严格保证至少发一个 0 的长度信息。额外的，连接服务器还需要控制每个脉冲的数据总流量，不至于一次发送数据超过逻辑服务器处理的能力。</p>
				<p>那么，逻辑服务器甚至可以用阻塞方式调用 recv 收取这些数据，连 select 也省了。至于数据真的是否会被接收方阻塞，就由连接服务器的逻辑保证了。</p>
				<p>说到阻塞接收，我跟一个同事讨论的时候，他严重担心这个的可靠性，不希望因为意外把逻辑服务器挂在一个 system call 上。他列举了许多可能发生的意外情况，不过我个人是不太担心的，原因不想在这里多解释。当然我这样设计，主要不是为了节省一个 select 的调用，而是希望方便调试。（当然，如果事实证明这样不可行，修改方案也很容易）</p>
				<p>因为阻塞接收可以保证逻辑服务器的严格时序性，当我们把两个服务器中的通讯记录下来，以后可以用这些数据完全重现游戏逻辑的过程，无论怎么调试运行，都可以保证逻辑服务器的行为是可以完全重现的。即，每 0.1s 接受已知的数据包，然后处理它们。</p>
				<p>这样做，逻辑服务器对网络层的代码量的需求也大大减少了，可以更专心的构建逻辑。<br><br></p>
		</div><img src ="http://www.cppblog.com/tx7do/aggbug/9528.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-07-07 12:02 <a href="http://www.cppblog.com/tx7do/archive/2006/07/07/9528.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在WinSock上使用IOCP</title><link>http://www.cppblog.com/tx7do/archive/2006/07/07/9518.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 07 Jul 2006 03:46:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2006/07/07/9518.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/9518.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2006/07/07/9518.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/9518.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/9518.html</trackback:ping><description><![CDATA[在WinSock上使用IOCP <br />本文章假设你已经理解WindowsNT的I/O模型以及I/O完成端口(IOCP)，并且比较熟悉将要用到的API，如果你打算学习IOCP，请参考Jeffery Richter的Advanced Windows(第三版)，第15章I/O设备，里面有极好的关于完成端口的讨论以及对即将使用API的说明。 <br />IOCP提供了一个用于开发高效率和易扩展程序的模型。Winsock2提供了对IOCP的支持，并在WindowsNT平台得到了完整的实现。然而IOCP是所有WindowsNT I/O模型中最难理解和实现的，为了帮助你使用IOCP设计一个更好的Socket服务，本文提供了一些诀窍。 <br /><br />Tip 1:使用Winsock2 IOCP函数例如WSASend和WSARecv，如同Win32文件I/O函数，例如WriteFile和ReadFile。 <br />微软提供的Socket句柄是一个可安装文件系统(IFS)句柄，因此你可以使用Win32的文件I/O函数调用这个句柄，然而，将Socket句柄和文件系统联系起来，你不得不陷入很多的Kernal/User模式转换的问题中，例如线程的上下文转换，花费的代价还包括参数的重新排列导致的性能降低。 <br />因此你应该使用只被Winsock2中IOCP允许的函数来使用IOCP。在ReadFile和WriteFile中会发生的额外的参数重整以及模式转换只会发生在一种情况下，那就是如果句柄的提供者并没有将自己的WSAPROTOCOL_INFO结构中的DwServiceFlags1设置为XP1_IFS_HANDLES。 <br />注解：即使使用WSASend和WSARecv，这些提供者仍然具有不可避免的额外的模式转换，当然ReadFile和WriteFile需要更多的转换。 <br /><br />TIP 2: 确定并发工作线程数量和产生的工作线程总量。 <br />并发工作线程的数量和工作线程的数量并不是同一概念。你可以决定IOCP使用最多2个的并发线程以及包括10个工作线程的线程池。工作线程池拥有的线程多于或者等于并发线程的数量时，工作线程处理队列中一个封包的时候可以调用win32的Wait函数，这样可以无延迟的处理队列中另外的封包。 <br />如果队列中有正在等待被处理的封包，系统将会唤醒一个工作线程处理他，最后，第一个线程确认正在休眠并且可以被再次调用，此时，可调用线程数量会多于IOCP允许的并发线程数量(例如,NumberOFConcurrentThreads)。然而，当下一个线程调用GetQueueCompletionStatus并且进入等待状态，系统不会唤醒他。一般来说，系统会试图保持你设定的并发工作线程数量。 <br />一般来讲，每拥有一个CPU，在IOCP中你可以使用一个并发工作线程，要做到这点，当你第一次初始化IOCP的时候，可以在调用CreateIOCompletionPort的时候将NumberOfConcurrentThreads设置为0。 <br /><br />TIP 3：将一个提交的I/O操作和完成封包的出列联系起来。 <br />当对一个封包进行出列，可以调用GetQueuedCompletionStatus返回一个完成Key和一个复合的结构体给I/O。你可以分别的使用这两个结构体来返回一个句柄和一个I/O操作信息，当你将IOCP提供的句柄信息注册给Socket，那么你可以将注册的Socket句柄当做一个完成Key来使用。为每一个I/O的"extend"操作提供一个包含你的应用程序IO状态信息的复合结构体。当然，必须确定你为每个的I/O提供的是唯一的复合结构体。当I/O完成的时候，会返回一个指向结构体的指针。 <br /><br />TIP 4:I/O完成封包队列的行为 <br />IOCP中完成封包队列的等待次序并不决定于Winsock2 I/O调用产生的顺序。如果一个Winsock2的I/O调用返回了SUCCESS或者IO_PENDING，那么他保证当I/O操作完成后，完成封包会进入IOCP的等待队列，而不管Socket句柄是否已经关闭。如果你关闭了socket句柄，那么将来调用WSASend,WSASendTo,WSARecv和WSARecvFrom会失败并返回一个不同于SUCCES或者IO_PENDING的代码，这时将不会产生一个完成封包。而在这种情况下，前一次使用GetQueuedCompletionStatus提交的I/O操作所得到的完成封包，会显示一个失败的信息。 <br />如果你删除了IOCP本身，那么不会有任何I/O请求发送给IOCP，因为IOCP的句柄已经不可用，尽管系统底层的IOCP核心结构并不会在所有已提交I/O请求完成之前被移除。 <br /><br />TIP5:IOCP的清除 <br />很重要的一件事是使用复合I/O时候的IOCP清除：如果一个I/O操作尚未完成，那么千万不要释放该操作创建的复合结构体。HasOverlappedIoCompleted函数可以帮助你检查一个I/O操作是否已经完成。 <br />关闭服务一般有两种情况，第一种你并不关心尚未结束的I/O操作的完成状态，你只希望尽可能快的关闭他。第二种，你打算关闭服务，但是你需要获知未结束I/O操作的完成状态。 <br />第一种情况你可以调用PostQueueCompletionStatus(N次，N等于你的工作线程数量)来提交一个特殊的完成封包，他通知所有的工作线程立即退出，关闭所有socket句柄和他们关联的复合结构体，然后关闭完成端口(IOCP)。在关闭复合结构体之前使用HasOverlappedIOCompleted检查他的完成状态。如果一个socket关闭了，所有基于他的未结束的I/O操作会很快的完成。 <br />在第二种情况，你可以延迟工作线程的退出来保证所有的完成封包可以被适当的出列。你可以首先关闭所有的socket句柄和IOCP。可是，你需要维护一个未完成I/O的数字，以便你的线程可以知道可以安全退出的时间。尽管当队列中有很多完成封包在等待的时候，活动的工作线程不能立即退出，但是在IOCP服务中使用全局I/O计数器并且使用临界区保护他的代价并不会象你想象的那样昂贵。 <br /><br />INFO: Design Issues When Using IOCP in a Winsock Server <br /><br />适用于 <br /><br />This article was previously published under Q192800 <br /><br />SUMMARY <br /><br />This article assumes you already understand the I/O model of the Windows NT I/O Completion Port (IOCP) and are familiar with the related APIs. If you want to learn IOCP, please see Advanced Windows (3rd edition) by Jeffery Richter, chapter 15 Device I/O for an excellent discussion on IOCP implementation and the APIs you need to use it. <br /><br /><br /><br />An IOCP provides a model for developing very high performance and very scalable server programs. Direct IOCP support was added to Winsock2 and is fully implemented on the Windows NT platform. However, IOCP is the hardest to understand and implement among all Windows NT I/O models. To help you design a better socket server using IOCP, a number of tips are provided in this article. <br /><br />MORE INFORMATION <br /><br />TIP 1: Use Winsock2 IOCP-capable functions, such as WSASend and WSARecv, over Win32 file I/O functions, such as WriteFile and ReadFile. <br /><br /><br /><br />Socket handles from Microsoft-based protocol providers are IFS handles so you can use Win32 file I/O calls with the handle. However, the interactions between the provider and file system involve many kernel/user mode transition, thread context switches, and parameter marshals that result in a significant performance penalty. You should use only Winsock2 IOCP- capable functions with IOCP. <br /><br /><br /><br />The additional parameter marshals and mode transitions in ReadFile and WriteFile only occur if the provider does not have XP1_IFS_HANDLES bit set in dwServiceFlags1 of its WSAPROTOCOL_INFO structure. <br /><br /><br /><br />NOTE: These providers have an unavoidable additional mode transition, even in the case of WSASend and WSARecv, although ReadFile and WriteFile will have more of them. <br /><br /><br /><br />TIP 2: Choose the number of the concurrent worker threads allowed and the total number of the worker threads to spawn. <br /><br /><br /><br />The number of worker threads and the number of concurrent threads that the IOCP uses are not the same thing. You can decide to have a maximum of 2 concurrent threads used by the IOCP and a pool of 10 worker threads. You have a pool of worker threads greater than or equal to the number of concurrent threads used by the IOCP so that a worker thread handling a dequeued completion packet can call one of the Win32 "wait" functions without delaying the handling of other queued I/O packets. <br /><br /><br /><br />If there are completion packets waiting to be dequeued, the system will wake up another worker thread. Eventually, the first thread satisfies it's Wait and it can be run again. When this happens, the number of the threads that can be run is higher than the concurrency allowed on the IOCP (for example, NumberOfConcurrentThreads). However, when next worker thread calls GetQueueCompletionStatus and enters wait status, the system does not wake it up. In other words, the system tries to keep your requested number of concurrent worker threads. <br /><br /><br /><br />Typically, you only need one concurrent worker thread per CPU for IOCP. To do this, enter 0 for NumberOfConcurrentThreads in the CreateIoCompletionPort call when you first create the IOCP. <br /><br /><br /><br />TIP 3: Associate a posted I/O operation with a dequeued completion packet. <br /><br /><br /><br />GetQueuedCompletionStatus returns a completion key and an overlapped structure for the I/O when dequeuing a completion packet. You should use these two structures to return per handle and per I/O operation information, respectively. You can use your socket handle as the completion key when you register the socket with the IOCP to provide per handle information. To provide per I/O operation "extend" the overlapped structure to contain your application-specific I/O-state information. Also, make sure you provide a unique overlapped structure for each overlapped I/O. When an I/O completes, the same pointer to the overlapped I/O structure is returned. <br /><br /><br /><br />TIP 4: I/O completion packet queuing behavior. <br /><br /><br /><br />The order in which I/O completion packets are queued in the IOCP is not necessarily the same order the Winsock2 I/O calls were made. Additionally, if a Winsock2 I/O call returns SUCCESS or IO_PENDING, it is guaranteed that a completion packet will be queued to the IOCP when the I/O completes, regardless of whether the socket handle is closed. After you close a socket handle, future calls to WSASend, WSASendTo, WSARecv, or WSARecvFrom will fail with a return code other than SUCCESS or IO_PENDING, which will not generate a completion packet. The status of the completion packet retrieved by GetQueuedCompletionStatus for I/O previously posted could indicate a failure in this case. <br /><br /><br /><br />If you delete the IOCP itself, no more I/O can be posted to the IOCP because the IOCP handle itself is invalid. However, the system's underlying IOCP kernel structures do not go away until all successfully posted I/Os are completed. <br /><br /><br /><br />TIP 5: IOCP cleanup. <br /><br /><br /><br />The most important thing to remember when performing ICOP cleanup is the same when using overlapped I/O: do not free an overlapped structure if the I/O for it has not yet completed. The HasOverlappedIoCompleted macro allows you to detect if an I/O has completed from its overlapped structure. <br /><br /><br /><br />There are typically two scenarios for shutting down a server. In the first scenario, you do not care about the completion status of outstanding I/Os and you just want to shut down as fast as you can. In the second scenario, you want to shut down the server, but you do need to know the completion status of each outstanding I/O. <br /><br /><br /><br />In the first scenario, you can call PostQueueCompletionStatus (N times, where N is the number of worker threads) to post a special completion packet that informs the worker thread to exit immediately, close all socket handles and their associated overlapped structures, and then close the completion port. Again, make sure you use HasOverlappedIoCompleted to check the completion status of an overlapped structure before you free it. If a socket is closed, all outstanding I/O on the socket eventually complete quickly. <br /><br /><br /><br />In the second scenario, you can delay exiting worker threads so that all completion packets can be properly dequeued. You can start by closing all socket handles and the IOCP. However, you need to maintain a count of the number of outstanding I/Os so that your worker thread can know when it is safe to exit the thread. The performance penalty of having a global I/O counter protected with a critical section for an IOCP server is not as bad as might be expected because the active worker thread does not switch out if there are more completion packets waiting in the queue. <img src ="http://www.cppblog.com/tx7do/aggbug/9518.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-07-07 11:46 <a href="http://www.cppblog.com/tx7do/archive/2006/07/07/9518.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ACE高效PROACTOR编程框架一ClientHandle </title><link>http://www.cppblog.com/tx7do/archive/2006/07/07/9517.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 07 Jul 2006 03:46:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2006/07/07/9517.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/9517.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2006/07/07/9517.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/9517.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/9517.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p>1、WIN32下面用proactor可以达到几乎RAW　IOCP的效率，由于封装关系，应该是差那么一点。<br /><br /></p>
				<p>客户端处理类的常规写法：<br />//处理客户端连接消息<br />class ClientHandler : public ACE_Service_Handler<br />{<br />public:<br /> /**构造函数<br />  *<br />  *<br />  */<br /> ClientHandler(unsigned int client_recv_buf_size=SERVER_CLIENT_RECEIVE_BUF_SIZE)<br />  :_read_msg_block(client_recv_buf_size),_io_count(0)<br /> {<br /> }</p>
				<p>
						<br /> ~ClientHandler(){}</p>
				<p> /**<br />  *初始化，因为可能要用到ClientHandler内存池，而这个池又不一定要用NEW<br />  */<br /> void init();</p>
				<p> /**清理函数，因为可能要用到内存池<br />  *<br />  */<br /> void fini();<br /></p>
				<p>//检查是否超时的函数</p>
				<p> void check_time_out(time_t cur_time);</p>
				<p>public:</p>
				<p> /**客户端连接服务器成功后调用<br />  *<br />  * \param handle 套接字句柄<br />  * \param &amp;message_block 第一次读到的数据（未用）<br />  */<br /></p>
				<p>//由Acceptor来调用！！！<br /> virtual void open (ACE_HANDLE handle,ACE_Message_Block &amp;message_block);</p>
				<p> /**处理网络读操作结束消息<br />  *<br />  * \param &amp;result 读操作结果<br />  */<br /> virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &amp;result);</p>
				<p>
						<br /> /**处理网络写操作结束消息<br />  *<br />  * \param &amp;result 写操作结果<br />  */<br /> virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &amp;result);</p>
				<p>private:</p>
				<p>//**生成一个网络读请求<br />  *<br />  * \param void <br />  * \return 0-成功，-1失败<br />  */<br /> int  initiate_read_stream  (void);</p>
				<p> /**生成一个写请求<br />  *<br />  * \param mb 待发送的数据<br />  * \param nBytes 待发送数据大小<br />  * \return 0－成功，－1失败<br />  */<br /> int  initiate_write_stream (ACE_Message_Block &amp; mb, size_t nBytes );<br /> <br /> /**<br />  *<br />  * \return 检查是否可以删除，用的是一个引用计数。每一个外出IO的时候＋1，每一个IO成功后－1<br />  */<br /> int check_destroy();<br /> <br /> //异步读<br /> ACE_Asynch_Read_Stream _rs;</p>
				<p> //异步写<br /> ACE_Asynch_Write_Stream _ws;</p>
				<p> //接收缓冲区只要一个就够了，因为压根就没想过要多读，我直到现在也不是很清楚为什么要多读，多读的话要考虑很多问题<br /> ACE_Message_Block _read_msg_block;</p>
				<p> //套接字句柄,这个可以不要了，因为基类就有个HANDLER在里面的。<br /> //ACE_HANDLE _handle;</p>
				<p> //一个锁，客户端反正有东东要锁的，注意，要用ACE_Recursive_Thread_Mutex而不是用ACE_Thread_Mutex，这里面是可以重入的，而且在WIN32下是直接的EnterCriticalSection，可以达到很高的效率<br /> ACE_Recursive_Thread_Mutex _lock;<br /> <br /> //在外IO数量,其实就是引用计数啦，没啥的。为0的时候就把这个东东关掉啦。<br /> long _io_count;<br /></p>
				<p>//检查超时用的，过段时间没东东就CLOSE他了。</p>
				<p> time_t _last_net_io;</p>
				<p>private:<br /></p>
				<p>//本来想用另外一种模型的，只用1个或者2个外出读，后来想想，反正一般内存都是足够的，就不管了。</p>
				<p> //ACE_Message_Block _send_msg_blocks[2];</p>
				<p> //ACE_Message_Block &amp;_sending_msg_block;</p>
				<p> //ACE_Message_Block &amp;_idle_msg_block;</p>
				<p>private:<br /> <br />public:<br />//TODO:move to prriva and use friend class!!!<br /></p>
				<p>//只是为了效率更高，不用STL的LIST是因为到现在我没有可用的Node_Allocator，所以效率上会有问题。<br /> ClientHandler *_next;</p>
				<p> ClientHandler *next(){return _next;}</p>
				<p> void next(ClientHandler *obj){_next=obj;}</p>
				<p>};<br /></p>
				<p>
						<br />//这是具体实现，有些地方比较乱，懒得管了，锁的有些地方不对。懒得改了，反正在出错或者有瓶颈的时候再做也不迟。</p>
				<p>void ClientHandler::handle_read_stream (const ACE_Asynch_Read_Stream::Result &amp;result)<br />{<br /> _last_net_io=ACE_OS::time(NULL);<br /> int byterecved=result.bytes_transferred ();<br /> if ( (result.success ()) &amp;&amp; (byterecved != 0))<br /> {<br />  //ACE_DEBUG ((LM_DEBUG,  "Receiver completed:%d\n",byterecved));<br /></p>
				<p>//处理完数据<br />  if(handle_received_data()==true)<br />  {<br />   //ACE_DEBUG ((LM_DEBUG,  "go on reading...\n"));<br /></p>
				<p>//把东东推到头部，处理粘包<br />   _read_msg_block.crunch();<br />   initiate_read_stream();<br />  }<br /> }<br /></p>
				<p>//这个地方不想用ACE_Atom_op，因为反正要有一个锁，而且一般都会用锁，不管了。假如不在意的话，应该直接用ACE_Atom_Op以达到最好的效率</p>
				<p> {<br />  ACE_Guard&lt;ACE_Recursive_Thread_Mutex&gt; locker (_lock);<br />  _io_count--;<br /> }<br /> check_destroy ();<br />}</p>
				<p>void ClientHandler::init()<br />{<br /></p>
				<p>//初始化数据，并不在构造函数里做。<br /> _last_net_io=ACE_OS::time(NULL);<br /> _read_msg_block.rd_ptr(_read_msg_block.base());<br /> _read_msg_block.wr_ptr(_read_msg_block.base());<br /> this-&gt;handle(ACE_INVALID_HANDLE);<br />}</p>
				<p>bool ClientHandler::handle_received_data()<br />{<br /></p>
				<p>...........自己处理<br /> return true;<br />}</p>
				<p>
						<br />//==================================================================<br />void ClientHandler::handle_write_stream (const ACE_Asynch_Write_Stream::Result &amp;result)<br />{<br /> //发送成功，RELEASE掉<br /> //这个不可能有多个RELEASE，直接XX掉<br /> //result.message_block ().release ();<br /> MsgBlockManager::get_instance().release_msg_block(&amp;result.message_block());</p>
				<p> {<br />  ACE_Guard&lt;ACE_Recursive_Thread_Mutex&gt; locker (_lock);<br />  _io_count--;<br /> }<br /> check_destroy ();<br />}</p>
				<p>//bool ClientHandler::destroy () <br />//{<br />// FUNC_ENTER;<br />// ClientManager::get_instance().release_client_handle(this);<br />// FUNC_LEAVE;<br />// return false ;<br />//}</p>
				<p>
						<br />int  ClientHandler::initiate_read_stream  (void)<br />{<br /> ACE_Guard&lt;ACE_Recursive_Thread_Mutex&gt; locker (_lock);<br /></p>
				<p>//考虑到粘包的呀<br /> if (_rs.read (_read_msg_block, _read_msg_block.space()) == -1)<br /> {<br />  ACE_ERROR_RETURN ((LM_ERROR,"%p\n","ACE_Asynch_Read_Stream::read"),-1);<br /> }<br /> _io_count++;<br /> return 0;<br />}</p>
				<p>/**生成一个写请求<br />*<br />* \param mb 待发送的数据<br />* \param nBytes 待发送数据大小<br />* \return 0－成功，－1失败<br />*/<br />int  ClientHandler::initiate_write_stream (ACE_Message_Block &amp; mb, size_t nBytes )<br />{<br /> ACE_Guard&lt;ACE_Recursive_Thread_Mutex&gt; locker (_lock);<br /> if (_ws.write (mb , nBytes ) == -1)<br /> {<br />  mb.release ();<br />  ACE_ERROR_RETURN((LM_ERROR,"%p\n","ACE_Asynch_Write_File::write"),-1);<br /> }<br /> _io_count++;<br /> return 0;<br />}</p>
				<p>void ClientHandler::open (ACE_HANDLE handle,ACE_Message_Block &amp;message_block)<br />{<br /> //FUNC_ENTER;<br /> _last_net_io=ACE_OS::time(NULL);<br /> _io_count=0;<br /> if(_ws.open(*this,this-&gt;handle())==-1)<br /> {<br />  ACE_ERROR ((LM_ERROR,"%p\n","ACE_Asynch_Write_Stream::open"));<br /> }<br /> else if (_rs.open (*this, this-&gt;handle()) == -1)<br /> {<br />  ACE_ERROR ((LM_ERROR,"%p\n","ACE_Asynch_Read_Stream::open"));<br /> }<br /> else<br /> {<br />  initiate_read_stream ();<br /> }</p>
				<p> check_destroy();<br /> //FUNC_LEAVE;<br />}</p>
				<p>void ClientHandler::fini()<br />{<br />}</p>
				<p>void ClientHandler::check_time_out(time_t cur_time)<br />{<br /> //ACE_Guard&lt;ACE_Recursive_Thread_Mutex&gt; locker (_lock);<br /> //ACE_DEBUG((LM_DEBUG,"cur_time is %u,last io is %u\n",cur_time,_last_net_io));</p>
				<p> //检测是否已经为0了<br /> if(this-&gt;handle()==ACE_INVALID_HANDLE)<br />  return;<br /> if(cur_time-_last_net_io&gt;CLIENT_TIME_OUT_SECONDS)<br /> {<br />  ACE_OS::shutdown(this-&gt;handle(),SD_BOTH);<br />  ACE_OS::closesocket(this-&gt;handle());<br />  this-&gt;handle(ACE_INVALID_HANDLE);<br /> }<br />}</p>
				<p>int ClientHandler::check_destroy()<br />{<br /> {<br />  ACE_Guard&lt;ACE_Recursive_Thread_Mutex&gt; locker (_lock);<br />  if (_io_count&gt; 0)<br />   return 1;<br /> }<br /> ACE_OS::shutdown(this-&gt;handle(),SD_BOTH);<br /> ACE_OS::closesocket(this-&gt;handle());<br /> this-&gt;handle(ACE_INVALID_HANDLE);<br /></p>
				<p>//这个地方给内存池吧。<br /> ClientManager::get_instance().release_client_handle(this);<br /> //delete this;<br /> return 0;<br />}</p>
		</div>
<img src ="http://www.cppblog.com/tx7do/aggbug/9517.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-07-07 11:46 <a href="http://www.cppblog.com/tx7do/archive/2006/07/07/9517.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>心跳包</title><link>http://www.cppblog.com/tx7do/archive/2006/07/07/9516.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 07 Jul 2006 03:45:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/archive/2006/07/07/9516.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/9516.html</wfw:comment><comments>http://www.cppblog.com/tx7do/archive/2006/07/07/9516.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/9516.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/9516.html</trackback:ping><description><![CDATA[一般是用来判断对方（设备，进程或其它网元）是否正常动行，一般采用定时发送简单的通讯包，如果在指定时间段内未收到对方响应，则判断对方已经当掉。用于检测TCP的异常断开。<br /><p>一般是用来判断对方（设备，进程或其它网元）是否正常动行，一般采用定时发送简单的通讯包，如果在指定时间段内未收到对方响应，则判断对方已经当掉。用于检测TCP的异常断开。</p><p><br />基本原因是服务器端不能有效的判断客户端是否在线也就是说，服务器无法区分客户端是长时间在空闲，还是已经掉线的情况.所谓的心跳包就是客户端定时发送简单的信息给服务器端告诉它我还在而已。</p><p>代码就是每隔几分钟发送一个固定信息给服务端，服务端收到后回复一个固定信息<br />如果服务端几分钟内没有收到客户端信息则视客户端断开。比如有些通信软件长时间不使用，要想知道它的状态是在线还是离线就需要心跳包，定时发包收包。</p><p>发包方：可以是客户也可以是服务端，看哪边实现方便合理。一般是客户端。服务器也可以定时轮询发心跳下去。<br /><br />一般来说，出于效率的考虑，是由客户端主动向服务器端发包，而不是相反。</p><img src ="http://www.cppblog.com/tx7do/aggbug/9516.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-07-07 11:45 <a href="http://www.cppblog.com/tx7do/archive/2006/07/07/9516.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>