﻿<?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/kevinlynx/category/6338.html</link><description>低调做技术</description><language>zh-cn</language><lastBuildDate>Wed, 14 May 2008 11:38:54 GMT</lastBuildDate><pubDate>Wed, 14 May 2008 11:38:54 GMT</pubDate><ttl>60</ttl><item><title>tcp要点学习-断开连接</title><link>http://www.cppblog.com/kevinlynx/archive/2008/05/14/49825.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Wed, 14 May 2008 07:46:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/05/14/49825.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/49825.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/05/14/49825.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/49825.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/49825.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 10pt"><strong>主要部分，四次握手：</strong>
<p style="FONT-SIZE: 10pt">断开连接其实从我的角度看不区分客户端和服务器端，任何一方都可以调用close(or closesocket)之类<br>的函数开始主动终止一个连接。这里先暂时说正常情况。当调用close函数断开一个连接时，主动断开的<br>一方发送FIN(finish报文给对方。有了之前的经验，我想你应该明白我说的FIN报文时什么东西。也就是<br>一个设置了FIN标志位的报文段。FIN报文也可能附加用户数据，如果这一方还有数据要发送时，将数据附<br>加到这个FIN报文时完全正常的。之后你会看到，这种附加报文还会有很多，例如ACK报文。我们所要把握<br>的原则是，TCP肯定会力所能及地达到最大效率，所以你能够想到的优化方法，我想TCP都会想到。
<p style="FONT-SIZE: 10pt">当被动关闭的一方收到FIN报文时，它会发送ACK确认报文(对于ACK这个东西你应该很熟悉了)。这里有个<br>东西要注意，因为TCP是双工的，也就是说，你可以想象一对TCP连接上有两条数据通路。当发送FIN报文<br>时，意思是说，发送FIN的一端就不能发送数据，也就是关闭了其中一条数据通路。被动关闭的一端发送<br>了ACK后，应用层通常就会检测到这个连接即将断开，然后被动断开的应用层调用close关闭连接。
<p style="FONT-SIZE: 10pt">我可以告诉你，一旦当你调用close(or closesocket)，这一端就会发送FIN报文。也就是说，现在被动<br>关闭的一端也发送FIN给主动关闭端。有时候，被动关闭端会将ACK和FIN两个报文合在一起发送。主动<br>关闭端收到FIN后也发送ACK，然后整个连接关闭(事实上还没完全关闭，只是关闭需要交换的报文发送<br>完毕)，四次握手完成。如你所见，因为被动关闭端可能会将ACK和FIN合到一起发送，所以这也算不上<br>严格的四次握手---四个报文段。
<p style="FONT-SIZE: 10pt">在前面的文章中，我一直没提TCP的状态转换。在这里我还是在犹豫是不是该将那张四处通用的图拿出来，<br>不过，这里我只给出断开连接时的状态转换图，摘自&lt;The TCP/IP Guide&gt;：
<p style="FONT-SIZE: 10pt"><a href="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/tcp_DDB4/tcpclose_2.png"><img style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=560 alt=tcpclose src="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/tcp_DDB4/tcpclose_thumb.png" width=670 border=0></a>
<p style="FONT-SIZE: 10pt">给出一个正常关闭时的windump信息：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">14</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">38.819856</span><span style="COLOR: #000000">&nbsp;IP&nbsp;cd</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">zhangmin.</span><span style="COLOR: #000000">1748</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">220.181</span><span style="COLOR: #000000">.</span><span style="COLOR: #000000">37.55</span><span style="COLOR: #000000">.</span><span style="COLOR: #000000">80</span><span style="COLOR: #000000">:&nbsp;F&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;ack&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;win&nbsp;</span><span style="COLOR: #000000">65535</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">14</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">38.863989</span><span style="COLOR: #000000">&nbsp;IP&nbsp;</span><span style="COLOR: #000000">220.181</span><span style="COLOR: #000000">.</span><span style="COLOR: #000000">37.55</span><span style="COLOR: #000000">.</span><span style="COLOR: #000000">80</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;cd</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">zhangmin.</span><span style="COLOR: #000000">1748</span><span style="COLOR: #000000">:&nbsp;F&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)&nbsp;ack&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;win&nbsp;</span><span style="COLOR: #000000">2920</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">14</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">00</span><span style="COLOR: #000000">:</span><span style="COLOR: #000000">38.864412</span><span style="COLOR: #000000">&nbsp;IP&nbsp;cd</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">zhangmin.</span><span style="COLOR: #000000">1748</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">220.181</span><span style="COLOR: #000000">.</span><span style="COLOR: #000000">37.55</span><span style="COLOR: #000000">.</span><span style="COLOR: #000000">80</span><span style="COLOR: #000000">:&nbsp;.&nbsp;ack&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;win&nbsp;</span><span style="COLOR: #000000">65535</span><span style="COLOR: #000000">&nbsp;</span></div>
<p style="FONT-SIZE: 10pt">&nbsp;
<p style="FONT-SIZE: 10pt"><strong>补充细节：</strong>
<p style="FONT-SIZE: 10pt">关于以上的四次握手，我补充下细节：<br>1. 默认情况下(不改变socket选项)，当你调用close( or closesocket，以下说close不再重复)时，如果<br>发送缓冲中还有数据，TCP会继续把数据发送完。<br>2. 发送了FIN只是表示这端不能继续发送数据(应用层不能再调用send发送)，但是还可以接收数据。<br>3. 应用层如何知道对端关闭？通常，在最简单的阻塞模型中，当你调用recv时，如果返回0，则表示对端<br>关闭。在这个时候通常的做法就是也调用close，那么TCP层就发送FIN，继续完成四次握手。如果你不调用<br>close，那么对端就会处于FIN_WAIT_2状态，而本端则会处于CLOSE_WAIT状态。这个可以写代码试试。<br>4. 在很多时候，TCP连接的断开都会由TCP层自动进行，例如你CTRL+C终止你的程序，TCP连接依然会正常关<br>闭，你可以写代码试试。
<p style="FONT-SIZE: 10pt"><strong>特别的TIME_WAIT状态：</strong>
<p style="FONT-SIZE: 10pt">从以上TCP连接关闭的状态转换图可以看出，主动关闭的一方在发送完对对方FIN报文的确认(ACK)报文后，<br>会进入TIME_WAIT状态。TIME_WAIT状态也称为2MSL状态。
<p style="FONT-SIZE: 10pt">什么是2MSL？MSL即Maximum Segment Lifetime，也就是报文最大生存时间，引用&lt;TCP/IP详解&gt;中的话：&#8220;<br>它(MSL)是任何报文段被丢弃前在网络内的最长时间。&#8221;那么，2MSL也就是这个时间的2倍。其实我觉得没<br>必要把这个MSL的确切含义搞明白，你所需要明白的是，当TCP连接完成四个报文段的交换时，主动关闭的<br>一方将继续等待一定时间(2-4分钟)，即使两端的应用程序结束。你可以写代码试试，然后用netstat查看下。
<p style="FONT-SIZE: 10pt">为什么需要2MSL？根据&lt;TCP/IP详解&gt;和&lt;The TCP/IP Guide&gt;中的说法，有两个原因：<br>其一，保证发送的ACK会成功发送到对方，如何保证？我觉得可能是通过超时计时器发送。这个就很难用<br>代码演示了。<br>其二，报文可能会被混淆，意思是说，其他时候的连接可能会被当作本次的连接。直接引用&lt;The TCP/IP Guide&gt;<br>的说法：The second is to provide a &#8220;buffering period&#8221; between the end of this connection <br>and any subsequent ones. If not for this period, it is possible that packets from different <br>connections could be mixed, creating confusion.
<p style="FONT-SIZE: 10pt"><strong>TIME_WAIT状态所带来的影响：</strong>
<p style="FONT-SIZE: 10pt">当某个连接的一端处于TIME_WAIT状态时，该连接将不能再被使用。事实上，对于我们比较有现实意义的<br>是，这个端口将不能再被使用。某个端口处于TIME_WAIT状态(其实应该是这个连接)时，这意味着这个TCP<br>连接并没有断开(完全断开)，那么，如果你bind这个端口，就会失败。
<p style="FONT-SIZE: 10pt">对于服务器而言，如果服务器突然crash掉了，那么它将无法再2MSL内重新启动，因为bind会失败。解决这<br>个问题的一个方法就是设置socket的SO_REUSEADDR选项。这个选项意味着你可以重用一个地址。
<p style="FONT-SIZE: 10pt"><strong>对于TIME_WAIT的插曲：</strong>
<p style="FONT-SIZE: 10pt">当建立一个TCP连接时，服务器端会继续用原有端口监听，同时用这个端口与客户端通信。而客户端默认情况<br>下会使用一个随机端口与服务器端的监听端口通信。有时候，为了服务器端的安全性，我们需要对客户端进行<br>验证，即限定某个IP某个特定端口的客户端。客户端可以使用bind来使用特定的端口。
<p style="FONT-SIZE: 10pt">对于服务器端，当设置了SO_REUSEADDR选项时，它可以在2MSL内启动并listen成功。但是对于客户端，当使<br>用bind并设置SO_REUSEADDR时，如果在2MSL内启动，虽然bind会成功，但是在windows平台上connect会失败。<br>而在linux上则不存在这个问题。(我的实验平台：winxp, ubuntu7.10)
<p style="FONT-SIZE: 10pt">要解决windows平台的这个问题，可以设置SO_LINGER选项。SO_LINGER选项决定调用close时，TCP的行为。<br>SO_LINGER涉及到linger结构体，如果设置结构体中l_onoff为非0，l_linger为0，那么调用close时TCP连接<br>会立刻断开，TCP不会将发送缓冲中未发送的数据发送，而是立即发送一个RST报文给对方，这个时候TCP连<br>接就不会进入TIME_WAIT状态。
<p style="FONT-SIZE: 10pt">如你所见，这样做虽然解决了问题，但是并不安全。通过以上方式设置SO_LINGER状态，等同于设置SO_DONTLINGER<br>状态。
<p style="FONT-SIZE: 10pt"><strong>断开连接时的意外：</strong><br>这个算不上断开连接时的意外，当TCP连接发生一些物理上的意外情况时，例如网线断开，linux上的TCP实现<br>会依然认为该连接有效，而windows则会在一定时间后返回错误信息。
<p style="FONT-SIZE: 10pt">这似乎可以通过设置SO_KEEPALIVE选项来解决，不过不知道这个选项是否对于所有平台都有效。
<p style="FONT-SIZE: 10pt"><strong>总结：</strong>
<p style="FONT-SIZE: 10pt">个人感觉，越写越烂。接下来会讲到TCP的数据发送，这会涉及到滑动窗口各种定时器之类的东西。我真诚<br>希望各位能够多提意见。对于TCP连接的断开，我们只要清楚：<br>1. 在默认情况下，调用close时TCP会继续将数据发送完毕；<br>2. TIME_WAIT状态会导致的问题；<br>3. 连接意外断开时可能会出现的问题。<br>4. maybe more... </p>
<img src ="http://www.cppblog.com/kevinlynx/aggbug/49825.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-05-14 15:46 <a href="http://www.cppblog.com/kevinlynx/archive/2008/05/14/49825.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学生时代做的东西-留个纪念</title><link>http://www.cppblog.com/kevinlynx/archive/2008/05/14/49783.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Wed, 14 May 2008 01:23:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/05/14/49783.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/49783.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/05/14/49783.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/49783.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/49783.html</trackback:ping><description><![CDATA[<p>可能我这个人比较怀旧，对什么东西都想做个记录，方便日后回忆。可能很多认识我的朋友都是通过GameRes那个作品专</p> <p>区。我对于当年那种疯狂编程的干劲很是自豪，现在差了很多，以前帮别人做小学生系列游戏外包的时候，可以12小时出</p> <p>个弱智的小游戏，那些日子一度被我称为’12小时编程挑战赛‘，只是自己跟自己比赛。</p> <p>&nbsp;</p> <p>每一次发布在GameRes(排除早期的那些垃圾玩意），在写简介时我都要把自己开发用的时间写上，可是脾气好的sea_bug</p> <p>每次都给我删掉了。我自己汇总一下：</p> <p>&nbsp;</p> <p>1. 最让我自豪的一个游戏引擎，耗尽了我当时所有的设计能力。我努力把它做得很具扩展性，可是忽略了功能性。现在基本不维护了，可能是用户群太少了。我想我还是没做好吧：</p> <p><a href="http://code.google.com/p/edge2d/" target="_blank">edge2d google code page</a></p> <p>托sea_bug的忙搞了个论坛，冷清得让我心寒:<a title="http://bbs.gameres.com/showforum.asp?forumid=91" href="http://bbs.gameres.com/showforum.asp?forumid=91">http://bbs.gameres.com/showforum.asp?forumid=91</a></p> <p>&nbsp;</p> <p>2. PacShooter3d:</p> <p><a title="http://data.gameres.com/showmessage.asp?TopicID=90655" href="http://data.gameres.com/showmessage.asp?TopicID=90655">http://data.gameres.com/showmessage.asp?TopicID=90655</a></p> <p>不知道怎么的被人放到一个网站上了：<a title="http://noyes.cn/Software.Asp?id=9667" href="http://noyes.cn/Software.Asp?id=9667">http://noyes.cn/Software.Asp?id=9667</a></p> <p><a href="http://www.cppblog.com/Files/kevinlynx/PacShooterSrc.rar" target="_blank">源代码下载。</a></p> <p>&nbsp;</p> <p>3. Space Demon demo</p> <p>当初看到dophi写的俄罗斯方块营造的那种感觉觉得很不错，于是决定认真地做个游戏出来。结果后来做的东西让我很失望。这是一个在代码上过度设计的东西。我虽然对这个游戏不满意，但是我对代码还基本满意。后来这个游戏的代码被我游戏学院的一个朋友拿给金山的一个主程（在他们学校教书？）看，还得到了表扬。;D</p> <p>这个游戏我是直接开源了的：<a title="http://www.gameres.com/showmessage.asp?TopicID=73123" href="http://www.gameres.com/showmessage.asp?TopicID=73123">http://www.gameres.com/showmessage.asp?TopicID=73123</a></p> <p>&nbsp;</p> <p>4. Crazy Eggs Clone</p> <p>&lt;Crazy Eggs&gt;是小林子他们工作室做的东西，属于casual games，拿到国外去卖的。我当时也觉得casual games市场不错，还找了个美工，大谈特谈，吹嘘了很多，最终在写策划案的时候失败了。我当时心也懒了，最终失败。</p> <p>同样是在GameRes上：<a title="http://www.gameres.com/showmessage.asp?TopicID=72351" href="http://www.gameres.com/showmessage.asp?TopicID=72351">http://www.gameres.com/showmessage.asp?TopicID=72351</a></p> <p><a href="http://www.cppblog.com/Files/kevinlynx/CrazeEggs_Src.zip" target="_blank">源代码下载。</a></p> <p>后来我为了宣传edge2d，特地把这个游戏移植到我的引擎上。我从来很自豪自己代码的模块性，所以移植起来很容易。除了edge2d版本，我还做了HGE版本，不过HGE版本是做给别人的外包：</p> <p><a href="http://edge2d.googlecode.com/files/EdgeExample-CrazyEggsEdge_v3.zip" target="_blank">edge2d版本下载</a></p> <p>&nbsp;</p> <p>5. Brick Shooter Jr</p> <p>这个游戏也是我翻版别人的，用的别人的美术+音乐资源，自己重写代码。后来网上有个人又用我的资源翻作了个，做的比我好。</p> <p><a title="http://data.gameres.com/showmessage.asp?TopicID=65654" href="http://data.gameres.com/showmessage.asp?TopicID=65654">http://data.gameres.com/showmessage.asp?TopicID=65654</a></p> <p><a href="http://www.cppblog.com/Files/kevinlynx/BrickShooterJrSrc.rar" target="_blank">源代码下载</a></p> <p>6. Feeding Frenzy</p> <p>Popcap的经典游戏，我做的垃圾东西，不提其他的了：</p> <p><a title="http://data.gameres.com/showmessage.asp?TopicID=62796" href="http://data.gameres.com/showmessage.asp?TopicID=62796">http://data.gameres.com/showmessage.asp?TopicID=62796</a></p> <p><a href="http://www.cppblog.com/Files/kevinlynx/FFSrc.zip" target="_blank">源代码下载</a></p> <p>&nbsp;</p> <p>7.是男人就下一百层</p> <p>超级古老的东西，这个东西当初还和上海一家广告公司合作过。我签署了长这么大的第一份合同，结果后来一分钱没捞到。他们公司现在也不做这个了。和我合作的产品经理现在貌似在搞棋牌。</p> <p><a title="http://data.gameres.com/showmessage.asp?TopicID=54475" href="http://data.gameres.com/showmessage.asp?TopicID=54475">http://data.gameres.com/showmessage.asp?TopicID=54475</a></p> <p><a href="http://www.cppblog.com/Files/kevinlynx/Down100sourceCode.rar" target="_blank">源代码下载</a></p> <p>8. 所谓的雷电，一个我最早做的东西，现在你开baidu搜索 kevin lynx，出来最多的链接就是&lt;雷电kevinlynx版&gt;，别信那</p> <p>些，全是流氓软件。</p> <p><a title="http://data.gameres.com/showmessage.asp?TopicID=54474" href="http://data.gameres.com/showmessage.asp?TopicID=54474">http://data.gameres.com/showmessage.asp?TopicID=54474</a></p> <p><a href="http://www.cppblog.com/Files/kevinlynx/DSSourceCode.rar" target="_blank">源代码下载</a></p> <p>&nbsp;</p> <p>其他还给别人做了一些外包，在此特别感谢哆啦G梦老大，给我找了很多工作。他这个人四处跳巢，还给我说了几次工作。</p> <p>只是我还想暂时留在成都，所以都拒绝了。那些外包做的都比较垃圾，做到后来基本有个小游戏框架了。版权问题可能不</p> <p>能发布出来吧。</p><img src ="http://www.cppblog.com/kevinlynx/aggbug/49783.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-05-14 09:23 <a href="http://www.cppblog.com/kevinlynx/archive/2008/05/14/49783.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>tcp要点学习-建立连接</title><link>http://www.cppblog.com/kevinlynx/archive/2008/05/11/49482.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Sat, 10 May 2008 17:03:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/05/11/49482.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/49482.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/05/11/49482.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/49482.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/49482.html</trackback:ping><description><![CDATA[<p style="font-size: 10pt"><strong>准备：</strong>  <p style="font-size: 10pt">在这里本文将遵循上一篇文章的风格，只提TCP协议中的要点，这样我觉得可以更容易地掌握TCP。或者<br>根本谈不上掌握，对于这种纯理论的东西，即使你现在掌握了再多的细节，一段时间后也会淡忘。  <p style="font-size: 10pt">在以后各种细节中，因为我们会涉及到分析一些TCP中的数据报，因此一个协议包截获工具必不可少。在<br>&lt;TCP/IP详解&gt;中一直使用tcpdump。这里因为我的系统是windows，所以只好使用windows平台的tcpdump，<br>也就是<a href="http://www.winpcap.org/windump/" target="_blank">WinDump</a>。在使用WinDump之前，你需要安装该程序使用的库<a href="http://www.winpcap.org/install/default.htm#Developer" target="_blank">WinpCap</a>。  <p style="font-size: 10pt">关于WinDump的具体用法你可以从网上其他地方获取，这里我只稍微提一下。要让WinDump开始监听数据，<br>首先需要确定让其监听哪一个网络设备(或者说是网络接口)。你可以:  <p style="font-size: 10pt">&nbsp;</p> <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #000000">windump </span><span style="color: #000000">-</span><span style="color: #000000">D </span></div> <p style="font-size: 10pt">&nbsp; <p style="font-size: 10pt">获取当前机器上的网络接口。然后使用：  <p style="font-size: 10pt">&nbsp;</p> <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #000000">windump </span><span style="color: #000000">-</span><span style="color: #000000">i </span><span style="color: #000000">2</span><span style="color: #000000">&nbsp;</span></div> <p style="font-size: 10pt">&nbsp; <p style="font-size: 10pt">开始对网络接口2的数据监听。windump如同tcpdump(其实就是tcpdump)一样支持过滤表达式，windump<br>将会根据你提供的过滤表达式过滤不需要的网络数据包，例如：  <p style="font-size: 10pt">&nbsp;</p> <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #000000">windump </span><span style="color: #000000">-</span><span style="color: #000000">i </span><span style="color: #000000">2</span><span style="color: #000000"> port </span><span style="color: #000000">4000</span><span style="color: #000000">&nbsp;</span></div> <p style="font-size: 10pt">&nbsp; <p style="font-size: 10pt">那么windump只会显示端口号为4000的网络数据。  <p style="font-size: 10pt"><strong>序号和确认号：</strong>  <p style="font-size: 10pt">要讲解TCP的建立过程，也就是那个所谓的三次握手，就会涉及到序号和确认号这两个东西。翻书到TCP<br>的报文头，有两个很重要的域(都是32位)就是序号域和确认号域。可能有些同学会对TCP那个报文头有所<br>疑惑(能看懂我在讲什么的会产生这样的疑惑么？)，这里我可以告诉你，你可以假想TCP的报文头就是个<br>C语言结构体(假想而已，去翻翻bsd对TCP的实现，肯定没这么简单)，那么大致上，所谓的TCP报文头就是：<br></p> <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #000000">typedef </span><span style="color: #0000ff">struct</span><span style="color: #000000"> _tcp_header<br><img id="Codehighlighter1_27_429_Open_Image" onclick="this.style.display='none'; Codehighlighter1_27_429_Open_Text.style.display='none'; Codehighlighter1_27_429_Closed_Image.style.display='inline'; Codehighlighter1_27_429_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_27_429_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_27_429_Closed_Text.style.display='none'; Codehighlighter1_27_429_Open_Image.style.display='inline'; Codehighlighter1_27_429_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_27_429_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_27_429_Open_Text"><span style="color: #000000">{<br><img id="Codehighlighter1_33_44_Open_Image" onclick="this.style.display='none'; Codehighlighter1_33_44_Open_Text.style.display='none'; Codehighlighter1_33_44_Closed_Image.style.display='inline'; Codehighlighter1_33_44_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_33_44_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_33_44_Closed_Text.style.display='none'; Codehighlighter1_33_44_Open_Image.style.display='inline'; Codehighlighter1_33_44_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp; </span><span id="Codehighlighter1_33_44_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**/</span><span id="Codehighlighter1_33_44_Open_Text"><span style="color: #808080">///</span><span style="color: #008000"> 16位源端口号</span><span style="color: #808080"></span></span><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><span style="color: #000000">&nbsp;&nbsp;&nbsp; unsigned </span><span style="color: #0000ff">short</span><span style="color: #000000"> src_port;<br><img id="Codehighlighter1_78_90_Open_Image" onclick="this.style.display='none'; Codehighlighter1_78_90_Open_Text.style.display='none'; Codehighlighter1_78_90_Closed_Image.style.display='inline'; Codehighlighter1_78_90_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_78_90_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_78_90_Closed_Text.style.display='none'; Codehighlighter1_78_90_Open_Image.style.display='inline'; Codehighlighter1_78_90_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp; </span><span id="Codehighlighter1_78_90_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**/</span><span id="Codehighlighter1_78_90_Open_Text"><span style="color: #808080">///</span><span style="color: #008000"> 16位目的端口号</span><span style="color: #808080"></span></span><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><span style="color: #000000">&nbsp;&nbsp;&nbsp; unsigned </span><span style="color: #0000ff">short</span><span style="color: #000000"> dst_port;<br><img id="Codehighlighter1_124_133_Open_Image" onclick="this.style.display='none'; Codehighlighter1_124_133_Open_Text.style.display='none'; Codehighlighter1_124_133_Closed_Image.style.display='inline'; Codehighlighter1_124_133_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_124_133_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_124_133_Closed_Text.style.display='none'; Codehighlighter1_124_133_Open_Image.style.display='inline'; Codehighlighter1_124_133_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp; </span><span id="Codehighlighter1_124_133_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**/</span><span id="Codehighlighter1_124_133_Open_Text"><span style="color: #808080">///</span><span style="color: #008000"> 32位序号</span><span style="color: #808080"></span></span><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><span style="color: #000000">&nbsp;&nbsp;&nbsp; unsigned </span><span style="color: #0000ff">long</span><span style="color: #000000"> seq_num;<br><img id="Codehighlighter1_165_175_Open_Image" onclick="this.style.display='none'; Codehighlighter1_165_175_Open_Text.style.display='none'; Codehighlighter1_165_175_Closed_Image.style.display='inline'; Codehighlighter1_165_175_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_165_175_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_165_175_Closed_Text.style.display='none'; Codehighlighter1_165_175_Open_Image.style.display='inline'; Codehighlighter1_165_175_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp; </span><span id="Codehighlighter1_165_175_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**/</span><span id="Codehighlighter1_165_175_Open_Text"><span style="color: #808080">///</span><span style="color: #008000"> 32位确认号</span><span style="color: #808080"></span></span><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><span style="color: #000000">&nbsp;&nbsp;&nbsp; unsigned </span><span style="color: #0000ff">long</span><span style="color: #000000"> ack_num;<br><img id="Codehighlighter1_207_244_Open_Image" onclick="this.style.display='none'; Codehighlighter1_207_244_Open_Text.style.display='none'; Codehighlighter1_207_244_Closed_Image.style.display='inline'; Codehighlighter1_207_244_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_207_244_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_207_244_Closed_Text.style.display='none'; Codehighlighter1_207_244_Open_Image.style.display='inline'; Codehighlighter1_207_244_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp; </span><span id="Codehighlighter1_207_244_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**/</span><span id="Codehighlighter1_207_244_Open_Text"><span style="color: #808080">///</span><span style="color: #008000"> 16位标志位[4位首部长度，保留6位，ACK、SYN之类的标志位]</span><span style="color: #808080"></span></span><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><span style="color: #000000">&nbsp;&nbsp;&nbsp; unsigned </span><span style="color: #0000ff">short</span><span style="color: #000000"> flag;<br><img id="Codehighlighter1_274_285_Open_Image" onclick="this.style.display='none'; Codehighlighter1_274_285_Open_Text.style.display='none'; Codehighlighter1_274_285_Closed_Image.style.display='inline'; Codehighlighter1_274_285_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_274_285_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_274_285_Closed_Text.style.display='none'; Codehighlighter1_274_285_Open_Image.style.display='inline'; Codehighlighter1_274_285_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp; </span><span id="Codehighlighter1_274_285_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**/</span><span id="Codehighlighter1_274_285_Open_Text"><span style="color: #808080">///</span><span style="color: #008000"> 16位窗口大小</span><span style="color: #808080"></span></span><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><span style="color: #000000">&nbsp;&nbsp;&nbsp; unsigned </span><span style="color: #0000ff">short</span><span style="color: #000000"> win_size;<br><img id="Codehighlighter1_319_329_Open_Image" onclick="this.style.display='none'; Codehighlighter1_319_329_Open_Text.style.display='none'; Codehighlighter1_319_329_Closed_Image.style.display='inline'; Codehighlighter1_319_329_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_319_329_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_319_329_Closed_Text.style.display='none'; Codehighlighter1_319_329_Open_Image.style.display='inline'; Codehighlighter1_319_329_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp; </span><span id="Codehighlighter1_319_329_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**/</span><span id="Codehighlighter1_319_329_Open_Text"><span style="color: #808080">///</span><span style="color: #008000"> 16位校验和</span><span style="color: #808080"></span></span><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">short</span><span style="color: #000000"> crc_sum;<br><img id="Codehighlighter1_353_364_Open_Image" onclick="this.style.display='none'; Codehighlighter1_353_364_Open_Text.style.display='none'; Codehighlighter1_353_364_Closed_Image.style.display='inline'; Codehighlighter1_353_364_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_353_364_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_353_364_Closed_Text.style.display='none'; Codehighlighter1_353_364_Open_Image.style.display='inline'; Codehighlighter1_353_364_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp; </span><span id="Codehighlighter1_353_364_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**/</span><span id="Codehighlighter1_353_364_Open_Text"><span style="color: #808080">///</span><span style="color: #008000"> 16位紧急指针</span><span style="color: #808080"></span></span><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">short</span><span style="color: #000000"> ptr;<br><img id="Codehighlighter1_384_428_Open_Image" onclick="this.style.display='none'; Codehighlighter1_384_428_Open_Text.style.display='none'; Codehighlighter1_384_428_Closed_Image.style.display='inline'; Codehighlighter1_384_428_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_384_428_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_384_428_Closed_Text.style.display='none'; Codehighlighter1_384_428_Open_Image.style.display='inline'; Codehighlighter1_384_428_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp; </span><span id="Codehighlighter1_384_428_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**/</span><span id="Codehighlighter1_384_428_Open_Text"><span style="color: #808080">///</span><span style="color: #008000"> 可选选项<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top">&nbsp;&nbsp;&nbsp; </span><span style="color: #808080">///</span><span style="color: #008000"> how to implement this ?&nbsp;&nbsp;&nbsp; </span><span style="color: #808080"></span></span><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"><span style="color: #000000">}</span></span><span style="color: #000000"> tcp_header; <br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span></div> <p style="font-size: 10pt"><br>那么，这个序号和确认号是什么？TCP报文为每一个字节都设置一个序号，觉得很奇怪？这里并不是为每一<br>字节附加一个序号(那会是多么可笑的编程手法?)，而是为一个TCP报文附加一个序号，这个序号表示报文<br>中数据的第一个字节的序号，而其他数据则是根据离第一个数据的偏移来决定序号的，例如，现在有数据：<br>abcd。如果这段数据的序号为1200，那么a的序号就是1200，b的序号就是1201。而TCP发送的下一个数据包<br>的序号就会是上一个数据包最后一个字节的序号加一。例如efghi是abcd的下一个数据包，那么它的序号就<br>是1204。通过这种看似简单的方法，TCP就实现了为每一个字节设置序号的功能(终于明白为什么书上要告诉<br>我们‘为每一个字节设置一个序号’了吧?)。注意，设置序号是一种可以让TCP成为’可靠协议‘的手段。<br>TCP中各种乱七八糟的东西都是有目的的，大部分目的还是为了’可靠‘两个字。别把TCP看高深了，如果<br>让你来设计一个网络协议，目的需要告诉你是’可靠的‘，你就会明白为什么会产生那些乱七八糟的东西了。  <p style="font-size: 10pt">接着看，确认号是什么？因为TCP会对接收到的数据包进行确认，发送确认数据包时，就会设置这个确认号，<br>确认号通常表示接收方希望接收到的下一段报文的序号。例如某一次接收方收到序号为1200的4字节数举报，<br>那么它发送确认报文给发送方时，就会设置确认号为1204。  <p style="font-size: 10pt">大部分书上在讲确认号和序号时，都会说确认号是序号加一。这其实有点误解人，所以我才在这里废话了<br>半天(高手宽容下:D)。  <p style="font-size: 10pt"><strong>开始三次握手：</strong>  <p style="font-size: 10pt">如果你还不会简单的tcp socket编程，我建议你先去学学，这就好比你不会C++基本语法，就别去研究vtable<br>之类。  <p style="font-size: 10pt">三次握手开始于客户端试图连接服务器端。当你调用诸如connect的函数时，正常情况下就会开始三次握手。<br>随便在网上找张三次握手的图：  <p style="font-size: 10pt"><a href="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/tcp_EB3/connection.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="210" alt="connection" src="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/tcp_EB3/connection_thumb.jpg" width="458" border="0"></a>  <p style="font-size: 10pt">如前文所述，三次握手也就是产生了三个数据包。客户端主动连接，发送SYN被设置了的报文(注意序号和<br>确认号，因为这里不包含用户数据，所以序号和确认号就是加一减一的关系)。服务器端收到该报文时，正<br>常情况下就发送SYN和ACK被设置了的报文作为确认，以及告诉客户端：我想打开我这边的连接(双工)。客户<br>端于是再对服务器端的SYN进行确认，于是再发送ACK报文。然后连接建立完毕。对于阻塞式socket而言，你<br>的connect可能就返回成功给你。  <p style="font-size: 10pt">在进行了铺天盖地的罗利巴索的基础概念的讲解后，看看这个连接建立的过程，是不是简单得几近无聊？  <p style="font-size: 10pt">我们来实际点，写个最简单的客户端代码：<br></p> <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #000000">&nbsp;&nbsp; sockaddr_in addr;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp; memset( </span><span style="color: #000000">&amp;</span><span style="color: #000000">addr, </span><span style="color: #000000">0</span><span style="color: #000000">, </span><span style="color: #0000ff">sizeof</span><span style="color: #000000">( addr ) );<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp; addr.sin_family </span><span style="color: #000000">=</span><span style="color: #000000"> AF_INET;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp; addr.sin_port </span><span style="color: #000000">=</span><span style="color: #000000"> htons( </span><span style="color: #000000">80</span><span style="color: #000000"> );<br><img id="Codehighlighter1_129_146_Open_Image" onclick="this.style.display='none'; Codehighlighter1_129_146_Open_Text.style.display='none'; Codehighlighter1_129_146_Closed_Image.style.display='inline'; Codehighlighter1_129_146_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_129_146_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_129_146_Closed_Text.style.display='none'; Codehighlighter1_129_146_Open_Image.style.display='inline'; Codehighlighter1_129_146_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top">&nbsp;&nbsp;&nbsp; </span><span id="Codehighlighter1_129_146_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**/</span><span id="Codehighlighter1_129_146_Open_Text"><span style="color: #808080">///</span><span style="color: #008000"> 220.181.37.55</span><span style="color: #808080"></span></span><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #000000">&nbsp;&nbsp;&nbsp; addr.sin_addr.s_addr </span><span style="color: #000000">=</span><span style="color: #000000"> inet_addr( </span><span style="color: #000000">"</span><span style="color: #000000">220.181.37.55</span><span style="color: #000000">"</span><span style="color: #000000"> );<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp; printf( </span><span style="color: #000000">"</span><span style="color: #000000">%s : connecting to server.\n</span><span style="color: #000000">"</span><span style="color: #000000">, _str_time() );<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">int</span><span style="color: #000000"> err </span><span style="color: #000000">=</span><span style="color: #000000"> connect( s, (sockaddr</span><span style="color: #000000">*</span><span style="color: #000000">) </span><span style="color: #000000">&amp;</span><span style="color: #000000">addr, </span><span style="color: #0000ff">sizeof</span><span style="color: #000000">( addr ) ); <br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span></div> <p style="font-size: 10pt">&nbsp;<br>主要就是connect。运行程序前我们运行windump：  <p style="font-size: 10pt">&nbsp;</p> <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #000000">windump </span><span style="color: #000000">-</span><span style="color: #000000">i </span><span style="color: #000000">2</span><span style="color: #000000"> host </span><span style="color: #000000">220.181</span><span style="color: #000000">.</span><span style="color: #000000">37.55</span><span style="color: #000000">&nbsp;</span></div> <p style="font-size: 10pt">&nbsp;</p> <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #000000">00</span><span style="color: #000000">:</span><span style="color: #000000">38</span><span style="color: #000000">:</span><span style="color: #000000">22.979229</span><span style="color: #000000"> IP noname.domain.</span><span style="color: #000000">4397</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">220.181</span><span style="color: #000000">.</span><span style="color: #000000">37.55</span><span style="color: #000000">.</span><span style="color: #000000">80</span><span style="color: #000000">: S </span><span style="color: #000000">2523219966</span><span style="color: #000000">:</span><span style="color: #000000">2523219966</span><span style="color: #000000">(</span><span style="color: #000000">0</span><span style="color: #000000">) win </span><span style="color: #000000">65535</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">mss </span><span style="color: #000000">1460</span><span style="color: #000000">,nop,nop,sackOK</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #000000">00</span><span style="color: #000000">:</span><span style="color: #000000">38</span><span style="color: #000000">:</span><span style="color: #000000">23.024254</span><span style="color: #000000"> IP </span><span style="color: #000000">220.181</span><span style="color: #000000">.</span><span style="color: #000000">37.55</span><span style="color: #000000">.</span><span style="color: #000000">80</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000"> noname.domain.</span><span style="color: #000000">4397</span><span style="color: #000000">: S </span><span style="color: #000000">1277008647</span><span style="color: #000000">:</span><span style="color: #000000">1277008647</span><span style="color: #000000">(</span><span style="color: #000000">0</span><span style="color: #000000">) ack </span><span style="color: #000000">2523219967</span><span style="color: #000000"> win </span><span style="color: #000000">2920</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">mss </span><span style="color: #000000">1440</span><span style="color: #000000">,nop,nop,sackOK</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #000000">00</span><span style="color: #000000">:</span><span style="color: #000000">38</span><span style="color: #000000">:</span><span style="color: #000000">23.024338</span><span style="color: #000000"> IP noname.domain.</span><span style="color: #000000">4397</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">220.181</span><span style="color: #000000">.</span><span style="color: #000000">37.55</span><span style="color: #000000">.</span><span style="color: #000000">80</span><span style="color: #000000">: . ack </span><span style="color: #000000">1</span><span style="color: #000000"> win </span><span style="color: #000000">65535</span><span style="color: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span></div> <p style="font-size: 10pt">&nbsp; <p style="font-size: 10pt">如何分析windump的结果，建议参看&lt;tcp/ip详解&gt;中对于tcpdump的描述。  <p style="font-size: 10pt"><strong>建立连接的附加信息：</strong>  <p style="font-size: 10pt">虽然SYN、ACK之类的报文没有用户数据，但是TCP还是附加了其他信息。最为重要的就是附加的MSS值。这个<br>可以被协商的MSS值基本上就只在建立连接时协商。如以上数据表示，MSS为1460字节。  <p style="font-size: 10pt"><strong>连接的意外：</strong>  <p style="font-size: 10pt">连接的意外我大致分为两种情况(也许还有更多情况)：目的主机不可达、目的主机并没有在指定端口监听。<br>当目的主机不可达时，也就是说，SYN报文段根本无法到达对方(如果你的机器根本没插网线，你就不可达)，<br>那么TCP收不到任何回复报文。这个时候，你会看到TCP中的定时器机制出现了。TCP对发出的SYN报文进行<br>计时，当在指定时间内没有得到回复报文时，TCP就会重传刚才的SYN报文。通常，各种不同的TCP实现对于<br>这个超时值都不同，但是据我观察，重传次数基本上都是3次。例如，我连接一个不可达的主机：  <p style="font-size: 10pt">&nbsp;</p> <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #000000">12</span><span style="color: #000000">:</span><span style="color: #000000">39</span><span style="color: #000000">:</span><span style="color: #000000">50.560690</span><span style="color: #000000"> IP cd</span><span style="color: #000000">-</span><span style="color: #000000">zhangmin.</span><span style="color: #000000">1573</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">220.181</span><span style="color: #000000">.</span><span style="color: #000000">37.55</span><span style="color: #000000">.</span><span style="color: #000000">1024</span><span style="color: #000000">: S </span><span style="color: #000000">3117975575</span><span style="color: #000000">:</span><span style="color: #000000">3117975575</span><span style="color: #000000">(</span><span style="color: #000000">0</span><span style="color: #000000">) win </span><span style="color: #000000">65535</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">mss </span><span style="color: #000000">1460</span><span style="color: #000000">,nop,nop,sackOK</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #000000">12</span><span style="color: #000000">:</span><span style="color: #000000">39</span><span style="color: #000000">:</span><span style="color: #000000">53.538734</span><span style="color: #000000"> IP cd</span><span style="color: #000000">-</span><span style="color: #000000">zhangmin.</span><span style="color: #000000">1573</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">220.181</span><span style="color: #000000">.</span><span style="color: #000000">37.55</span><span style="color: #000000">.</span><span style="color: #000000">1024</span><span style="color: #000000">: S </span><span style="color: #000000">3117975575</span><span style="color: #000000">:</span><span style="color: #000000">3117975575</span><span style="color: #000000">(</span><span style="color: #000000">0</span><span style="color: #000000">) win </span><span style="color: #000000">65535</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">mss </span><span style="color: #000000">1460</span><span style="color: #000000">,nop,nop,sackOK</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #000000">12</span><span style="color: #000000">:</span><span style="color: #000000">39</span><span style="color: #000000">:</span><span style="color: #000000">59.663726</span><span style="color: #000000"> IP cd</span><span style="color: #000000">-</span><span style="color: #000000">zhangmin.</span><span style="color: #000000">1573</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">220.181</span><span style="color: #000000">.</span><span style="color: #000000">37.55</span><span style="color: #000000">.</span><span style="color: #000000">1024</span><span style="color: #000000">: S </span><span style="color: #000000">3117975575</span><span style="color: #000000">:</span><span style="color: #000000">3117975575</span><span style="color: #000000">(</span><span style="color: #000000">0</span><span style="color: #000000">) win </span><span style="color: #000000">65535</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">mss </span><span style="color: #000000">1460</span><span style="color: #000000">,nop,nop,sackOK</span><span style="color: #000000">&gt;</span></div> <p style="font-size: 10pt">&nbsp; <p style="font-size: 10pt">发出了三个序号一样的SYN报文，但是没有得到一个回复报文(废话)。每一个SYN报文之间的间隔时间都是<br>有规律的，在windows上是3秒6秒9秒12秒。上面的数据你看不到12秒这个数据，因为这是第三个报文发出的<br>时间和connect返回错误信息时的时间之差。另一方面，如果连接同一个网络，这个间隔时间又不同。例如<br>直接连局域网，间隔时间就差不多为500ms。  <p style="font-size: 10pt">(我强烈建议你能运行windump去试验这里提到的每一个现象，如果你在ubuntu下使用tcpdump，记住sudo :D)  <p style="font-size: 10pt">出现意外的第二种情况是如果主机数据包可达，但是试图连接的端口根本没有监听，那么发送SYN报文的这<br>方会收到RST被设置的报文(connect也会返回相应的信息给你)，例如：  <p style="font-size: 10pt">&nbsp;</p> <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #000000">13</span><span style="color: #000000">:</span><span style="color: #000000">37</span><span style="color: #000000">:</span><span style="color: #000000">22.202532</span><span style="color: #000000"> IP cd</span><span style="color: #000000">-</span><span style="color: #000000">zhangmin.</span><span style="color: #000000">1658</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000"> 7AURORA</span><span style="color: #000000">-</span><span style="color: #000000">CCTEST.</span><span style="color: #000000">7100</span><span style="color: #000000">: S </span><span style="color: #000000">2417354281</span><span style="color: #000000">:</span><span style="color: #000000">2417354281</span><span style="color: #000000">(</span><span style="color: #000000">0</span><span style="color: #000000">) win </span><span style="color: #000000">65535</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">mss </span><span style="color: #000000">1460</span><span style="color: #000000">,nop,nop,sackOK</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #000000">13</span><span style="color: #000000">:</span><span style="color: #000000">37</span><span style="color: #000000">:</span><span style="color: #000000">22.202627</span><span style="color: #000000"> IP 7AURORA</span><span style="color: #000000">-</span><span style="color: #000000">CCTEST.</span><span style="color: #000000">7100</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000"> cd</span><span style="color: #000000">-</span><span style="color: #000000">zhangmin.</span><span style="color: #000000">1658</span><span style="color: #000000">: R </span><span style="color: #000000">0</span><span style="color: #000000">:</span><span style="color: #000000">0</span><span style="color: #000000">(</span><span style="color: #000000">0</span><span style="color: #000000">) ack </span><span style="color: #000000">2417354282</span><span style="color: #000000"> win </span><span style="color: #000000">0</span><span style="color: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #000000">13</span><span style="color: #000000">:</span><span style="color: #000000">37</span><span style="color: #000000">:</span><span style="color: #000000">22.711415</span><span style="color: #000000"> IP cd</span><span style="color: #000000">-</span><span style="color: #000000">zhangmin.</span><span style="color: #000000">1658</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000"> 7AURORA</span><span style="color: #000000">-</span><span style="color: #000000">CCTEST.</span><span style="color: #000000">7100</span><span style="color: #000000">: S </span><span style="color: #000000">2417354281</span><span style="color: #000000">:</span><span style="color: #000000">2417354281</span><span style="color: #000000">(</span><span style="color: #000000">0</span><span style="color: #000000">) win </span><span style="color: #000000">65535</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">mss </span><span style="color: #000000">1460</span><span style="color: #000000">,nop,nop,sackOK</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #000000">13</span><span style="color: #000000">:</span><span style="color: #000000">37</span><span style="color: #000000">:</span><span style="color: #000000">22.711498</span><span style="color: #000000"> IP 7AURORA</span><span style="color: #000000">-</span><span style="color: #000000">CCTEST.</span><span style="color: #000000">7100</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000"> cd</span><span style="color: #000000">-</span><span style="color: #000000">zhangmin.</span><span style="color: #000000">1658</span><span style="color: #000000">: R </span><span style="color: #000000">0</span><span style="color: #000000">:</span><span style="color: #000000">0</span><span style="color: #000000">(</span><span style="color: #000000">0</span><span style="color: #000000">) ack </span><span style="color: #000000">1</span><span style="color: #000000"> win </span><span style="color: #000000">0</span><span style="color: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #000000">13</span><span style="color: #000000">:</span><span style="color: #000000">37</span><span style="color: #000000">:</span><span style="color: #000000">23.367733</span><span style="color: #000000"> IP cd</span><span style="color: #000000">-</span><span style="color: #000000">zhangmin.</span><span style="color: #000000">1658</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000"> 7AURORA</span><span style="color: #000000">-</span><span style="color: #000000">CCTEST.</span><span style="color: #000000">7100</span><span style="color: #000000">: S </span><span style="color: #000000">2417354281</span><span style="color: #000000">:</span><span style="color: #000000">2417354281</span><span style="color: #000000">(</span><span style="color: #000000">0</span><span style="color: #000000">) win </span><span style="color: #000000">65535</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">mss </span><span style="color: #000000">1460</span><span style="color: #000000">,nop,nop,sackOK</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #000000">13</span><span style="color: #000000">:</span><span style="color: #000000">37</span><span style="color: #000000">:</span><span style="color: #000000">23.367826</span><span style="color: #000000"> IP 7AURORA</span><span style="color: #000000">-</span><span style="color: #000000">CCTEST.</span><span style="color: #000000">7100</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000"> cd</span><span style="color: #000000">-</span><span style="color: #000000">zhangmin.</span><span style="color: #000000">1658</span><span style="color: #000000">: R </span><span style="color: #000000">0</span><span style="color: #000000">:</span><span style="color: #000000">0</span><span style="color: #000000">(</span><span style="color: #000000">0</span><span style="color: #000000">) ack </span><span style="color: #000000">1</span><span style="color: #000000"> win </span><span style="color: #000000">0</span><span style="color: #000000">&nbsp;</span></div> <p style="font-size: 10pt">&nbsp; <p style="font-size: 10pt">可以看出，7AURORA-CCTEST.7100返回了RST报文给我，但是我这边根本不在乎这个报文，继续发送SYN报文。<br>三次过后connect就返回了。(数据反映的事实是这样)  <p style="font-size: 10pt"><strong>关于listen:</strong> <p style="font-size: 10pt">TCP服务器端会维护一个新连接的队列。当新连接上的客户端三次握手完成时，就会将其放入这个队列。这个队 <p style="font-size: 10pt">列的大小是通过listen设置的。当这个队列满时，如果有新的客户端试图连接（发送SYN），服务器端丢弃报文， <p style="font-size: 10pt">同时不做任何回复。 <p style="font-size: 10pt"><strong>总结：</strong><br>TCP连接的建立的相关要点就是这些(or more?)。正常情况下就是三次握手，非正常情况下就是SYN三次超时，<br>以及收到RST报文却被忽略。 </p><img src ="http://www.cppblog.com/kevinlynx/aggbug/49482.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-05-11 01:03 <a href="http://www.cppblog.com/kevinlynx/archive/2008/05/11/49482.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>lua和python谁更适用于嵌入MMORPG？</title><link>http://www.cppblog.com/kevinlynx/archive/2008/05/06/49023.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Tue, 06 May 2008 09:37:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/05/06/49023.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/49023.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/05/06/49023.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/49023.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/49023.html</trackback:ping><description><![CDATA[<p>&nbsp;</p> <p>预计新项目会选择lua或python之一作为游戏的脚本语言。以前草草地接触过这两门语言，对于语法，以及嵌入进C/C++程序都有点感性上的认识。可能是受《UNIX编程艺术》中KISS原则的影响，现在总喜欢简洁的东西。所以我个人比较偏向于使用lua。</p> <p>&nbsp;</p> <p>这两天翻了下网络上的资料，在lua的wiki上看到一篇比较lua和python的<a href="http://lua-users.org/wiki/LuaVersusPython">文章</a>，草草地翻译出要点：</p> <p>Python:<br>1. 扩展库很多，资料很多<br>2. 数值计算比较强大，支持多维数组，而lua没有数组类型<br>3. 本身带的c类型(?)支持处理动态链接库，不需要进行C封装(C扩展)<br>4. 远程调试器，似乎lua扩展工具支持<br>5. 自然语言似的语法<br>6. 对于string和list的支持，lua可以通过扩展库实现<br>7. 对unicode的支持<br>8. 空格敏感(代码不忽略空格)，这其实可以使python的代码风格看起来更好一点<br>9. 内建位操作，lua可以通过扩展库支持<br>10.语言本身对错误的处理要好些，可以有效减少程序错误<br>11.初级文档比lua多<br>12.对面向对象支持更好  <p>Lua:<br>1. 比python小巧很多(包括编译出来的运行时库)<br>2. 占用更小的内存<br>3. 解释器速度更快<br>4. 比python更容易集成到C语言中<br>5. 对于对象不使用引用计数(引用计数会导致更多的问题？)<br>6. lua早期定位于一种配置语言(作为配置文件)，因此比起python来更容易配置数据<br>7. 语言更漂亮(nice)、简单(simple)、强大(powerful)。<br>8. lua支持多线程，每个线程可以配置独立的解释器，因此lua更适合于集成进多线程程序<br>9. 对空格不敏感，不用担心编辑器会将tab替换成空格  <p>Useful Comments:<br>1. Everything is an object allocated on the heap in Python, including numbers. (So 123+456 creates a new heap object).<br>2. lua对于coroutine的支持更适用于嵌入进游戏，虽然python也有，但是并没有包含进核心模块  <p>3.Python was a language better suited to Game AI</p> <p>&nbsp;</p> <p>本来想去找点对于python的正面资料(嵌入进游戏这方面），但是居然没找到。客观地说如果单独用python做应用，python还是很有优势。现在心意已决，应该向leader推荐lua。</p> <p>&nbsp;</p> <p>ps，希望能补充以上两种语言的特点。</p><img src ="http://www.cppblog.com/kevinlynx/aggbug/49023.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-05-06 17:37 <a href="http://www.cppblog.com/kevinlynx/archive/2008/05/06/49023.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TCP/IP Concepts 1</title><link>http://www.cppblog.com/kevinlynx/archive/2008/04/18/47471.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Fri, 18 Apr 2008 02:02:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/04/18/47471.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/47471.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/04/18/47471.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/47471.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/47471.html</trackback:ping><description><![CDATA[<p><br><font style="FONT-SIZE: 10pt; BACKGROUND-COLOR: #ffffff">最近在草草地看&lt;TCP/IP详解&gt;TCP那一部分，之所以草草地看是因为觉得早晚一天会回过头去细看。手头上<br>有工作要做，所以先草草地把之前随便摘抄的TCP/IP相关概念贴出来：<br><br>继续草草地贴:<br><br>--------------------------------------------------------------------------------------------------------------------------------------------------------<br>TCP segment:<br>Thus, we have simply &#8220;passed the buck&#8221; to TCP, which must take the stream from the application <br>and divide it into discrete messages for IP. These messages are called TCP segments.</font></p>
<p><font style="FONT-SIZE: 10pt; BACKGROUND-COLOR: #ffffff">On regular intervals, it forms segments to be transmitted using IP. The size of the segment is <br>controlled by two primary factors. The first issue is that there is an overall limit to the size <br>of a segment, chosen to prevent unnecessary fragmentation at the IP layer. This is governed by a <br>parameter called the maximum segment size (MSS), which is determined during connection establishment. <br>The second is that TCP is designed so that once a connection is set up, each of the devices tells the <br>other how much data it is ready to accept at any given time. If this is lower than the MSS value, a <br>smaller segment must be sent. This is part of the sliding window system described in the next topic.</font></p>
<p><font style="FONT-SIZE: 10pt; BACKGROUND-COLOR: #ffffff">Since TCP works with individual bytes of data rather than discrete messages, it must use an <br>identification scheme that works at the byte level to implement its data transmission and tracking <br>system. This is accomplished by assigning each byte TCP processes a sequence number.</font></p>
<p><font style="FONT-SIZE: 10pt; BACKGROUND-COLOR: #ffffff"><br>Since applications send data to TCP as a stream of bytes and not prepackaged messages, each <br>application must use its own scheme to determine where one application data element ends and the <br>next begins.<br><br>--------------------------------------------------------------------------------------------------------------------------------------------------------<br></p>
<p>TCP MSS:<br><a href="http://www.tcpipguide.com/free/t_TCPMaximumSegmentSizeMSSandRelationshiptoIPDatagra.htm">http://www.tcpipguide.com/free/t_TCPMaximumSegmentSizeMSSandRelationshiptoIPDatagra.htm</a></p>
<p>In addition to the dictates of the current window size, each TCP device also has associated <br>with it a ceiling on TCP size—a segment size that will never be exceeded regardless of how<br>&nbsp;large the current window is. This is called the maximum segment size (MSS). When deciding <br>how much data to put into a segment, each device in the TCP connection will choose the amount<br>&nbsp;based on the current window size, in conjunction with the various algorithms described in <br>the reliability section, but it will never be so large that the amount of data exceeds the<br>&nbsp;MSS of the device to which it is sending. </p>
<p><br>Note: I need to point out that the name &#8220;maximum segment size&#8221; is in fact misleading. The<br>&nbsp;value actually refers to the maximum amount of data that a segment can hold—it does not <br>include the TCP headers. So if the MSS is 100, the actual maximum segment size could be 120 <br>(for a regular TCP header) or larger (if the segment includes TCP options). </p>
<p>This was computed by starting with the minimum MTU for IP networks of 576. </p>
<p>Devices can indicate that they wish to use a different MSS value from the default by including <br>a Maximum Segment Size option in the SYN message they use to establish a connection. Each <br>device in the connection may use a different MSS value.<br><br>--------------------------------------------------------------------------------------------------------------------------------------------------------<br><br>delayed ACK algorithm<br><br><a href="http://tangentsoft.net/wskfaq/intermediate.html#delayed-ack">http://tangentsoft.net/wskfaq/intermediate.html#delayed-ack</a></p>
<p>In a simpleminded implementation of TCP, every data packet that comes in is immediately acknowledged<br>&nbsp;with an ACK packet. (ACKs help to provide the reliability TCP promises.)</p>
<p>In modern stacks, ACKs are delayed for a short time (up to 200ms, typically) for three reasons: a) <br>to avoid the silly window syndrome; b) to allow ACKs to piggyback on a reply frame if one is ready <br>to go when the stack decides to do the ACK; and c) to allow the stack to send one ACK for several <br>frames, if those frames arrive within the delay period.</p>
<p>The stack is only allowed to delay ACKs for up to 2 frames of data.</p>
<p><br>&nbsp;</p>
<p>--------------------------------------------------------------------------------------------------------------------------------------------------------<br>Nagle algorithm:</p>
<p>Nagle's algorithm, named after John Nagle, is a means of improving the efficiency of TCP/IP networks by reducing the number of packets that need to be sent over the network.</p>
<p>Nagle's document, Congestion Control in IP/TCP Internetworks (RFC896) describes what he called the 'small packet problem', where an application repeatedly emits data in small chunks, frequently only 1 byte in size. Since TCP packets have a 40 byte header (20 bytes for TCP, 20 bytes for IPv4), this results in a 41 byte packet for 1 byte of useful information, a huge overhead. This situation often occurs in Telnet sessions, where most keypresses generate a single byte of data which is transmitted immediately. Worse, over slow links, many such packets can be in transit at the same time, potentially leading to congestion collapse.</p>
<p>Nagle's algorithm works by coalescing a number of small outgoing messages, and sending them all at once. Specifically, as long as there is a sent packet for which the sender has received no acknowledgment, the sender should keep buffering its output until it has a full packet's worth of output, so that output can be sent all at once.</p>
<p><br>[edit] Algorithm<br>if there is new data to send<br>&nbsp; if the window size &gt;= MSS and available data is &gt;= MSS<br>&nbsp;&nbsp;&nbsp; send complete MSS segment now<br>&nbsp; else<br>&nbsp;&nbsp;&nbsp; if there is unconfirmed data still in the pipe<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enqueue data in the buffer until an acknowledge is received<br>&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; send data immediately<br>&nbsp;&nbsp;&nbsp; end if<br>&nbsp; end if<br>end if<br>where MSS = Maximum segment size</p>
<p>This algorithm interacts badly with TCP delayed acknowledgments, a feature introduced into TCP at roughly the same time in the early 1980s, but by a different group. With both algorithms enabled, applications which do two successive writes to a TCP connection, followed by a read, experience a constant delay of up to 500 milliseconds, the "ACK delay". For this reason, TCP implementations usually provide applications with an interface to disable the Nagle algorithm. This is typically called the TCP_NODELAY option. The first major application to run into this problem was the X Window System.</p>
<p>The tinygram problem and silly window syndrome are sometimes confused. The tinygram problem occurs when the window is almost empty. Silly window syndrome occurs when the window is almost full</p>
<p>===================================================================================================================================<br>3.17 - What is the Nagle algorithm?<br>The Nagle algorithm is an optimization to TCP that makes the stack wait until all data is acknowledged on the connection before it sends more data. The exception is that Nagle will not cause the stack to wait for an ACK if it has enough enqueued data that it can fill a network frame. (Without this exception, the Nagle algorithm would effectively disable TCP's sliding window algorithm.) For a full description of the Nagle algorithm, see RFC 896.</p>
<p>So, you ask, what's the purpose of the Nagle algorithm?</p>
<p>The ideal case in networking is that each program always sends a full frame of data with each call to send(). That maximizes the percentage of useful program data in a packet.</p>
<p>The basic TCP and IPv4 headers are 20 bytes each. The worst case protocol overhead percentage, therefore, is 40/41, or 98%. Since the maximum amount of data in an Ethernet frame is 1500 bytes, the best case protocol overhead percentage is 40/1500, less than 3%.</p>
<p>While the Nagle algorithm is causing the stack to wait for data to be ACKed by the remote peer, the local program can make more calls to send(). Because TCP is a stream protocol, it can coalesce the data in those send() calls into a single TCP packet, increasing the percentage of useful data.</p>
<p>Imagine a simple Telnet program: the bulk of a Telnet conversation consists of sending one character, and receiving an echo of that character back from the remote host. Without the Nagle algorithm, this results in TCP's worst case: one byte of user data wrapped in dozens of bytes of protocol overhead. With the Nagle algorithm enabled, the TCP stack won't send that one Telnet character out until the previous characters have all been acknowledged. By then, the user may well have typed another character or two, reducing the relative protocol overhead.</p>
<p>This simple optimization interacts with other features of the TCP protocol suite, too:</p>
<p>Most stacks implement the delayed ACK algorithm: this causes the remote stack to delay ACKs under certain circumstances, which allows the local stack a bit of time to "Nagle" some more bytes into a single packet. </p>
<p>The Nagle algorithm tends to improve the percentage of useful data in packets more on slow networks than on fast networks, because ACKs take longer to come back. </p>
<p>TCP allows an ACK packet to also contain data. If the local stack decides it needs to send out an ACK packet and the Nagle algorithm has caused data to build up in the output buffer, the enqueued data will go out along with the ACK packet. <br>The Nagle algorithm is on by default in Winsock, but it can be turned off on a per-socket basis with the TCP_NODELAY option of setsockopt(). This option should not be turned off except in a very few situations.</p>
<p>Beware of depending on the Nagle algorithm too heavily. send() is a kernel function, so every call to send() takes much more time than for a regular function call. Your application should coalesce its own data as much as is practical to minimize the number of calls to send().</p>
<p><br>--------------------------------------------------------------------------------------------------------------------------------------------------------<br><br>Sliding Window Acknowledgment System :<br><a href="http://www.tcpipguide.com/free/t_TCPSlidingWindowAcknowledgmentSystemForDataTranspo.htm">http://www.tcpipguide.com/free/t_TCPSlidingWindowAcknowledgmentSystemForDataTranspo.htm</a><br>--------------------------------------------------------------------------------------------<br>A basic technique for ensuring reliability in communications uses a rule that requires a <br>device to send back an acknowledgment each time it successfully receives a transmission. <br>If a transmission is not acknowledged after a period of time, it is retransmitted by its <br>sender. This system is called positive acknowledgment with retransmission (PAR). One<br>&nbsp;drawback with this basic scheme is that the transmitter cannot send a second message <br>until the first has been acknowledged.<br>--------------------------------------------------------------------------------------------</p>
<p><a href="http://www.ssfnet.org/Exchange/tcp/tcpTutorialNotes.html">http://www.ssfnet.org/Exchange/tcp/tcpTutorialNotes.html</a></p>
<p>The sliding window serves several purposes:<br>(1) it guarantees the reliable delivery of data<br>(2) it ensures that the data is delivered in order,<br>(3) it enforces flow control between the sender and the receiver.</p>
<p><br><br><br>------------------to be continued<br></p>
</font>
<img src ="http://www.cppblog.com/kevinlynx/aggbug/47471.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-04-18 10:02 <a href="http://www.cppblog.com/kevinlynx/archive/2008/04/18/47471.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WoW服务器模拟器Ascent网络模块分析</title><link>http://www.cppblog.com/kevinlynx/archive/2008/04/02/46097.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Wed, 02 Apr 2008 13:22:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/04/02/46097.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/46097.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/04/02/46097.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/46097.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/46097.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 10pt">Ascent网络模块<o:p></o:p></p>
<p style="FONT-SIZE: 10pt">Author: Kevin Lynx</p>
<p style="FONT-SIZE: 10pt"><o:p>&nbsp;</o:p></p>
<p style="FONT-SIZE: 10pt">Ascent是WoW的服务器模拟器，你可以从<a href="http://wiki.ascentemu.com/index.php?title=Checkout">它的SVN</a>上获取它的全部代码，并从它的WIKI页面获取架构起整个服务器的相关步骤。</p>
<p style="FONT-SIZE: 10pt"><strong>基本架构：<o:p></o:p></strong></p>
<p style="FONT-SIZE: 10pt">Ascent网络模块核心的几个类关系如下图所示：<br></p>
<p style="FONT-SIZE: 10pt"><img height=275 alt="" src="http://www.cppblog.com/images/cppblog_com/kevinlynx/ascent_net.jpg" width=403 border=0><br><v:shapetype id=_x0000_t75 stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><v:shape id=_x0000_i1025 o:ole="" type="#_x0000_t75"><v:imagedata o:title="" src="file:///C:\DOCUME~1\zhangmin\LOCALS~1\Temp\msohtmlclip1\01\clip_image001.emz"></v:imagedata></v:shape></p>
<p style="FONT-SIZE: 10pt">ThreadBase属于Ascent线程池模块中的类，它实现了一个job类，当其被加入到线程池中开始执行时，线程池管理器会为其分配一个线程（如果有线程资源）并多态调用到ThreadBase派生类的run函数。</p>
<p style="FONT-SIZE: 10pt">SocketWorkerThread用以代表IOCP网络模型中的一个工作者线程，它会从IOCP结果队列里取出异步IO的操作结果。这里的IOCP使用的完成键是Socket对象指针。SocketWorkerThread获取到IO操作结果后，根据获得的完成键将结果通知给具体的Socket对象。（Socket的说明见后面）</p>
<p style="FONT-SIZE: 10pt">ListenSocket代表一个监听套接字。该网络模块其实只是简单地将socket中的概念加以封装。也就说，它依然把一个套接字分为两种类型：监听套接字和数据套接字（代表一个网络连接）。所谓的监听套接字，是指只可以在该套接字上进行监听操作；而数据套接字则只可以在此套接字上进行发送、接收数据的操作。</p>
<p style="FONT-SIZE: 10pt">Socket代表我上面说的数据套接字。ListenSocket是一个类模板，为这个模板指定的模板参数通常是派生于Socket的类。其实这里使用了这个小技巧隐藏了工厂模式的细节。因为ListenSocket被放在一个单独的线程里运作，当其接受到一个新的网络连接时，就创建一个Socket派生类对象。（ListenSocket类如何知道这个派生类的类名？这就是通过类模板的那个模板参数）</p>
<p style="FONT-SIZE: 10pt">上层模块通常会派生Socket类，实现一些IO操作的回调。也就说，当某个IO操作完成后，会通过Socket基类让上层模块获取通知。</p>
<p style="FONT-SIZE: 10pt">SocketMgr是一个全局单件类。它主要负责一些网络库的全局操作（例如winsock库的初始化），它还维护了一个容器，保存所有的Socket对象。这其实是它的主要作用。</p>
<p style="FONT-SIZE: 10pt"><strong>运作之一，接收新的连接</strong>：<o:p></o:p></p>
<p style="FONT-SIZE: 10pt">接收新的网络连接是通过ListenSocket实现的。在创建一个ListenSocket对象时，你需要指定它的模板参数。这个参数通常是一个派生于Socket的类。如下：</p>
<p style="FONT-SIZE: 10pt" align=left>ascent-logonserver/Main.cpp<o:p></o:p></p>
<p style="FONT-SIZE: 10pt" align=left>&nbsp;&nbsp;&nbsp;&nbsp; </p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">ListenSocket</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">AuthSocket</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;cl&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;ListenSocket</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">AuthSocket</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(host.c_str(),&nbsp;cport);</span></div>
<p style="FONT-SIZE: 10pt" align=left>&nbsp;</p>
<p style="FONT-SIZE: 10pt">AuthSocket派生于Socket。创建ListenSocket时构造函数指定监听IP和监听端口。</p>
<p style="FONT-SIZE: 10pt"><o:p>&nbsp;</o:p></p>
<p style="FONT-SIZE: 10pt">因为ListenSocket派生于ThreadBase，属于线程池job，因此要让ListenSocket工作起来，只需要将其加入到线程池管理器：</p>
<p style="FONT-SIZE: 10pt" align=left>ascent-logonserver/Main.cpp<o:p></o:p></p>
<p style="FONT-SIZE: 10pt"><o:p>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">ThreadPool.ExecuteTask(cl);</span></div>
<p style="FONT-SIZE: 10pt"></o:p><o:p>&nbsp;</o:p></p>
<p style="FONT-SIZE: 10pt">ListenSocket开始运作起来后，会阻塞式地WSAAccept。如果WSAAccept返回一个有效的套接字，ListenSocket就创建一个Socket派生类对象（类型由模板参数指定），在上面举的例子中，也就是AuthSocket：</p>
<p style="FONT-SIZE: 10pt">ascent-logonserver/ ListenSocketWin32.h</p>
<p style="FONT-SIZE: 10pt" align=left>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;socket&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;T(aSocket);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">创建AuthSocket并保存网络套接字aSocket</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;socket</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">SetCompletionPort(m_cp);</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">保存完成端口对象</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;socket</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Accept(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">m_tempAddress);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">关联到完成端口等<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p style="FONT-SIZE: 10pt" align=left>Accept函数最终会将新创建的Socket对象保存到SocketMgr对象内部维护的容器里。在这里，还会回调到上层模块的OnConnect函数，从而实现信息捕获。</p>
<p style="FONT-SIZE: 10pt"><strong>运作之二，接收数据<o:p></o:p></strong></p>
<p style="FONT-SIZE: 10pt">在windows平台下，该网络模块使用的是IOCP模型，属于异步IO。当接收新的连接时，即发出WSARecv的IO操作。在工作者线程中，也就是SocketWorkerThread中，会根据IOCP完成键得到Socket对象指针，然后根据不同的IO操作结果多态回调到Socket派生类对应的函数。例如如果是WSARecv完成，则调用到AuthSocket::OnRead函数（上述例子）。OnRead函数直接可以获取到保存数据的缓冲区指针。事实上，每一个Socket对象在被创建时，就会自动创建接收缓冲区以及发送缓冲区。</p>
<p style="FONT-SIZE: 10pt"><strong>运作之三，发送数据<o:p></o:p></strong></p>
<p style="FONT-SIZE: 10pt">分析到这里，我们可以看出，该网络模块实现得很一般。在接受数据部分，网络工作者线程回调到对应的Socket对象，Socket直接对数据进行上层逻辑处理。更好的做法是当工作者线程回调到上层Socket（Socket的派生类）时，这里应该简单地将数据组织成上层数据包并放入上层数据包队列，让上层逻辑稍后处理，而不是让网络模块自己去处理。这样做主要是考虑到多线程模型。</p>
<p style="FONT-SIZE: 10pt">同样，该网络模块的发送模块也是一样，没有缓冲机制。当要发送数据时，直接调用到Socket的Send函数。该函数拷贝用户数据到自己维护的发送缓冲区，然后将自己的缓冲区指针直接提交给IOCP，WSASend发送。</p>
<p style="FONT-SIZE: 10pt"><o:p>&nbsp;</o:p></p>
<p style="FONT-SIZE: 10pt"><strong>结束<o:p></o:p></strong></p>
<p style="FONT-SIZE: 10pt">该网络模块实现的似乎有点简陋，在该模块之上也没有数据校验、数据加密的模块（这些动作散乱地分布在最上层逻辑）。在架构上也没能很好地将概念区分开来，Socket套用了原始socket中的数据套接字，而不是我所希望的NetSession。可以圈点的地方在于该模块很多地方使用了回调函数表，从而方便地实现事件传送。</p>
<p style="FONT-SIZE: 10pt"><o:p>&nbsp;</o:p></p>
<img src ="http://www.cppblog.com/kevinlynx/aggbug/46097.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-04-02 21:22 <a href="http://www.cppblog.com/kevinlynx/archive/2008/04/02/46097.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>探究CRC32算法实现原理-why table-driven implemention</title><link>http://www.cppblog.com/kevinlynx/archive/2008/04/01/45952.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Tue, 01 Apr 2008 13:22:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/04/01/45952.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/45952.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/04/01/45952.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/45952.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/45952.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 探究CRC32算法实现原理-why table-driven implementionAuthor : Kevin Lynxemail&nbsp; : zmhn320@163.comPreface基于不重造轮子的原则，本文尽量不涉及网络上遍地都是的资料。What's CRC ?简而言之，CRC是一个数值。该数值被用于校验数据的正确性。CRC数值简单地说就是通过让你需要做处理的数...&nbsp;&nbsp;<a href='http://www.cppblog.com/kevinlynx/archive/2008/04/01/45952.html'>阅读全文</a><img src ="http://www.cppblog.com/kevinlynx/aggbug/45952.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-04-01 21:22 <a href="http://www.cppblog.com/kevinlynx/archive/2008/04/01/45952.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>