duan2

导航

 

尽管T C P和U D P都使用相同的网络层(I P),T C P却向应用层提供与U D P完全不同的服务。T C P提供一种面向连接的、可靠的字节流服务。面向连接意味着两个使用 T C P的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个 T C P连接。这一过程与打电话很相似,先拨号振铃,等待对方摘机说“喂”,然后才说明是谁。在第 1 8章我们将看到一个 T C P连接是如何建立的,以及当一方通信结束后如何断开连接

 

 

在一个T C P连接中,仅有两方进行彼此通信。广播和多播不能用于T C P。
T C P通过下列方式来提供可靠性:
• 应用数据被分割成T C P认为最适合发送的数据块。这和 U D P完全不同,应用程序产生的
数据报长度将保持不变。由 T C P传递给I P的信息单位称为报文段或段( s e g m e n t)
• 当T C P发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能
及时收到一个确认,将重发这个报文段。
• 当T C P收到发自T C P连接另一端的数据,它将发送一个确认。这个确认不是立即发送,
通常将推迟几分之一秒
• T C P将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输
过程中的任何变化。如果收到段的检验和有差错, T C P将丢弃这个报文段和不确认收到
此报文段(希望发端超时并重发)。
• 既然T C P报文段作为I P数据报来传输,而I P数据报的到达可能会失序,因此 T C P报文段
的到达也可能会失序。如果必要, T C P将对收到的数据进行重新排序,将收到的数据以
正确的顺序交给应用层。
• 既然I P数据报会发生重复,T C P的接收端必须丢弃重复的数据。
• T C P还能提供流量控制。 T C P连接的每一方都有固定大小的缓冲空间。 T C P的接收端只
bbs.theithome.com
允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲
区溢出。

 

 

  两个应用程序通过T C P连接交换8 bit字节构成的字节流。T C P不在字节流中插入记录标识符。我们将这称为字节流服务(byte stream service)。如果一方的应用程序先传1 0字节,又传2 0字节,再传5 0字节,连接的另一方将无法了解发方每次发送了多少字节。收方可以分 4次接收这8 0个字节,每次接收 2 0字节。一端将字节流放到 T C P连接上,同样的字节流将出现在T C P连接的另一端。另外,T C P对字节流的内容不作任何解释。 T C P不知道传输的数据字节流是二进制数据,还是A S C I I字符、E B C D I C字符或者其他类型数据。对字节流的解释由 T C P连接双方的应用层解释。这种对字节流的处理方式与U n i x操作系统对文件的处理方式很相似。U n i x的内核对一个应用读或写的内容不作任何解释,而是交给应用程序处理。对U n i x的内核来说,它无法区分一个二进制文件与一个文本文件。

 

TCP首部

T C P数据被封装在一个I P数据报中,如图1 7 - 1所示

 

 

 

 图1 7 - 2显示T C P首部的数据格式。如果不计任选字段,它通常是 2 0个字节。

 

 

 

 每个T C P段都包含源端和目的端的端口号,用于寻找发端和收端应用进程。这两个值加上I P首部中的源端I P地址和目的端I P地址唯一确定一个T C P连接

 

序号用来标识从T C P发端向T C P收端发送的数据字节流,它表示在这个报文段中的的第一个数据字节。如果将字节流看作在两个应用程序间的单向流动,则 T C P用序号对每个字节进行计数。序号是32 bit的无符号数,序号到达2 3 2 -1后又从0开始。

 

当建立一个新的连接时, S Y N标志变1。序号字段包含由这个主机选择的该连接的初始序号I S N(Initial Sequence Number)。该主机要发送数据的第一个字节序号为这个 I S N加1,因为S Y N标志消耗了一个序号(将在下章详细介绍如何建立和终止连接,届时我们将看到 F I N标志也要占用一个序号)。

