收藏 分享(赏)

TCP-IP详解卷三:TCP事务协议,HTTP,NNTP和UNIX域协议.pdf

上传人:wenkunet 文档编号:6993 上传时间:2018-05-21 格式:PDF 页数:250 大小:12.03MB
下载 相关 举报
TCP-IP详解卷三:TCP事务协议,HTTP,NNTP和UNIX域协议.pdf_第1页
第1页 / 共250页
TCP-IP详解卷三:TCP事务协议,HTTP,NNTP和UNIX域协议.pdf_第2页
第2页 / 共250页
TCP-IP详解卷三:TCP事务协议,HTTP,NNTP和UNIX域协议.pdf_第3页
第3页 / 共250页
TCP-IP详解卷三:TCP事务协议,HTTP,NNTP和UNIX域协议.pdf_第4页
第4页 / 共250页
TCP-IP详解卷三:TCP事务协议,HTTP,NNTP和UNIX域协议.pdf_第5页
第5页 / 共250页
点击查看更多>>
资源描述

1、下载第 1章 T/TCP 概 述1.1 概述本章首先介绍客户-服务器事务概念。我们从使用 U D P的客户-服务器应用开始,这是最简单的情形。接着我们编写使用 T C P的客户和服务器程序,并由此考察两台主机间交互的T C P / I P分组。然后我们使用 T / T C P,证明利用 T / T C P可以减少分组数,并给出为利用 T / T C P需要对两端的源代码所做的最少改动。接下来介绍了运行书中示例程序的测试网络,并对分别使用 U D P、 T C P和 T / T C P的客户 -服务器应用程序进行了简单的时间耗费比较。我们考察了一些使用 T C P的典型 I n t e r n

2、e t应用程序,看看如果两端都支持 T / T C P,将需要做哪些修改。紧接着,简要介绍了 I n t e r n e t协议族中事务协议的发展历史,概略叙述了现有的 T / T C P实现。本书全文以及有关 T / T C P的文献中,事务一词的含义都是指客户向服务器发出一个请求,然后服务器对该请求作出应答。 I n t e r n e t中最常见的一个例子是,客户向域名服务器 ( D N S )发出请求,查询域名对应的 I P地址,然后域名服务器给出响应。本书中的事务这个术语并没有数据库中的事务那样的含义:加锁、两步提交、回退,等等。1.2 UDP上的客户 -服务器我们先来看一个简单的

3、U D P客户-服务器应用程序的例子,其客户程序源代码如图 1 - 1所示。在这个例子中,客户向服务器发出一个请求,服务器处理该请求,然后发回一个应答。图 1-1 UDP上的简单客户程序第一部分 TCP事务协议图 1-1 (续 )本书中所有源代码的格式都是这样。每一非空行前面都标有行号。正文中叙述某段源代码时,这段源代码的起始和结束行号标记于正文段落的左边,如下面的正文所示。有时这些段落前面会有一小段说明,对所描述的源代码进行概要说明。源代码段开头和结尾处的水平线标明源代码段所在的文件名。这些文件名通常都是指我们在 1 . 9节中将介绍的 4 . 4版 B S D - L i t e中发布的文

4、件。我们来讨论这个程序的一些有关特性,但不详细描述插口函数,因为我们假设读者对这些函数有一些基本的认识。关于插口函数的细节在参考书 Stevens 1990的第 6章中可以找到。图 1 - 2给出了头文件 c l i s e r v . h。1. 创建 U D P插口1 0 - 1 1 s o c k e t函数用于创建一个 U D P插口,并将一个非负的插口描述符返回给调用进程。出错处理函数 e r r _ s y s参见参考书 Stevens 1992的附录 B . 2。这个函数可以接受任意数目的参数,但要用 v s p r i n t f函数对它们格式化,然后这个函数会打印出系统调用所返

5、回的e r r n o值所对应的 U n i x出错信息,然后终止进程。2. 填写服务器地址1 2 - 1 5 首先用 m e m s e t函数将 I n t e r n e t插口地址结构清零, 然后填入服务器的 I P地址和端口号。为简明起见,我们要求用户在程序运行中通过命令行输入一个点分十进制数形式的 I P地址(a r g v 1 )。服务器端口号 (U D P _ S E R V _ P O R T)在头文件 c l i s e r v . h中用 # d e f i n e定义,在本章的所有程序首部中都包含了该头文件。这样做是为了使程序简洁,并避免使调用g e t h o s t

