﻿<?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/7029.html</link><description>低调做技术</description><language>zh-cn</language><lastBuildDate>Wed, 14 May 2008 15:25:24 GMT</lastBuildDate><pubDate>Wed, 14 May 2008 15:25:24 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>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></channel></rss>