既然每个传输的字节都被计数,确认序号包含发送确认的一端所期望收到的下一个序号。因此,确认序号应当是上次已成功收到数据字节序号加 1。只有A C K标志(下面介绍)为 1时

确认序号字段才有效发送A C K无需任何代价,因为32 bit的确认序号字段和A C K标志一样,总是T C P首部的一部分。因此,我们看到一旦一个连接建立起来,这个字段总是被设置, A C K标志也总是被设置为1。T C P为应用层提供全双工服务。这意味数据能在两个方向上独立地进行传输。因此,连接的每一端必须保持每个方向上的传输数据序号。

 

T C P的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收的字节。窗口大小是一个 16 bit字段,因而窗口大小最大为 6 5 5 3 5字节。在2 4 . 4节我们将看到新的窗口刻度选项,它允许这个值按比例变化以提供更大的窗口。

 

 

TCP连接的建立与终止

连接的建立与终止

为了了解一个T C P连接在建立及终止时发生了什么,我们在系统 s v r 4上键入下列命令

 

t e l n e t命令在与丢弃( d i s c a r d )服务(参见1 . 1 2节)对应的端口上与主机 b s d i建立一条T C P连接。这服务类型正是我们需要观察的一条连接建立与终止的服务类型,而不需要服务

器发起任何数据交换。

 

 这7个T C P报文段仅包含T C P首部。没有任何数据。对于T C P段,每个输出行开始按如下格式显示:

 

源 > 目的: 标志
这里的标志代表T C P首部(图1 7 - 2)中6个标志比特中的4个。图1 8 - 2显示了表示标志的5
个字符的含义。

 

在第1行中,字段1 4 1 5 5 3 1 5 2 1 : 1 4 1 5 5 3 1 5 2 1 ( 0 )表示分组的序号是1 4 1 5 5 3 1 5 2 1,而报文段中
数据字节数为0

在第2行中,字段ack 1415531522 表示确认序号。它只有在首部中的 A C K标志比特被
设置1时才显示

每行显示的字段win 4096表示发端通告的窗口大小。在这些例子中,我们没有交换任
何数据,窗口大小就维持默认情况下的 4 0 9 6(我们将在2 0 . 4节中讨论T C P窗口大小)。

 

图1 8 - 1中的最后一个字段<mss 1024>表示由发端指明的最大报文段长度选项。发端将
不接收超过这个长度的 T C P报文段。这通常是为了避免分段(见 11 . 5节)。我们将在1 8 . 4节讨
论最大报文段长度,而在1 8 . 1 0节介绍不同TCP 选项的格式。

 

 建立连接协议

1) 请求端(通常称为客户)发送一个 S Y N段指明客户打算连接的服务器的端口,以及初
始序号(I S N,在这个例子中为1 4 1 5 5 3 1 5 2 1)。这个S Y N段为报文段1。
2) 服务器发回包含服务器的初始序号的 S Y N报文段(报文段2)作为应答。同时,将确认
序号设置为客户的I S N加1以对客户的S Y N报文段进行确认。一个S Y N将占用一个序号。
3) 客户必须将确认序号设置为服务器的 I S N加1以对服务器的S Y N报文段进行确认(报文
段3)。
这三个报文段完成连接的建立。这个过程也称为三次握手( three-way handshake)。

发送第一个S Y N的一端将执行主动打开( active open)。接收这个S Y N并发回下一个S Y N
的另一端执行被动打开(passive open)

当一端为建立连接而发送它的 S Y N时,它为连接选择一个初始序号。 I S N随时间而变化,
因此每个连接都将具有不同的 I S N。RFC 793 [Postel 1981c]指出I S N可看作是一个3 2比特的计
数器,每4 m s加1。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送,而
导致某个连接的一方对它作错误的解释。

 

报文段3与报文段4之间4 . 1秒的时间间隔是建立 T C P连接到向t e l n e t键入q u i t命令来中止该
连接的时间。

 

连接终止协议