6、 b y n a m e和 g e t s e r v b y n a m e函数的源代码复杂化。3. 构造并向服务器发送请求1 6 - 1 9 客户程序构造一个请求 (只用一行注释来表示 ),并用 s e n d t o函数将其发出,这样就有一个 U D P数据报发往服务器。同样是为了简明起见,我们假设请求 (R E Q U E S T)和应答(R E P L Y)的报文长度为固定值。实用的程序应当按照请求和应答的最大长度来分配缓存空间,但实际的请求和应答报文长度是变化的,而且一般都比较小。4. 读取和处理服务器的应答2 0 - 2 3 调用 r e c v f r o m函数将使进程阻塞

7、(即置为睡眠状态 ),直至收到一个数据报。接着客户进程处理应答 (用一行注释来表示 ),然后进程终止。由于 r e c v f r o m函数中没有超时机制,请求报文或应答报文中任何一个丢失都将造成该进程永久挂起。事实上, U D P客户 -服务器应用的一个基本问题就是对现实世界中的此类错误缺少健壮性。在本节的末尾将对这个问题做更详细的讨论。2计计 第一部分 TCP事务协议 下载在头文件 c l i s e r v . h中,我们将 S A定义为 struct sockaddr*,即指向一般的插口地址结构的指针。每当有一个插口函数需要一个指向插口地址结构的指针时,该指针必须被置为指向一个一般性

8、插口地址结构的指针。这是由于插口函数先于ANSI C标准出现,在 8 0年代早期开发插口函数的时候, v o i d *(空类型 )指针类型尚不可用。问题是, “ struct sockaddr*”总共有 1 7个字符,这经常使这一行源代码超出屏幕 (或书本页面 )的右边界,因此我们将其缩写成为 S A。这个缩写是从 B S D内核源代码中借用过来的。图 1 - 2给出了在本章所有程序中都包含的头文件 c l i s e r v . h。图 1-2 本章各程序中均包含的头文件 c l i s e r v . h图 1 - 3给出了相应的 U D P服务器程序。图 1-3 与图 1 - 1的 U

9、 D P客户程序对应的 U D P服务器程序第 1章 T / T C P概述 计计 3下载图 1-3 (续 )5. 创建 U D P插口和绑定本机地址8 - 1 5 调用 s o c k e t函数创建一个 U D P插口,并在其 I n t e r n e t插口地址结构中填入服务器的本机地址。这里本机地址设置为通配符 (I N A D D R _ A N Y),这意味着服务器可以从任何一个本机接口接收数据报 (假设服务器是多宿主的,即可以有多个网络接口 )。端口号设为服务器的知名端口 (U D P _ S E R V _ P O R T),该常量也在前面讲过的头文件 c l i s e r

10、 v . h中定义。本机 I P地址和知名端口用 b i n d函数绑定到插口上。6. 处理客户请求1 6 - 2 5 接下来,服务器程序就进入一个无限循环:等待客户程序的请求到达 (r e c v f r o m),处理该请求 (我们只用一行注释来表示处理动作 ),然后发出应答 (s e n d t o)。这只是最简单的 U D P客户-服务器应用。实际中常见的例子是域名服务系统 ( D N S )。 D N S客户 (称作解析器 )通常是一般客户应用程序 (例如, Te l n e t客户、 F T P客户或 W W W浏览器 )的一个部分。解析器向 D N S服务器发出一个 U D P数

11、据报,查询某一域名对应的 I P地址。服务器发回的应答通常也是一个 U D P数据报。如果观察客户向服务器发送请求时双方交换的分组,我们就会得到图 1 - 4这样的时间系列,页面上时间自上而下递增。服务器程序先启动,其行为过程给在图 1 - 4的右半部,客户程序稍后启动。我们分别来看客户和服务器程序中调用的函数及其相应内核执行的动作。在对 s o c k e t函数的两次调用中,上下紧挨着的两个箭头表示内核执行请求的动作并立即返回。在调用s e n d t o函数时,尽管内核也立即返回,但实际上已经发出了一个 U D P数据报。为简明起见,我们假设客户程序的请求和服务器程序的应答所生成的 I

12、P数据报的长度都小于网络的最大传输单元 ( M T U ), I P数据报不必分段。在这个图中,有两次调用 r e c v f r o m函数使进程睡眠,直到有数据报到达才被唤醒。我们把内核中相应的例程记为 s l e e p和 w a k e u p。最后,我们还在图中标出了事务所耗费的时间。图 1 - 4的左侧标示的是客户端测得的事务时间:从客户发出请求到收到服务器的应答所经历的时间。组成这段事务时间的数值标在图的右侧: RTT + SPT,其中 RT T是网络往返时间, S P T是服务器处理客户请求的时间。 U D P客户-服务器事务的最短时间就是 RTT + SPT。4计计 第一部分

