﻿<?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/wanghaiguang/category/19962.html</link><description>不要浪费你的生命，在你一定会后悔的地方上。
逆水行舟，不进则退</description><language>zh-cn</language><lastBuildDate>Thu, 20 Sep 2012 05:16:47 GMT</lastBuildDate><pubDate>Thu, 20 Sep 2012 05:16:47 GMT</pubDate><ttl>60</ttl><item><title>tcp要点学习-断开连接</title><link>http://www.cppblog.com/wanghaiguang/archive/2012/09/20/191382.html</link><dc:creator>王海光</dc:creator><author>王海光</author><pubDate>Thu, 20 Sep 2012 05:00:00 GMT</pubDate><guid>http://www.cppblog.com/wanghaiguang/archive/2012/09/20/191382.html</guid><wfw:comment>http://www.cppblog.com/wanghaiguang/comments/191382.html</wfw:comment><comments>http://www.cppblog.com/wanghaiguang/archive/2012/09/20/191382.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/wanghaiguang/comments/commentRss/191382.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/wanghaiguang/services/trackbacks/191382.html</trackback:ping><description><![CDATA[<p style="font-size: 10pt"><span style="font-size: 12pt">Author : Kevin Lynx </span>
<p style="font-size: 10pt"><strong style="font-size: 12pt">主要部分，四次握手：</strong> 
<p style="font-size: 10pt"><span style="font-size: 12pt">断开连接其实从我的角度看不区分客户端和服务器端，任何一方都可以调用close(or closesocket)之类</span><br /><span style="font-size: 12pt">的函数开始主动终止一个连接。这里先暂时说正常情况。当调用close函数断开一个连接时，主动断开的</span><br /><span style="font-size: 12pt">一方发送FIN(finish报文给对方。有了之前的经验，我想你应该明白我说的FIN报文时什么东西。也就是</span><br /><span style="font-size: 12pt">一个设置了FIN标志位的报文段。FIN报文也可能附加用户数据，如果这一方还有数据要发送时，将数据附</span><br /><span style="font-size: 12pt">加到这个FIN报文时完全正常的。之后你会看到，这种附加报文还会有很多，例如ACK报文。我们所要把握</span><br /><span style="font-size: 12pt">的原则是，TCP肯定会力所能及地达到最大效率，所以你能够想到的优化方法，我想TCP都会想到。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">当被动关闭的一方收到FIN报文时，它会发送ACK确认报文(对于ACK这个东西你应该很熟悉了)。这里有个</span><br /><span style="font-size: 12pt">东西要注意，因为TCP是双工的，也就是说，你可以想象一对TCP连接上有两条数据通路。当发送FIN报文</span><br /><span style="font-size: 12pt">时，意思是说，发送FIN的一端就不能发送数据，也就是关闭了其中一条数据通路。被动关闭的一端发送</span><br /><span style="font-size: 12pt">了ACK后，应用层通常就会检测到这个连接即将断开，然后被动断开的应用层调用close关闭连接。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">我可以告诉你，一旦当你调用close(or closesocket)，这一端就会发送FIN报文。也就是说，现在被动</span><br /><span style="font-size: 12pt">关闭的一端也发送FIN给主动关闭端。有时候，被动关闭端会将ACK和FIN两个报文合在一起发送。主动</span><br /><span style="font-size: 12pt">关闭端收到FIN后也发送ACK，然后整个连接关闭(事实上还没完全关闭，只是关闭需要交换的报文发送</span><br /><span style="font-size: 12pt">完毕)，四次握手完成。如你所见，因为被动关闭端可能会将ACK和FIN合到一起发送，所以这也算不上</span><br /><span style="font-size: 12pt">严格的四次握手---四个报文段。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">在前面的文章中，我一直没提TCP的状态转换。在这里我还是在犹豫是不是该将那张四处通用的图拿出来，</span><br /><span style="font-size: 12pt">不过，这里我只给出断开连接时的状态转换图，摘自&lt;The TCP/IP Guide&gt;： </span>
<p style="font-size: 10pt"><a href="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/tcp_DDB4/tcpclose_2.png"></a><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/wanghaiguang/image/tcpclose_thumb.png" width="670" height="560" />&nbsp;
<p style="font-size: 10pt"><span style="font-size: 12pt">给出一个正常关闭时的windump信息：</span><br /></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"><img align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"  alt="" /><span style="color: #000000; font-size: 12pt">14</span><span style="color: #000000; font-size: 12pt">:</span><span style="color: #000000; font-size: 12pt">00</span><span style="color: #000000; font-size: 12pt">:</span><span style="color: #000000; font-size: 12pt">38.819856</span><span style="color: #000000; font-size: 12pt"> IP cd</span><span style="color: #000000; font-size: 12pt">-</span><span style="color: #000000; font-size: 12pt">zhangmin.</span><span style="color: #000000; font-size: 12pt">1748</span><span style="color: #000000">&nbsp;</span><span style="color: #000000; font-size: 12pt">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000; font-size: 12pt">220.181</span><span style="color: #000000; font-size: 12pt">.</span><span style="color: #000000; font-size: 12pt">37.55</span><span style="color: #000000; font-size: 12pt">.</span><span style="color: #000000; font-size: 12pt">80</span><span style="color: #000000; font-size: 12pt">: F </span><span style="color: #000000; font-size: 12pt">1</span><span style="color: #000000; font-size: 12pt">:</span><span style="color: #000000; font-size: 12pt">1</span><span style="color: #000000; font-size: 12pt">(</span><span style="color: #000000; font-size: 12pt">0</span><span style="color: #000000; font-size: 12pt">) ack </span><span style="color: #000000; font-size: 12pt">1</span><span style="color: #000000; font-size: 12pt"> win </span><span style="color: #000000; font-size: 12pt">65535</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #000000; font-size: 12pt">14</span><span style="color: #000000; font-size: 12pt">:</span><span style="color: #000000; font-size: 12pt">00</span><span style="color: #000000; font-size: 12pt">:</span><span style="color: #000000; font-size: 12pt">38.863989</span><span style="color: #000000; font-size: 12pt"> IP </span><span style="color: #000000; font-size: 12pt">220.181</span><span style="color: #000000; font-size: 12pt">.</span><span style="color: #000000; font-size: 12pt">37.55</span><span style="color: #000000; font-size: 12pt">.</span><span style="color: #000000; font-size: 12pt">80</span><span style="color: #000000">&nbsp;</span><span style="color: #000000; font-size: 12pt">&gt;</span><span style="color: #000000; font-size: 12pt"> cd</span><span style="color: #000000; font-size: 12pt">-</span><span style="color: #000000; font-size: 12pt">zhangmin.</span><span style="color: #000000; font-size: 12pt">1748</span><span style="color: #000000; font-size: 12pt">: F </span><span style="color: #000000; font-size: 12pt">1</span><span style="color: #000000; font-size: 12pt">:</span><span style="color: #000000; font-size: 12pt">1</span><span style="color: #000000; font-size: 12pt">(</span><span style="color: #000000; font-size: 12pt">0</span><span style="color: #000000; font-size: 12pt">) ack </span><span style="color: #000000; font-size: 12pt">2</span><span style="color: #000000; font-size: 12pt"> win </span><span style="color: #000000; font-size: 12pt">2920</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #000000; font-size: 12pt">14</span><span style="color: #000000; font-size: 12pt">:</span><span style="color: #000000; font-size: 12pt">00</span><span style="color: #000000; font-size: 12pt">:</span><span style="color: #000000; font-size: 12pt">38.864412</span><span style="color: #000000; font-size: 12pt"> IP cd</span><span style="color: #000000; font-size: 12pt">-</span><span style="color: #000000; font-size: 12pt">zhangmin.</span><span style="color: #000000; font-size: 12pt">1748</span><span style="color: #000000">&nbsp;</span><span style="color: #000000; font-size: 12pt">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000; font-size: 12pt">220.181</span><span style="color: #000000; font-size: 12pt">.</span><span style="color: #000000; font-size: 12pt">37.55</span><span style="color: #000000; font-size: 12pt">.</span><span style="color: #000000; font-size: 12pt">80</span><span style="color: #000000; font-size: 12pt">: . ack </span><span style="color: #000000; font-size: 12pt">2</span><span style="color: #000000; font-size: 12pt"> win </span><span style="color: #000000; font-size: 12pt">65535</span><span style="color: #000000">&nbsp;</span></div>
<p style="font-size: 10pt">&nbsp; 
<p style="font-size: 10pt"><strong style="font-size: 12pt">补充细节：</strong> 
<p style="font-size: 10pt"><span style="font-size: 12pt">关于以上的四次握手，我补充下细节：</span><br /><span style="font-size: 12pt">1. 默认情况下(不改变socket选项)，当你调用close( or closesocket，以下说close不再重复)时，如果</span><br /><span style="font-size: 12pt">发送缓冲中还有数据，TCP会继续把数据发送完。</span><br /><span style="font-size: 12pt">2. 发送了FIN只是表示这端不能继续发送数据(应用层不能再调用send发送)，但是还可以接收数据。</span><br /><span style="font-size: 12pt">3. 应用层如何知道对端关闭？通常，在最简单的阻塞模型中，当你调用recv时，如果返回0，则表示对端</span><br /><span style="font-size: 12pt">关闭。在这个时候通常的做法就是也调用close，那么TCP层就发送FIN，继续完成四次握手。如果你不调用</span><br /><span style="font-size: 12pt">close，那么对端就会处于FIN_WAIT_2状态，而本端则会处于CLOSE_WAIT状态。这个可以写代码试试。</span><br /><span style="font-size: 12pt">4. 在很多时候，TCP连接的断开都会由TCP层自动进行，例如你CTRL+C终止你的程序，TCP连接依然会正常关</span><br /><span style="font-size: 12pt">闭，你可以写代码试试。 </span>
<p style="font-size: 10pt"><strong style="font-size: 12pt">特别的TIME_WAIT状态：</strong> 
<p style="font-size: 10pt"><span style="font-size: 12pt">从以上TCP连接关闭的状态转换图可以看出，主动关闭的一方在发送完对对方FIN报文的确认(ACK)报文后，</span><br /><span style="font-size: 12pt">会进入TIME_WAIT状态。TIME_WAIT状态也称为2MSL状态。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">什么是2MSL？MSL即Maximum Segment Lifetime，也就是报文最大生存时间，引用&lt;TCP/IP详解&gt;中的话：&#8220;</span><br /><span style="font-size: 12pt">它(MSL)是任何报文段被丢弃前在网络内的最长时间。&#8221;那么，2MSL也就是这个时间的2倍。其实我觉得没</span><br /><span style="font-size: 12pt">必要把这个MSL的确切含义搞明白，你所需要明白的是，当TCP连接完成四个报文段的交换时，主动关闭的</span><br /><span style="font-size: 12pt">一方将继续等待一定时间(2-4分钟)，即使两端的应用程序结束。你可以写代码试试，然后用netstat查看下。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">为什么需要2MSL？根据&lt;TCP/IP详解&gt;和&lt;The TCP/IP Guide&gt;中的说法，有两个原因：</span><br /><span style="font-size: 12pt">其一，保证发送的ACK会成功发送到对方，如何保证？我觉得可能是通过超时计时器发送。这个就很难用</span><br /><span style="font-size: 12pt">代码演示了。</span><br /><span style="font-size: 12pt">其二，报文可能会被混淆，意思是说，其他时候的连接可能会被当作本次的连接。直接引用&lt;The TCP/IP Guide&gt;</span><br /><span style="font-size: 12pt">的说法：The second is to provide a &#8220;buffering period&#8221; between the end of this connection </span><br /><span style="font-size: 12pt">and any subsequent ones. If not for this period, it is possible that packets from different </span><br /><span style="font-size: 12pt">connections could be mixed, creating confusion. </span>
<p style="font-size: 10pt"><strong style="font-size: 12pt">TIME_WAIT状态所带来的影响：</strong> 
<p style="font-size: 10pt"><span style="font-size: 12pt">当某个连接的一端处于TIME_WAIT状态时，该连接将不能再被使用。事实上，对于我们比较有现实意义的</span><br /><span style="font-size: 12pt">是，这个端口将不能再被使用。某个端口处于TIME_WAIT状态(其实应该是这个连接)时，这意味着这个TCP</span><br /><span style="font-size: 12pt">连接并没有断开(完全断开)，那么，如果你bind这个端口，就会失败。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">对于服务器而言，如果服务器突然crash掉了，那么它将无法再2MSL内重新启动，因为bind会失败。解决这</span><br /><span style="font-size: 12pt">个问题的一个方法就是设置socket的SO_REUSEADDR选项。这个选项意味着你可以重用一个地址。 </span>
<p style="font-size: 10pt"><strong style="font-size: 12pt">对于TIME_WAIT的插曲：</strong> 
<p style="font-size: 10pt"><span style="font-size: 12pt">当建立一个TCP连接时，服务器端会继续用原有端口监听，同时用这个端口与客户端通信。而客户端默认情况</span><br /><span style="font-size: 12pt">下会使用一个随机端口与服务器端的监听端口通信。有时候，为了服务器端的安全性，我们需要对客户端进行</span><br /><span style="font-size: 12pt">验证，即限定某个IP某个特定端口的客户端。客户端可以使用bind来使用特定的端口。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">对于服务器端，当设置了SO_REUSEADDR选项时，它可以在2MSL内启动并listen成功。但是对于客户端，当使</span><br /><span style="font-size: 12pt">用bind并设置SO_REUSEADDR时，如果在2MSL内启动，虽然bind会成功，但是在windows平台上connect会失败。</span><br /><span style="font-size: 12pt">而在linux上则不存在这个问题。(我的实验平台：winxp, ubuntu7.10) </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">要解决windows平台的这个问题，可以设置SO_LINGER选项。SO_LINGER选项决定调用close时，TCP的行为。</span><br /><span style="font-size: 12pt">SO_LINGER涉及到linger结构体，如果设置结构体中l_onoff为非0，l_linger为0，那么调用close时TCP连接</span><br /><span style="font-size: 12pt">会立刻断开，TCP不会将发送缓冲中未发送的数据发送，而是立即发送一个RST报文给对方，这个时候TCP连</span><br /><span style="font-size: 12pt">接就不会进入TIME_WAIT状态。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">如你所见，这样做虽然解决了问题，但是并不安全。通过以上方式设置SO_LINGER状态，等同于设置SO_DONTLINGER</span><br /><span style="font-size: 12pt">状态。 </span>
<p style="font-size: 10pt"><strong style="font-size: 12pt">断开连接时的意外：</strong><br />这个算不上断开连接时的意外，当TCP连接发生一些物理上的意外情况时，例如网线断开，linux上的TCP实现<br />会依然认为该连接有效，而windows则会在一定时间后返回错误信息。 
<p style="font-size: 10pt"><span style="font-size: 12pt">这似乎可以通过设置SO_KEEPALIVE选项来解决，不过不知道这个选项是否对于所有平台都有效。 </span>
<p style="font-size: 10pt"><strong style="font-size: 12pt">总结：</strong> 
<p style="font-size: 10pt"><span style="font-size: 12pt">个人感觉，越写越烂。接下来会讲到TCP的数据发送，这会涉及到滑动窗口各种定时器之类的东西。我真诚</span><br /><span style="font-size: 12pt">希望各位能够多提意见。对于TCP连接的断开，我们只要清楚：</span><br /><span style="font-size: 12pt">1. 在默认情况下，调用close时TCP会继续将数据发送完毕；</span><br /><span style="font-size: 12pt">2. TIME_WAIT状态会导致的问题；</span><br /><span style="font-size: 12pt">3. 连接意外断开时可能会出现的问题。</span><br /><span style="font-size: 12pt">4. maybe more... <br /><br />本文转自：<a href="http://www.cppblog.com/kevinlynx/archive/2008/05/14/49825.html">http://www.cppblog.com/kevinlynx/archive/2008/05/14/49825.html</a></span></p><img src ="http://www.cppblog.com/wanghaiguang/aggbug/191382.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/wanghaiguang/" target="_blank">王海光</a> 2012-09-20 13:00 <a href="http://www.cppblog.com/wanghaiguang/archive/2012/09/20/191382.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>tcp要点学习-建立连接 </title><link>http://www.cppblog.com/wanghaiguang/archive/2012/09/20/191379.html</link><dc:creator>王海光</dc:creator><author>王海光</author><pubDate>Thu, 20 Sep 2012 04:56:00 GMT</pubDate><guid>http://www.cppblog.com/wanghaiguang/archive/2012/09/20/191379.html</guid><wfw:comment>http://www.cppblog.com/wanghaiguang/comments/191379.html</wfw:comment><comments>http://www.cppblog.com/wanghaiguang/archive/2012/09/20/191379.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/wanghaiguang/comments/commentRss/191379.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/wanghaiguang/services/trackbacks/191379.html</trackback:ping><description><![CDATA[<p style="font-size: 10pt"><span style="font-size: 12pt">Author : Kevin Lynx </span>
<p style="font-size: 10pt"><strong style="font-size: 12pt">准备：</strong> 
<p style="font-size: 10pt"><span style="font-size: 12pt">在这里本文将遵循上一篇文章的风格，只提TCP协议中的要点，这样我觉得可以更容易地掌握TCP。或者</span><br /><span style="font-size: 12pt">根本谈不上掌握，对于这种纯理论的东西，即使你现在掌握了再多的细节，一段时间后也会淡忘。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">在以后各种细节中，因为我们会涉及到分析一些TCP中的数据报，因此一个协议包截获工具必不可少。在</span><br /><span style="font-size: 12pt">&lt;TCP/IP详解&gt;中一直使用tcpdump。这里因为我的系统是windows，所以只好使用windows平台的tcpdump，</span><br /><span style="font-size: 12pt">也就是</span><a href="http://www.winpcap.org/windump/" target="_blank"><font color="#cc6666"><span style="font-size: 12pt">WinDump</span></font></a><span style="font-size: 12pt">。在使用WinDump之前，你需要安装该程序使用的库</span><a href="http://www.winpcap.org/install/default.htm#Developer" target="_blank"><font color="#cc6666"><span style="font-size: 12pt">WinpCap</span></font></a><span style="font-size: 12pt">。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">关于WinDump的具体用法你可以从网上其他地方获取，这里我只稍微提一下。要让WinDump开始监听数据，</span><br /><span style="font-size: 12pt">首先需要确定让其监听哪一个网络设备(或者说是网络接口)。你可以: </span></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"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><span style="color: #000000">windump </span><span style="color: #000000">-</span><span style="color: #000000">D </span></div>
<p style="font-size: 10pt"><span style="font-size: 12pt">获取当前机器上的网络接口。然后使用： </span></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"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><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"><span style="font-size: 12pt">开始对网络接口2的数据监听。windump如同tcpdump(其实就是tcpdump)一样支持过滤表达式，windump</span><br /><span style="font-size: 12pt">将会根据你提供的过滤表达式过滤不需要的网络数据包，例如： </span></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"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><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"><span style="font-size: 12pt">那么windump只会显示端口号为4000的网络数据。 </span>
<p style="font-size: 10pt"><strong style="font-size: 12pt">序号和确认号：</strong> 
<p style="font-size: 10pt"><span style="font-size: 12pt">要讲解TCP的建立过程，也就是那个所谓的三次握手，就会涉及到序号和确认号这两个东西。翻书到TCP</span><br /><span style="font-size: 12pt">的报文头，有两个很重要的域(都是32位)就是序号域和确认号域。可能有些同学会对TCP那个报文头有所</span><br /><span style="font-size: 12pt">疑惑(能看懂我在讲什么的会产生这样的疑惑么？)，这里我可以告诉你，你可以假想TCP的报文头就是个</span><br /><span style="font-size: 12pt">C语言结构体(假想而已，去翻翻bsd对TCP的实现，肯定没这么简单)，那么大致上，所谓的TCP报文头就是：</span><br /></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"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_27_429_Closed_Image" 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';" 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_27_429_Closed_Text"><img alt="" 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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_33_44_Closed_Image" 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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&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_33_44_Closed_Text">/**/</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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_78_90_Closed_Image" 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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&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_78_90_Closed_Text">/**/</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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_124_133_Closed_Image" 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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&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_124_133_Closed_Text">/**/</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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_165_175_Closed_Image" 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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&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_165_175_Closed_Text">/**/</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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_207_244_Closed_Image" 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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&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_207_244_Closed_Text">/**/</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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_274_285_Closed_Image" 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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&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_274_285_Closed_Text">/**/</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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_319_329_Closed_Image" 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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&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_319_329_Closed_Text">/**/</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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_353_364_Closed_Image" 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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&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_353_364_Closed_Text">/**/</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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /><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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_384_428_Closed_Image" 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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&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_384_428_Closed_Text">/**/</span><span id="Codehighlighter1_384_428_Open_Text"><span style="color: #808080">///</span><span style="color: #008000"> 可选选项<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" /><span style="color: #000000">}</span></span><span style="color: #000000"> tcp_header; <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></span></div>
<p style="font-size: 10pt"><span style="font-size: 12pt">那么，这个序号和确认号是什么？TCP报文为每一个字节都设置一个序号，觉得很奇怪？这里并不是为每一</span><br /><span style="font-size: 12pt">字节附加一个序号(那会是多么可笑的编程手法?)，而是为一个TCP报文附加一个序号，这个序号表示报文</span><br /><span style="font-size: 12pt">中数据的第一个字节的序号，而其他数据则是根据离第一个数据的偏移来决定序号的，例如，现在有数据：</span><br /><span style="font-size: 12pt">abcd。如果这段数据的序号为1200，那么a的序号就是1200，b的序号就是1201。而TCP发送的下一个数据包</span><br /><span style="font-size: 12pt">的序号就会是上一个数据包最后一个字节的序号加一。例如efghi是abcd的下一个数据包，那么它的序号就</span><br /><span style="font-size: 12pt">是1204。通过这种看似简单的方法，TCP就实现了为每一个字节设置序号的功能(终于明白为什么书上要告诉</span><br /><span style="font-size: 12pt">我们&#8216;为每一个字节设置一个序号&#8217;了吧?)。注意，设置序号是一种可以让TCP成为&#8217;可靠协议&#8216;的手段。</span><br /><span style="font-size: 12pt">TCP中各种乱七八糟的东西都是有目的的，大部分目的还是为了&#8217;可靠&#8216;两个字。别把TCP看高深了，如果</span><br /><span style="font-size: 12pt">让你来设计一个网络协议，目的需要告诉你是&#8217;可靠的&#8216;，你就会明白为什么会产生那些乱七八糟的东西了。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">接着看，确认号是什么？因为TCP会对接收到的数据包进行确认，发送确认数据包时，就会设置这个确认号，</span><br /><span style="font-size: 12pt">确认号通常表示接收方希望接收到的下一段报文的序号。例如某一次接收方收到序号为1200的4字节数举报，</span><br /><span style="font-size: 12pt">那么它发送确认报文给发送方时，就会设置确认号为1204。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">大部分书上在讲确认号和序号时，都会说确认号是序号加一。这其实有点误解人，所以我才在这里废话了</span><br /><span style="font-size: 12pt">半天(高手宽容下:D)。 </span>
<p style="font-size: 10pt"><strong style="font-size: 12pt">开始三次握手：</strong> 
<p style="font-size: 10pt"><span style="font-size: 12pt">如果你还不会简单的tcp socket编程，我建议你先去学学，这就好比你不会C++基本语法，就别去研究vtable</span><br /><span style="font-size: 12pt">之类。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">三次握手开始于客户端试图连接服务器端。当你调用诸如connect的函数时，正常情况下就会开始三次握手。</span><br /><span style="font-size: 12pt">随便在网上找张三次握手的图： </span>
<p style="font-size: 10pt"><a href="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/tcp_EB3/connection.jpg"><img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="connection" src="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/tcp_EB3/connection_thumb.jpg" width="458" height="210" /></a> 
<p style="font-size: 10pt"><span style="font-size: 12pt">如前文所述，三次握手也就是产生了三个数据包。客户端主动连接，发送SYN被设置了的报文(注意序号和</span><br /><span style="font-size: 12pt">确认号，因为这</span><span style="font-size: 12pt">里不包含用户数据，所以序号和确认号就是加一减一的关系)。服务器端收到该报文时，正</span><br /><span style="font-size: 12pt">常情况下就发送SYN和ACK被设置了的报文作为确认，以及告诉客户端：我想打开我这边的连接(双工)。客户</span><br /><span style="font-size: 12pt">端于是再对服务器端的SYN进行确认，于是再发送ACK报文。然后连接建立完毕。对于阻塞式socket而言，你</span><br /><span style="font-size: 12pt">的connect可能就返回成功给你。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">在进行了铺天盖地的罗利巴索的基础概念的讲解后，看看这个连接建立的过程，是不是简单得几近无聊？ </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">我们来实际点，写个最简单的客户端代码：</span><br /></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"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><span style="color: #000000">&nbsp;&nbsp; sockaddr_in addr;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />&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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp; addr.sin_family </span><span style="color: #000000">=</span><span style="color: #000000"> AF_INET;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />&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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_129_146_Closed_Image" 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';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif">&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_129_146_Closed_Text">/**/</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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />&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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" />&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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></span></div>
<p style="font-size: 10pt"><span style="font-size: 12pt">主要就是connect。运行程序前我们运行windump： </span></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"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><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-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"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></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 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" /></span></div>
<p style="font-size: 10pt"><span style="font-size: 12pt">如何分析windump的结果，建议参看&lt;tcp/ip详解&gt;中对于tcpdump的描述。 </span>
<p style="font-size: 10pt"><strong style="font-size: 12pt">建立连接的附加信息：</strong> 
<p style="font-size: 10pt"><span style="font-size: 12pt">虽然SYN、ACK之类的报文没有用户数据，但是TCP还是附加了其他信息。最为重要的就是附加的MSS值。这个</span><br /><span style="font-size: 12pt">可以被协商的MSS值基本上就只在建立连接时协商。如以上数据表示，MSS为1460字节。 </span>
<p style="font-size: 10pt"><strong style="font-size: 12pt">连接的意外：</strong> 
<p style="font-size: 10pt"><span style="font-size: 12pt">连接的意外我大致分为两种情况(也许还有更多情况)：目的主机不可达、目的主机并没有在指定端口监听。</span><br /><span style="font-size: 12pt">当目的主机不可达时，也就是说，SYN报文段根本无法到达对方(如果你的机器根本没插网线，你就不可达)，</span><br /><span style="font-size: 12pt">那么TCP收不到任何回复报文。这个时候，你会看到TCP中的定时器机制出现了。TCP对发出的SYN报文进行</span><br /><span style="font-size: 12pt">计时，当在指定时间内没有得到回复报文时，TCP就会重传刚才的SYN报文。通常，各种不同的TCP实现对于</span><br /><span style="font-size: 12pt">这个超时值都不同，但是据我观察，重传次数基本上都是3次。例如，我连接一个不可达的主机： </span></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"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></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"><span style="font-size: 12pt">发出了三个序号一样的SYN报文，但是没有得到一个回复报文(废话)。每一个SYN报文之间的间隔时间都是</span><br /><span style="font-size: 12pt">有规律的，在windows上是3秒6秒9秒12秒。上面的数据你看不到12秒这个数据，因为这是第三个报文发出的</span><br /><span style="font-size: 12pt">时间和connect返回错误信息时的时间之差。另一方面，如果连接同一个网络，这个间隔时间又不同。例如</span><br /><span style="font-size: 12pt">直接连局域网，间隔时间就差不多为500ms。 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">(我强烈建议你能运行windump去试验这里提到的每一个现象，如果你在ubuntu下使用tcpdump，记住sudo :D) </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">出现意外的第二种情况是如果主机数据包可达，但是试图连接的端口根本没有监听，那么发送SYN报文的这</span><br /><span style="font-size: 12pt">方会收到RST被设置的报文(connect也会返回相应的信息给你)，例如： </span></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"><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></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 alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></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"><span style="font-size: 12pt">可以看出，7AURORA-CCTEST.7100返回了RST报文给我，但是我这边根本不在乎这个报文，继续发送SYN报文。</span><br /><span style="font-size: 12pt">三次过后connect就返回了。(数据反映的事实是这样) </span>
<p style="font-size: 10pt"><strong style="font-size: 12pt">关于listen:</strong> 
<p style="font-size: 10pt"><span style="font-size: 12pt">TCP服务器端会维护一个新连接的队列。当新连接上的客户端三次握手完成时，就会将其放入这个队列。这个队 </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">列的大小是通过listen设置的。当这个队列满时，如果有新的客户端试图连接（发送SYN），服务器端丢弃报文， </span>
<p style="font-size: 10pt"><span style="font-size: 12pt">同时不做任何回复。 </span>
<p style="font-size: 10pt"><strong style="font-size: 12pt">总结：</strong><br style="font-size: 12pt" /><span style="font-size: 12pt">TCP连接的建立的相关要点就是这些(or more?)。正常情况下就是三次握手，非正常情况下就是SYN三次超时，</span><br style="font-size: 12pt" /><span style="font-size: 12pt">以及收到RST报文却被忽略。 <br /><br />本文转自：<a href="http://www.cppblog.com/kevinlynx/archive/2008/05/11/49482.html">http://www.cppblog.com/kevinlynx/archive/2008/05/11/49482.html</a></span></p><img src ="http://www.cppblog.com/wanghaiguang/aggbug/191379.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/wanghaiguang/" target="_blank">王海光</a> 2012-09-20 12:56 <a href="http://www.cppblog.com/wanghaiguang/archive/2012/09/20/191379.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>