<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>http://jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>http://jackxiang.com/post//</link>
<title><![CDATA[TCP握手协议]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[WEB2.0]]></category>
<pubDate>Mon, 25 Oct 2010 10:50:00 +0000</pubDate> 
<guid>http://jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	TCP握手协议(网转)<br/>&nbsp;&nbsp;在TCP/IP协议中，TCP协议提供可靠的连接服务，采用三次握手建立一个连接。<br/>&nbsp;&nbsp;第一次握手：建立连接时，客户端发送syn包(syn=j)到服务器，并进入SYN_SEND状态，等待服务器确认；<br/>&nbsp;&nbsp;第二次握手：服务器收到syn包，必须确认客户的SYN（ack=j+1），同时自己也发送一个SYN包（syn=k），即SYN+ACK包，此时服务器进入SYN_RECV状态；<br/>&nbsp;&nbsp;第三次握手：客户端收到服务器的SYN＋ACK包，向服务器发送确认包ACK(ack=k+1)，此包发送完毕，客户端和服务器进入ESTABLISHED状态，完成三次握手。<br/>&nbsp;&nbsp;完成三次握手，客户端与服务器开始传送数据，在上述过程中，还有一些重要的概念：<br/>&nbsp;&nbsp;未连接队列：在三次握手协议中，服务器维护一个未连接队列，该队列为每个客户端的SYN包（syn=j）开设一个条目，该条目表明服务器已收到SYN包，并向客户发出确认，正在等待客户的确认包。这些条目所标识的连接在服务器处于Syn_RECV状态，当服务器收到客户的确认包时，删除该条目，服务器进入 ESTABLISHED状态。<br/>&nbsp;&nbsp;Backlog参数：表示未连接队列的最大容纳数目。<br/>&nbsp;&nbsp;SYN-ACK 重传次数服务器发送完SYN－ACK包，如果未收到客户确认包，服务器进行首次重传，等待一段时间仍未收到客户确认包，进行第二次重传，如果重传次数超过系统规定的最大重传次数，系统将该连接信息从半连接队列中删除。注意，每次重传等待的时间不一定相同。<br/>&nbsp;&nbsp;半连接存活时间：是指半连接队列的条目存活的最长时间，也即服务从收到SYN包到确认这个报文无效的最长时间，该时间值是所有重传请求包的最长等待时间总和。有时我们也称半连接存活时间为Timeout时间、SYN_RECV存活时间。<br/><br/>&nbsp;&nbsp;syn_send&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a&nbsp;&nbsp; syn=j&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ---&gt; b<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a&nbsp;&nbsp; syn=k ack=j+1<br/>&nbsp;&nbsp;ESTABLISHED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;&nbsp; ack=k+1&nbsp;&nbsp;&nbsp;&nbsp; ---&gt;b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ESTABLISHED<br/><br/>TCP连接的建立与中止<br/>1.连接的建立<br/>&nbsp;&nbsp;在建立连接的时候，客户端首先向服务器申请打开某一个端口(用SYN段等于1的TCP报文)，然后服务器端发回一个ACK报文通知客户端请求报文收到，客户端收到确认报文以后再次发出确认报文确认刚才服务器端发出的确认报文（绕口么），至此，连接的建立完成。这就叫做三次握手。如果打算让双方都做好准备的话，一定要发送三次报文，而且只需要三次报文就可以了。<br/>&nbsp;&nbsp;可以想见，如果再加上TCP的超时重传机制，那么TCP就完全可以保证一个数据包被送到目的地。<br/>2.结束连接<br/>&nbsp;&nbsp;TCP 有一个特别的概念叫做half-close，这个概念是说，TCP的连接是全双工（可以同时发送和接收）连接，因此在关闭连接的时候，必须关闭传和送两个方向上的连接。客户机给服务器一个FIN为1的TCP报文，然后服务器返回给客户端一个确认ACK报文，并且发送一个FIN报文，当客户机回复ACK报文后（四次握手），连接就结束了。<br/>3.最大报文长度<br/>&nbsp;&nbsp;在建立连接的时候，通信的双方要互相确认对方的最大报文长度(MSS)，以便通信。一般这个SYN长度是MTU减去固定IP首部和TCP首部长度。对于一个以太网，一般可以达到1460字节。当然如果对于非本地的IP，这个MSS可能就只有536字节，而且，如果中间的传输网络的MSS更佳的小的话，这个值还会变得更小。<br/>4.TCP的状态迁移图(如下:)<br/><br/><a href="http://jackxiang.com/attachment.php?fid=145" target="_blank"><img src="http://jackxiang.com/attachment.php?fid=145" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/><br/>&nbsp;&nbsp;说明: ----&gt;实线箭头说明客户的正常状态变迁<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;----&gt;虚线箭头说明服务器的正常状态变迁<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;应用进程：说明当应用执行某种操作时发生的状态变迁<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;收：说明当收到TCP报文段时状态的变迁<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;发：说明为了进行某个状态变迁要发送的TCP报文段<br/><br/>&nbsp;&nbsp;状态迁移图，包含了两个部分---服务器的状态迁移和客户端的状态迁移，如果从某一个角度出发来看这个图，就会清晰许多，这里面的服务器和客户端都不是绝对的，发送数据的就是客户端，接受数据的就是服务器。<br/>&nbsp;&nbsp;4.1.客户端应用程序的状态迁移图<br/>&nbsp;&nbsp;&nbsp;&nbsp;客户端的状态可以用如下的流程来表示：<br/>&nbsp;&nbsp;&nbsp;&nbsp;CLOSED-&gt;SYN_SENT-&gt;ESTABLISHED-&gt;FIN_WAIT_1-&gt;FIN_WAIT_2-&gt;TIME_WAIT-&gt;CLOSED<br/>&nbsp;&nbsp;&nbsp;&nbsp;以上流程是在程序正常的情况下应该有的流程，从图中可以看到，在建立连接时，当客户端收到SYN报文的ACK以后，客户端就打开了数据交互地连接。而结束连接则通常是客户端主动结束的，客户端结束应用程序以后，需要经历FIN_WAIT_1，FIN_WAIT_2等状态，这些状态的迁移就是前面提到的结束连接的四次握手。<br/>&nbsp;&nbsp;4.2.服务器的状态迁移图<br/>&nbsp;&nbsp;&nbsp;&nbsp;服务器的状态可以用如下的流程来表示：<br/>&nbsp;&nbsp;&nbsp;&nbsp;CLOSED-&gt;LISTEN-&gt;SYN收到-&gt;ESTABLISHED-&gt;CLOSE_WAIT-&gt;LAST_ACK-&gt;CLOSED<br/>&nbsp;&nbsp;&nbsp;&nbsp;在建立连接的时候，服务器端是在第三次握手之后才进入数据交互状态，而关闭连接则是在关闭连接的第二次握手以后（注意不是第四次）。而关闭以后还要等待客户端给出最后的ACK包才能进入初始的状态。<br/>&nbsp;&nbsp;4.3.其他状态迁移<br/>&nbsp;&nbsp;&nbsp;&nbsp;图还有一些其他的状态迁移，这些状态迁移针对服务器和客户端两方面的总结如下<br/>&nbsp;&nbsp;&nbsp;&nbsp;LISTEN-&gt;SYN_SENT，对于这个解释就很简单了，服务器有时候也要打开连接的嘛。<br/>&nbsp;&nbsp;&nbsp;&nbsp;SYN_SENT-&gt;SYN收到，服务器和客户端在SYN_SENT状态下如果收到SYN数据报，则都需要发送SYN的ACK数据报并把自己的状态调整到SYN收到状态，准备进入ESTABLISHED<br/>&nbsp;&nbsp;&nbsp;&nbsp;SYN_SENT-&gt;CLOSED，在发送超时的情况下，会返回到CLOSED状态。<br/>&nbsp;&nbsp;&nbsp;&nbsp;SYN_收到-&gt;LISTEN，如果受到RST包，会返回到LISTEN状态。<br/>&nbsp;&nbsp;&nbsp;&nbsp;SYN_收到-&gt;FIN_WAIT_1，这个迁移是说，可以不用到ESTABLISHED状态，而可以直接跳转到FIN_WAIT_1状态并等待关闭。<br/>&nbsp;&nbsp;4.4.2MSL等待状态<br/>&nbsp;&nbsp;&nbsp;&nbsp;图里面，有一个TIME_WAIT等待状态，这个状态又叫做2MSL状态，说的是在TIME_WAIT2发送了最后一个ACK数据报以后，要进入 TIME_WAIT状态，这个状态是防止最后一次握手的数据报没有传送到对方那里而准备的（注意这不是四次握手，这是第四次握手的保险状态）。这个状态在很大程度上保证了双方都可以正常结束，但是，问题也来了。<br/>&nbsp;&nbsp;&nbsp;&nbsp;由于插口的2MSL状态（插口是IP和端口对的意思，socket），使得应用程序在 2MSL时间内是无法再次使用同一个插口的，对于客户程序还好一些，但是对于服务程序，例如httpd，它总是要使用同一个端口来进行服务，而在2MSL时间内，启动httpd就会出现错误（插口被使用）。为了避免这个错误，服务器给出了一个平静时间的概念，这是说在2MSL时间内，虽然可以重新启动服务器，但是这个服务器还是要平静的等待2MSL时间的过去才能进行下一次连接。<br/>&nbsp;&nbsp;4.5.FIN_WAIT_2状态<br/>&nbsp;&nbsp;&nbsp;&nbsp;这就是著名的半关闭的状态了，这是在关闭连接时，客户端和服务器两次握手之后的状态。在这个状态下，应用程序还有接受数据的能力，但是已经无法发送数据，但是也有一种可能是，客户端一直处于FIN_WAIT_2状态，而服务器则一直处于WAIT_CLOSE状态，而直到应用层来决定关闭这个状态。<br/>5.RST，同时打开和同时关闭<br/>&nbsp;&nbsp;RST是另一种关闭连接的方式，应用程序应该可以判断RST包的真实性，即是否为异常中止。而同时打开和同时关闭则是两种特殊的TCP状态，发生的概率很小。<br/>6.TCP服务器设计<br/>&nbsp;&nbsp;UDP的服务器完全不需要所谓的并发机制，它只要建立一个数据输入队列就可以。但是TCP不同，TCP服务器对于每一个连接都需要建立一个独立的进程（或者是轻量级的，线程），来保证对话的独立性。所以TCP服务器是并发的。而且TCP还需要配备一个呼入连接请求队列（UDP服务器也同样不需要），来为每一个连接请求建立对话进程，这也就是为什么各种TCP服务器都有一个最大连接数的原因。而根据源主机的IP和端口号码，服务器可以很轻松的区别出不同的会话，来进行数据的分发。<br/> <br/>三次握手：<br/>&nbsp;&nbsp;1：服务器必须准备好接受外来的连接，这通过调用socket,bind,和listen函数来完成,称为被动打开<br/>&nbsp;&nbsp;2：客户通过调用connect 进行主动打开，这引起客户TCP发送一个SYN分节。一般情况下，SYN分节不携带数据，它只含有一个IP头部，一个TCP头部，及可能的TCP选项。<br/>&nbsp;&nbsp;3：服务器必须确认客户的SYN,同时自己也得发送一个SYN分节，包含同一连接中发送数据的一个系列号，服务器以单个分节向客户发送SYN和对客户SYN的ACK.<br/>&nbsp;&nbsp;4：客户确认ACK. 
]]>
</description>
</item><item>
<link>http://jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论] TCP握手协议]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>