13、 TCP事务协议 下载图 1-4 UDP客户-服务器事务的时序图尽管没有明确说明,但我们已经假设从客户到服务器的路径需要 1/2 RT T时间,返回的路径又需 1/2 RT T时间。但实际情况并非总是如此。据对大约 6 0 0条 I n t e r n e t路径的研究 Paxson 1995b发现: 3 0 %的路径呈现明显的不对称性,说明两个方向上的路由经过了不同的站点。我们的 U D P客户-服务器看起来非常简捷 (每个程序只有大约 3 0行有关网络的源代码 ),但在实际环境中应用还不够健壮。由于 U D P是不保证可靠的协议,数据报可能会丢失、失序或重复,因此实用的应用程序必须处理这些

14、问题。这通常是在客户程序调用 r e c v f r o m时设置一个超时定时器,用以检测数据报的丢失,并重传请求。如果要使用超时定时器,客户程序就要测量 RT T并动态更新,这是因为互连网上的 RT T会在很大范围内变化,并且变化很快。但如果是服务器的应答丢失,而不是请求,那么服务器就要再次处理同一个请求,这可能会给某些服务带来问题。解决这个问题的办法之一是让服务器将每个客户最近一次请求的响应暂存起来,必要时重传这个应答即可,而不需要再次处理这个请求。最后,典型的情况是,客户向服务器发送的每个请求中都有一个不同的标识,服务器把这个标识在响应中传回来,使客户能把请求和响应匹配起来。在参考书 S

15、tevens 1990的 8 . 4节中给出了 U D P上的客户-服务器处理这些问题的源代码细节,但这将在程序中增加大约 5 0 0行源代码。一方面,许多 U D P应用程序都通过执行所有这些额外步骤 (超时机制、 RT T值测量、请求标识,等等 )来增加可靠性;另一方面,随着新的 U D P应用程序不断出现,这些步骤也在不断地推陈出新。参考书 Patridge 1990b中指出, “为了开发可靠的 U D P应用程序 ,你要有状态信息 (序列号、重传计数器和往返时间估计器 ),原则上你要用到当前 T C P连接块中的全部信第 1章 T / T C P概述 计计 5下载客户端函数 内核 网络

16、 内核服务器端函数返回进程请求返回息。因此,构筑一个可靠的 U D P ,本质上和开发 T C P一样难” 。有些应用程序并不实现上面所述的所有步骤:例如在接收时使用超时机制,但并不测量RT T值,当然更不会动态地更新 RT T值。这样,当应用程序从一个环境 (比如局域网 )移植到另一个环境 (比如广域网 )中应用时,就可能会引发一些问题。比较好的解决办法是用 TCP 而不是用U D P,这样就可以利用 T C P提供的所有可靠传输特性。但是这种办法会使客户端测得的事务时间由 RTT + SPT增加到 2 RTT + SPT(见下一节 ),而且还会大大增加两个系统之间交换的分组数目。对付这些新

17、的问题也有一个办法,即用 T / T C P取代 T C P,我们将在 1 . 4节中对此进行讨论。1.3 TCP上的客户 -服务器下一个例子是 T C P上的客户-服务器事务应用。图 1 - 5给出了客户程序。图 1-5 TCP事务的客户1. 创建 T C P插口和连接到服务器1 0 - 1 7 调用 s o c k e t函数创建一个 T C P插口,然后在 I n t e r n e t插口地址结构中填入服务器的 I P地址和端口号。对 c o n n e c t函数的调用启动 T C P的三次握手过程,在客户和服务器之间建立起连接。卷 1的第 1 8章给出了 T C P连接建立和释放过

18、程中交换分组的详细情况。2. 发送请求和半关闭连接1 9 - 2 2 客户的请求是用 w r i t e函数发给服务器的。之后客户调用 s h u t d o w n函数 (函数的第 26计计 第一部分 TCP事务协议 下载个参数为 1 )关闭连接的一半,即数据流从客户向服务器的方向。这就告知服务器客户的数据已经发完了:从客户端向服务器传递了一个文件结束的通知。这时有一个设置了 F I N标志的T C P报文段发给服务器。客户此时仍然能够从连接中读取数据 只关闭了一个方向的数据流。这就叫做 T C P的半关闭 ( h a l f - c l o s e )。卷 1的第 1 8 . 5节给出了有