建立一个连接需要三次握手,而终止一个连接要经过 4次握手。这由T C P的半关闭(h a l f -c l o s e)造成的。既然一个T C P连接是全双工(即数据在两个方向上能同时传递),因此每个方向必须单独地进行关闭。这原则就是当一方完成它的数据发送任务后就能发送一个 F I N来终止这个方向连接。当一端收到一个 F I N,它必须通知应用层另一端几经终止了那个方向的数据传送。发送F I N通常是应用层进行关闭的结果

 

收到一个F I N只意味着在这一方向上没有数据流动。一个 T C P连接在收到一个F I N后仍能发送数据。而这对利用半关闭的应用来说是可能的,尽管在实际应用中只有很少的 T C P应用

程序这样做。正常关闭过程如图1 8 - 3所示。我们将在1 8 . 5节中详细介绍半关闭。

 

 

 

当服务器收到这个 F I N,它发回一个A C K,确认序号为收到的序号加 1(报文段5)。和S Y N一样,一个F I N将占用一个序号。同时T C P服务器还向应用程序(即丢弃服务器)传送一个文件结束符。接着这个服务器程序就关闭它的连接,导致它的 T C P端发送一个F I N(报文段6),客户必须发回一个确认,并将确认序号设置为收到序号加1(报文段7)。

 

图1 8 - 4显示了终止一个连接的典型握手顺序。我们省略了序号。在这个图中,发送F I N将导致应用程序关闭它们的连接,这些F I N的A C K是由T C P软件自动产生的。

 

连接建立的超时

很多情况导致无法建立连接。一种情况是服务器主机没有处于正常状态。为了模拟这种情
况,我们断开服务器主机的电缆线,然后向它发出t e l n e t命令。图1 8 - 6显示了t c p d u m p的输出。

在这个输出中有趣的一点是客户间隔多长时间发送一个 S Y N,试图建立连接。第2个S Y N与第1个的间隔是5 . 8秒,而第3个与第2个的间隔是2 4秒。

 

第一次超时时间

 

这是因为B S D版的T C P软件采用一种500 ms的定时器。这种500 ms的定时器用于确定本章中所有的各种各样的T C P超时。当我们键入t e l n e t命令,将建立一个6秒的定时器(1 2个时钟滴答(t i c k)),但它可能在之后的 5 . 5秒~ 6秒内的任意时刻超时。图 1 8 - 7显示了这一发生过程。尽管定时器初始化为 1 2个时钟滴答,但定时计数器会在设置后的第一个 0~500 ms中的任意时刻减1。从那以后,定时计数器大约每隔 500 ms减1,但在第1个500 ms内是可变的(我们使用限定词“大约”是因为在 T C P每隔500 ms获得系统控制的瞬间,系统内核可能会优先处理其他中断)

 

 

当滴答计数器为 0时,6秒的定时器便会超时(见图 1 8 - 7),这个定时器会在以后的 2 4秒
(4 8个滴答)重新复位。之后的下一个定时器将更接近 2 4秒,因为当T C P的500 ms定时器被内
核调用时,它就会被修改一次。

 

最大报文段长度

最大报文段长度(M S S)表示T C P传往另一端的最大块数据的长度。当一个连接建立时,连接的双方都要通告各自的 M S S。我们已经见过M S S都是1 0 2 4。这导致I P数据报通常是4 0字节长:2 0字节的T C P首部和2 0字节的I P首部。在有些书中,将它看作可“协商”选项。它并不是任何条件下都可协商。当建立一个连接时,每一方都有用于通告它期望接收的 M S S选项(M S S选项只能出现在S Y N报文段中)。如果一方不接收来自另一方的 M S S值,则M S S就定为默认值5 3 6字节(这个默认值允许2 0字节的I P首部和2 0字节的T C P首部以适合5 7 6字节I P数据报)。一般说来,如果没有分段发生, M S S还是越大越好(这也并不总是正确,参见图 2 4 - 3和图2 4 - 4中的例子)。报文段越大允许每个报文段传送的数据就越多,相对 I P和T C P首部有更高的网络利用率。当 T C P发送一个S Y N时,或者是因为一个本地应用进程想发起一个连接,或者是因为另一端的主机收到了一个连接请求,它能将 M S S值设置为外出接口上的 M T U长度减去固定的I P首部和T C P首部长度。对于一个以太网,M S S值可达1 4 6 0字节。使用IEEE 802.3的封装(参见2 . 2节),它的M S S可达1 4 5 2字节。在本章见到的涉及 B S D / 3 8 6和S V R 4的M S S为1 0 2 4,这是因为许多 B S D的实现版本需要

 

TCP的半关闭

 

T C P提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。这就是所谓的半关闭。正如我们早些时候提到的只有很少的应用程序使用它。为了使用这个特性,编程接口必须为应用程序提供一种方式来说明“我已经完成了数据传送,因此发送一个文件结束( F I N)给另一端,但我还想接收另一端发来的数据,直到它给我发来文件结束(F I N)”。

 

图1 8 - 1 0显示了一个半关闭的典型例子。让左方的客户端开始半关闭,当然也可以由另一端开始。开始的两个报文段和图1 8 - 4是相同的:初始端发出的 F I N,接着是另一端对这个 F I N的A C K报文段。但后面就和图1 8 - 4不同,因为接收半关闭的一方仍能发送数据。我们只显示一个数据报文段和一个A C K报文段,但可能发送了许多数据报文段(将在第 1 9章讨论数据报文段和确认报文段的交换)。当收到半关闭的一端在完成它的数据传送后,将发送一个F I N关闭这个方向的连接,这将传送一个文件结束符给发起这个半关闭的应用进程。当对第二个 F I N进行确认后,这个连接便彻底关闭了。

 

TCP的状态变迁图

我们已经介绍了许多有关发起和终止 T C P连接的规则。这些规则都能从图 1 8 - 1 2所示的状
态变迁图中得出。

 

TCP状态转移要点
TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不 会被释放。网络服务器程序要同时管理大量连接,所以很有必要保证无用连接完全断开,否则大量僵死的连接会浪费许多服务器资源。在众多TCP状态中,最值得 注意的状态有两个:CLOSE_WAIT和TIME_WAIT。  

1、LISTENING状态
FTP服务启动后首先处于侦听(LISTENING)状态。

2、ESTABLISHED状态
ESTABLISHED的意思是建立连接。表示两台机器正在通信
3、CLOSE_WAIT
    对方主动关闭连接或者网络异常导致连接中断,这时我方的状态会变成CLOSE_WAIT 此时我方要调用close()来使得连接正确关闭
4、TIME_WAIT
    我方主动调用close()断开连接,收到对方确认后状态变为TIME_WAIT。TCP协议规定TIME_WAIT状态会一直持续2MSL(即两倍的分 段最大生存期),以此来确保旧的连接状态不会对新连接产生影响。处于TIME_WAIT状态的连接占用的资源不会被内核释放,所以作为服务器,在可能的情 况下,尽量不要主动断开连接,以减少TIME_WAIT状态造成的资源浪费。
    目前有一种避免TIME_WAIT资源浪费的方法,就是关闭socket的LINGER选项。但这种做法是TCP协议不推荐使用的,在某些情况下这个操作可能会带来错误。
5、SYN_SENT状态

   SYN_SENT状态表示请求连接,当你要访问其它的计算机的服务时首先要发个同步信号给该端口,此时状态为SYN_SENT,如果连接成功了就变为 ESTABLISHED,此时SYN_SENT状态非常短暂。但如果发现SYN_SENT非常多且在向不同的机器发出,那你的机器可能中了冲击波或震荡波 之类的病毒了。这类病毒为了感染别的计算机,它就要扫描别的计算机,在扫描的过程中对每个要扫描的计算机都要发出了同步请求,这也是出现许多 SYN_SENT的原因。