19、关细节。3. 读取应答2 3 - 2 4 读取应答是由函数 r e a d _ s t r e a m完成的,如图 1 - 6所示。由于 T C P是一个面向字节流的协议,没有任何形式的记录定界符,因而从服务器端 T C P传回的应答可能会包含在多个T C P报文段中。这也就可能会需要多次调用 r e a d函数才能传递给客户进程。而且我们知道,当服务器发送完应答后就会关闭连接,使得 T C P向客户端发送一个带 F I N的报文段,在 r e a d函数中返回一个文件结束标志 (返回值为 0 )。为了处理这些细节问题,在 r e a d _ s t r e a m函数中不断调用 r e a

20、d函数直到接收缓存满或者 r e a d函数返回一个文件结束标志。 r e a d _ s t r e a m函数的返回值就是读取到的字节数。图 1-6 r e a d _ s t r e a m 函数还有一些别的方法可以在类似 T C P这样的流协议中用来给记录定界。许多I n t e r n e t应用程序 ( F T P、 S M T P、 H T T P和 N N T P )使用回车和换行符来标记记录的结束。其他一些应用程序 ( D N S, R P C )则在每个记录的前面加上一个定长的记录长度字段。在我们的例子中,利用了 T C P的文件结束标志 ( F I N ),因为在每次事务

21、中客户只向服务器发送一个请求,而服务器也只发回一个应答。 F T P也在其数据连接中采用了这项技术,用以告知对方文件已经结束。图 1 - 7给出的是 T C P的服务器程序。图 1-7 TCP事务的服务器程序第 1章 T / T C P概述 计计 7下载图 1-7 (续 )4. 创建监听用 T C P插口8 - 1 7 用于创建一个 T C P插口,并将服务器的知名端口绑定到该插口上。与 U D P服务器一样,T C P服务器也将通配符作为其 I P地址。调用 l i s t e n函数将新创建的插口作为监听插口,用于等待客户端发起的连接。 l i s t e n函数的第二个参数规定了允许的最

22、大挂起连接数,内核要为该插口将这些连接进行排队处理。S O M A X C O N N在头文件 中定义。其数值过去一直都取 5,但现在有一些比较新的系统将其定为 1 0。对于一些很繁忙的服务器 (例如: We b服务器 ),已经发现需要取更大的值,比如 256或 1024。在 14.5节中我们还将对此问题进行更多的讨论。5. 接受连接和处理请求1 8 - 2 8 服务器进程调用 a c c e p t函数后就进入阻塞状态,直到有客户进程调用 c o n n e c t函数而建立起一个连接。函数 a c c e p t返回一个新的插口描述符 s o c k f d,代表与客户和服务器之间所建立的

23、连接。服务器调用函数 r e a d _ s t r e a m读取客户的请求 (图 1 - 6 ),再调用 w r i t e函数向客户发送应答。这是一个反复循环的服务器:把当前的客户请求处理完毕后才又调用 a c c e p t去接受另一个客户的连接。并发服务器可以并行地处理多个客户请求 (即:同时处理 )。在 U n i x的主机上实现并发服务器的常用技术是:在 a c c e p t函数返回后,调用 U n i x的f o r k函数创建一个子进程,由子进程处理客户的请求,父进程则紧接着又调用a c c e p t去接受别的客户连接。实现并发服务器的另一项技术是为每个新建立的连接8计计

24、 第一部分 TCP事务协议 下载创建一个线程 (叫做轻量进程 )。为了避免那些与网络无关的进程控制函数把我们的例子搞复杂,我们只给出了反复循环的服务器。参考书 Stevens 1992的第 4章讨论比较了循环服务器和并发服务器。还有第三个选择是采用预分支服务器。即服务器启动时连续调用 f o r k函数数次,并让每个子进程都在同一个监听插口描述符上调用 a c c e p t函数。这种办法节省了为每个客户的连接请求临时创建子进程的时间开销,这对于繁忙的服务器来说,是很大的节省。有些 H T T P服务器就采用了这项技术。图 1 - 8给出了 T C P上客户-服务器事务的时间系列。我们首先注意

25、到,与图 1 - 4中 U D P上的第 1章 T / T C P概述 计计 9下载客户端函 数 内 核 网 络 内 核 函 数服务器端返回 (数据 )返回返回(数据 )进程请求图 1-8 TCP上客户-服务器事务的时序事务相比,网络上交换的分组数增加了: T C P上事务的分组数是 9,而 U D P上的则是 2。采用T C P后,客户端测量的事务时间是不少于 2 RTT + SPT。通常,中间三个从客户到服务器的报文段 (对服务器 S Y N的 A C K、请求以及客户的 F I N )是紧密相连的;后面两个从服务器到客户的报文段 (服务器的应答和 F I N )也是紧密相连的。这使实际事

26、务时间比从图 1 - 8中看到的更接近2 RTT + SPT。本例中多出来的一个 RT T源于 T C P连接建立的时间开销:图 1 - 8中前两个报文段所花的时间。如果 T C P可以把建连和发送客户数据以及客户 F I N (图中客户端发出的前四个报文段 )合起来,再把服务器的应答和 F I N合起来,事务时间就又可以回到 RTT + SPT了,这与 U D P的一样。事实上,这就是 T / T C P中采用的基本技巧。6. TCP的 T I M E _ WA I T状态T C P要求,首先发出 F I N的一端 (我们的例子中是客户 ),在通信双方都完全关闭连接之后,仍然要保持在 T I

27、 M E _ WA I T状态直至两倍的报文段最大生存时间 ( M S L )。 M S L的建议值是 1 2 0秒,也即处于 T I M E _ WAT E状态要达到 4分钟。当连接处于 T I M E _ WA I T状态时,同一连接 (即客户 I P地址和端口号,以及服务器 I P地址和端口号这 4个值相同 )不能重复打开 (我们在第 4章中还要更多地讨论 T I M E _ WA I T状态 )。许多基于伯克利代码的 T C P实现,在 T I M E _ WA I T状态的保持时间仅仅为 6 0秒,而不是 RFC 1122 Braden 1989中指定的 2 4 0秒。在本书的所有计

28、算中,我们还是假定正确的等待周期为 2 4 0秒。在我们的例子中,客户端首先发出 F I N,这称为主动关闭,因而 T I M E _ WA I T状态出现在客户端。在这个状态延续期内, T C P要为这个已经关闭的连接保留一定的状态信息,以便能正确处理那些在网络中延迟一段时间、在连接关闭之后到达的报文段。同样,如果最后一个A C K丢失了,服务器将重传 F I N,使客户端重传最后的 A C K。其他一些应用程序,特别是 W W W中的 H T T P,要求客户程序发送一个专门的命令来指示已经将请求发送完毕 (而不是像我们的客户程序那样采用半关闭连接的办法 );接着服务器就发回应答,紧接着就

29、是服务器的 F I N。然后客户程序再发出 F I N。这样做与前面所述的不同之处在于,现在的 T I M E _ WA I T状态出现在服务器端而不是客户端。对许多客户访问的繁忙服务器来说,需要保留的状态信息会占用服务器的大量内存。因此,当设计一个事务性客户服务器应用程序时,让连接的哪一端关闭后进入 T I M E _ WA I T状态值得仔细斟酌。我们还将看到,T / T C P可以让 T I M E _ WA I T状态的延续时间从 2 4 0秒减少到大约 1 2秒。7. 减少 T C P中的报文段数像图 1 - 9所示的那样, 把数据和控制报文段合并起来可以减少图 1 - 8中所示的

30、T C P报文段数。请注意,这里的第一个报文段中包含有 S Y N、数据和 F I N,而不像图 1 - 8中那样仅仅是 S Y N。类似地,服务器的应答和服务器的 F I N也可以合并。虽然这样的分组序列也符合 T C P的规定,但是作者无法在应用程序中利用现有的插口 A P I使 T C P产生这样的报文段序列 (因此才在图 1 - 9中客户端产生第一个报文段时和服务器端产生最后一个报文段时标上了问号 );而且据作者所知,也没有哪一个应用程序确实生成了这样的报文段序列。值得一提的是,尽管我们把报文段的数目由 9减少到了 5,但客户端观测的事务依然是 2RTT + SPT。这是因为 T C P中规定,服务器端的 T C P在三次握手结束之前不能向服务器进程提交数据 (卷 2的第 2 7 . 9节说明了 T C P是如何在连接建立之前将到达的数据进行排队缓存的 )。加10计计 第一部分 TCP事务协议 下载

展开阅读全文
相关资源
相关搜索
资源标签

当前位置:首页 > 网络技术 > 后端技术

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:文库网官方知乎号:文库网

经营许可证编号: 粤ICP备2021046453号世界地图

文库网官网©版权所有2025营业执照举报