根据TCP协议定义的3次握手断开连接规定,发起socket主动关闭的一方 socket将进入TIME_WAIT状态,TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),在Windows下默认为4分钟,即240秒,TIME_WAIT状态下的socket不能被回收使用. 具体现象是对于一个处理大量短连接的服务器,如果是由服务器主动关闭客户端的连接,将导致服务器端存在大量的处于TIME_WAIT状态的socket, 甚至比处于Established状态下的socket多的多,严重影响服务器的处理能力,甚至耗尽可用的socket,停止服务. TIME_WAIT是TCP协议用以保证被重新分配的socket不会受到之前残留的延迟重发报文影响的机制,是必要的逻辑保证.

复位报文段

 

我们已经介绍了T C P首部中的R S T比特是用于“复位”的。一般说来,无论何时一个报文段发往基准的连接( referenced connection)出现错误,T C P都会发出一个复位报文段(这里提到的“基准的连接”是指由目的 I P地址和目的端口号以及源 I P地址和源端口号指明的连接。这就是为什么RFC 793称之为插口)。

 

 

到不存在的端口的连接请求

产生复位的一种常见情况是当连接请求到达时,目的端口没有进程正在听。对于 U D P,我们在6 . 5节看到这种情况,当一个数据报到达目的端口时,该端口没在使用,它将产生一个I C M P端口不可达的信息。而T C P则使用复位。

 

Te l n e t客户程序会立即显示这个差错信息。图 1 8 - 1 4显示了对应这个命令的分组交换过程。

在这个图中需要注意的值是复位报文段中的序号字段和确认序号字段。因为 A C K比特在到达的报文段中没有被设置为 1,复位报文段中的序号被置为 0,确认序号被置为进入的I S N加上数据字节数。尽管在到达的报文段中没有真正的数据,但 S Y N比特从逻辑上占用了1字节的序号空间;因此,在这个例子中复位报文段中确认序号被置为 I S N与数据长度(0)、S Y N比特所占的1的总和。

 

异常终止一个连接

我们在1 8 . 2节中看到终止一个连接的正常方式是一方发送 F I N。有时这也称为有序释放(orderly release),因为在所有排队数据都已发送之后才发送 F I N,正常情况下没有任何数据丢失。但也有可能发送一个复位报文段而不是 F I N来中途释放一个连接。有时称这为异常释放(abortive release)。

异常终止一个连接对应用程序来说有两个优点:(1)丢弃任何待发数据并立即发送复位报文段;(2)R S T的接收方会区分另一端执行的是异常关闭还是正常关闭。应用程序使用的A P I必须提供产生异常关闭而不是正常关闭的手段

使用s o c k程序能够观察这种异常关闭的过程。 Socket API通过“linger on close”选项(S O _ L I N G E R)提供了这种异常关闭的能力。我们加上 - L选项并将停留时间设为 0。这将导致连接关闭时进行复位而不是正常的 F I N。我们连接到处于服务器上的 s o c k程序,并键入一输入行:

 

 

第6行对应为终止客户程序而键入的文件结束符(C o n t r o l _ D)。由于我们指明使用异常关闭而不是正常关闭(命令行中的- L 0选项),因此主机b s d i端的T C P发送一个R S T而不是通常的F I N。R S T报文段中包含一个序号和确认序号。需要注意的是 R S T报文段不会导致另一端产生任何响应,另一端根本不进行确认。收到R S T的一方将终止该连接,并通知应用层连接复位。

 

 我们在服务器上得到下面的差错信息

 

 

 这个服务器程序从网络中接收数据并将它接收的数据显示到其标准输出上。通常,从它的T C P上收到文件结束符后便将结束,但这里我们看到当收到 R S T时,它产生了一个差错。这个差错正是我们所期待的:连接被对方复位了。

 

TCP 服务器的设计

 大多数的T C P服务器进程是并发的。当一个新的连接请求到达服务器时,服务器接受这个请求,并调用一个新进程来处理这个新的客户请求。不同的操作系统使用不同的技术来调用新的服务器进程。在 U n i x系统下,常用的技术是使用 f o r k函数来创建新的进程。如果系统支持,也可使用轻型进程,即线程( t h r e a d)。我们感兴趣的是 T C P与若干并发服务器的交互作用。需要回答下面的问题:当一个服务器进程接受一来自客户进程的服务请求时是如何处理端口的?如果多个连接请求几乎同时到达会发生什么情况?

 

TCP服务器端口号

通过观察任何一个 T C P服务器,我们能了解 T C P如何处理端口号。我们使用 n e t s t a t
命令来观察 Te l n e t服务器。下面是在没有 Te l n e t连接时的显示(只留下显示 Te l n e t服务器的
行)。

 

sun % netstat -a -n -f inet

 

- a标志将显示网络中的所有主机端,而不仅仅是处于 E S TA B L I S H E D的主机端。- n标志
将以点分十进制的形式显示 I P地址,而不是通过 D N S将地址转化为主机名,同时还要求显示
端口号(例如为 2 3)而不是服务名称(如 Te l n e t)。-f inet选项则仅要求显示使用 T C P或
U D P的主机

 

 

呼入连接请求队列

一个并发服务器调用一个新的进程来处理每个客户请求,因此处于被动连接请求的服务器应该始终准备处理下一个呼入的连接请求。那正是使用并发服务器的根本原因。但仍有可能出现当服务器在创建一个新的进程时,或操作系统正忙于处理优先级更高的进程时,到达多个连接请求。当服务器正处于忙时, T C P是如何处理这些呼入的连接请求

在伯克利的T C P实现中采用以下规则:

 

1) 正等待连接请求的一端有一个固定长度的连接队列,该队列中的连接已被 T C P接受(即三次握手已经完成),但还没有被应用层所接受。注意区分T C P接受一个连接是将其放入这个队列,而应用层接受连接是将其从该队列中移出。

2) 应用层将指明该队列的最大长度,这个值通常称为积压值 ( b a c k l o g )。它的取值范围是0 ~ 5之间的整数,包括0和5(大多数的应用程序都将这个值说明为 5)。

 

3) 当一个连接请求(即S Y N)到达时,T C P使用一个算法,根据当前连接队列中的连接数来确定是否接收这个连接。我们期望应用层说明的积压值为这一端点所能允许接受连接的最大数目,但情况不是那么简单。图1 8 - 2 3显示了积压值与传统的伯克利系统和S o l a r i s2 . 2所能允许的最大接受连接数之间的关系。注意,积压值说明的是 T C P监听的端点已被T C P接受而等待应用层接受的最大连接数。这个积压值对系统所允许的最大连接数,或者并发服务器所能并发处理的客户数,并无影响。

4) 如果对于新的连接请求,该 T C P监听的端点的连接队列中还有空间(基于图 1 8 - 2 3),T C P模块将对S Y N进行确认并完成连接的建立。但应用层只有在三次握手中的第三个报文段收到后才会知道这个新连接时。另外,当客户进程的主动打开成功但服务器的应用层还不知道这个新的连接时,它可能会认为服务器进程已经准备好接收数据了(如果发生这种情况,服务器的T C P仅将接收的数据放入缓冲队列)。

5) 如果对于新的连接请求,连接队列中已没有空间, T C P将不理会收到的 S Y N。也不发回任何报文段(即不发回 R S T)。如果应用层不能及时接受已被 T C P接受的连接,这些连接可能占满整个连接队列,客户的主动打开最终将超时。

 

 

posted on 2018-06-10 17:05  duan2  阅读(463)  评论(0编辑  收藏  举报