贝贝花花包包店,精品555皮具,钱夹,皮夹

字体: | 推荐给好友 上一篇 | 下一篇

ACE应用-第2章 JAWS:高性能Web服务器构架

发布: 2008-6-13 13:46 | 作者: Douglas C. Schmidt | 来源: 转载 | 查看: 269次

 
2.3.7 JAWS构架回顾
 
2.2激发了对通过构架和模式来构建高性能Web服务器的需要。我们使用JAWS作为例子来演示构架和模式是怎样使程序员避开开发Web服务器软件的常见陷阱的。模式和构架共同支持集成化组件和设计抽象的复用 [4]。
2.3描述怎样建构JAWS构架,以及它所提供的策略。为了清晰地说明JAWS的设计组织,我们概述了对JAWS构架有最大影响的战略和战术设计模式。最为重要的战略模式有接受器反应堆前摄器主动对象服务配置器模式,等等。策略适配器状态单体模式是JAWS中所用的有影响的战术模式。
这些模式被用来提供JAWS体系结构的“脚手架”。它们描述了必需的、形式为较小的组件的协作实体。从这里开始,构架的主要组件(也就是,并发策略I/O策略协议流水线缓存式虚拟文件系统构架)被构建和集成进在一个骨架应用中。通过定制构架的特定子组件(例如,过滤器缓存策略),开发者可以使用该骨架来构造专门的Web服务器软件系统。
图2-17显示JAWS构架的所有模式和组件是怎样集成的。JAWS构架以下面的方式来推动高性能Web服务器的构建。首先,它提供若干预配置的并发和I/O分派模型、一个提供标准的缓存替换策略的文件缓存,以及一个用于实现协议流水线的构架。其次,JAWS中所用的模式有助于使Web服务器策略与(1)实现细节和(2)配置时间去耦合。这样的去耦合使得新策略可以很容易地集成进JAWS。最后,JAWS的设计允许服务器静态和动态地改变它的行为。例如,通过适当的策略Profile,JAWS可以适应在Web服务器执行期间所发生的不同情况。通过进行动态适配来应用这些可扩展的策略和组件,JAWS简化了高性能Web服务器的开发和配置。
 
2.4 Web服务器基准测试床和实验结果
 
2.3描述的模式和构架组件使得JAWS能够静态和动态地适应它的环境。尽管这样的灵活性是有益的,Web服务器的成功最终还是要依赖于它怎样满足Internet以及企业Intranet的性能需求。要满足这些需求,需要对影响Web服务器性能的关键因素有全面的了解。
这一部分描述在系统地将不同负载条件应用于JAWS的不同配置时,我们所获得的性能结果。这些结果说明了为什么没有哪种配置能够在所有负载条件下最优地执行。这也论证了对像JAWS这样的灵活的构架的需要;这样的构架可在变化的负载条件下重配置、以获取最优性能。
 
 
图2-17 JAWS Web服务器构架
 
2.4.1 硬件测试床
 
我们的硬件测试床如图2-18所示。测试床由两台Micron Millennia PRO2 plus工作站组成。每台PRO2有128 MB RAM,并配有2个Pentium Pro处理器。客户机的时钟速度为200 MHZ,而服务器则为180 MHZ。此外,每台PRO2还有一块由Efficient Networks, Inc制造的ENI-155P-MF-S ATM卡,并由Orca 3.01驱动软件来驱动。两台工作站经由ATM网络相连,网络通过FORE Systems ASX-200BX运行,最大带宽为622 Mbps。但是,由于LAN竞争模式的限制,我们的测试床的最高带宽大约为120 Mbps。
 
 
图2-18 基准测试床概览
 
2.4.2 软件请求生成器Software Request Generator
 
我们使用WebSTONE[32] v2.0基准测试软件来收集客户和服务器端的测试数据。这些数据包括服务器平均吞吐量客户平均响应时间。WebSTONE是一个标准的基准测试工具,可以生成负载请求、模拟典型的Web服务器文件访问模式。我们的实验使用WebSTONE来为特定大小的文件生成负载及收集统计数据,以确定不同的并发和事件分派策略的影响。
在此测试中所用的文件访问模式如表2-1所示。该表显示在流行的服务器上的实际负载条件,其数据来源于SPEC所指导的一项对文件访问模式的研究[33]。
 
文档大小
频度
500字节
5K字节
50K字节
5M字节
35%
50%
14%
1%
表2-1 文件访问模式
 
2.4.3 实验结果
 
下面给出的结果比较了JAWS Web服务器的若干不同的适配版本的性能。我们将讨论不同的事件分派和I/O模型对于吞吐量和响应时间的影响。为这次实验,使用了JAWS的三种适配版本。
 
1.    同步Thread-per-Request在此适配版本中,JAWS被配置成派生一个新线程来处理每个到来的请求,并且使用同步I/O。
2.    同步线程池:JAWS被配置成在使用同步I/O的同时、预派生一个线程池来处理到来的请求。
3.    异步线程池:对于这种配置,JAWS被配置成在为异步I/O使用TransmitFile的同时、预先派生一个线程池来处理到来的请求。TransmitFile是Win32函数,它在网络连接上同步或异步地发送文件。
 
吞吐量被定义为每秒钟客户接收到的平均bit数。在客户基准测试软件发送HTTP请求之前,启动了一个高精度的用于吞吐量测量的定时器。只要连接在客户端一被关闭,定时器就会停止。接收到的bit数包括服务器发送的HTML头。
响应时间被定义为从客户发送请求开始,到完整地接受完文件为止、客户所看到的以毫秒为单位的延迟量。它测量在发送HTTP GET请求给Web服务器之后、并且在内容开始到达客户之前,最终用户必须等待多长时间。客户基准测试软件一发送HTTP请求,用于响应时间测量的定时器就会启动;客户一完成对所请求的来自服务器的文件的接收,定时器就会停止。
下面的五幅图分别是实验中所用的不同大小的文件(从500字节到5M字节,因子为10)的测试结果。这些文件大小代表在我们的实验中所测量的文件大小的“谱段”,用以揭示文件大小对性能都有什么影响。
 
2.4.3.1 吞吐量比较
 
图2-19到图2-23演示当所请求文件的大小和服务器点击率系统地增加时,吞吐量的变化情况。如我们所预期的,在每秒的连接数增长时,每个连接的吞吐量通常会退化。这源于正在被维护的同时连接数的增长,导致了每个连接吞吐量的下降。
如图2-21所示,当连接负载增长时,对于较小文件,Thread-per-Request的吞吐量有可能迅速退化。相反,同步线程池实现的吞吐量退化要更为温和。这种差异的原因是Thread-per-Request导致更高的线程创建开销,因为要为每个GET请求派生一个新线程。相反,线程池策略中的线程创建开销通过在服务器开始执行时预先派生线程而分摊了。
图2-19到2-23中的结果说明对于小文件(也就是,< 50K字节),TransmitFile执行得异常糟糕。我们的实验表明TransmitFile的性能直接依赖于同时请求数。我们相信在繁重的服务器负载情况下(也就是,高点击率),TransmitFile被迫在内核处理到来的请求时进行等待。这创建了数目很大的同时连接,从而降低了服务器性能。
但是在文件的的大小增长时,TransmitFile很快就胜过了同步分派模型。例如,在5M字节文件(在图2-23中显示)的繁重负载下,它超出下一种最为接近的模型大约40%。TransmitFile被优化以利用Windows NT内核特性,从而减少了数据拷贝和上下切换的次数。
 
2.4.3.2 响应时间比较
 
图2-19到2-23演示当所请求文件的大小和服务器点击率增加时,响应性能的变化情况。如我们所预期的,在每秒的连接数增长时,每个连接的响应时间通常也会变长。这反映出加在服务器上的额外负载,降低了它服务新客户请求的能力。
和前面一样,对于小文件,TransmitFile执行得异常糟糕。但是,在文件大小增长时,相对于轻负载情况下的同步分派,它的响应时间得到了迅速的改善。
 
2.4.3.3 基准测试结果总结
 
如这一部分中的结果所示,取决于并发和事件分派机制,吞吐量和响应时间有着显著的变化。对于小文件,同步线程池策略提供了更好的整体性能。在中等负载下,同步事件分派模型提供的响应时间要略微优于异步模型。但是,在传输大文件的繁重负载情况下,使用TransmistFile的异步模型提供了更好的服务质量。因而,在Windows NT下,取决于服务器的工作负载和文件请求的分布,理想的Web服务器应该将自身适配到合适的事件分派和文件I/O模型。
 
 
图2-19 500字节文件的实验结果
 
 
图2-20 5K文件的实验结果
 
 
图2-21 50K文件的实验结果
 
 
图2-22 500K文件的实验结果
 
 
图2-23 5M文件的实验结果
 
2.4.4 用于优化Web服务器的技术总结
 
在我们的研究中,我们已经发现有可能通过更好的服务器设计来改善服务器性能(在[34]中给出了类似的观察报告)。因而,在“硬编码”服务器(也就是,使用固定并发、I/O和缓存策略的服务器)能够不可否认地提供极好的性能的同时,灵活的服务器构架,比如JAWS,并不必然与糟糕的性能相联系。
这一部分总结决定Web服务器性能的最为重要的因素。这些观察报告基于我们对现有服务器设计和实现策略、以及我们调谐JAWS的经验的研究[1, 3]。这些研究揭示了开发高性能Web服务器的主要优化目标。
 
轻量级并发:如在[3]中所看到的,基于进程的并发机制可能会产生糟糕的性能。在多处理器系统中,基于进程的并发机制可以良好地执行,特别是在进程数目与处理器数目相等时。在这种情况下,每个处理器可以运行一个Web服务器进程,从而使上下文切换开销得以最小化。
通常,进程应被预先生成,以避免动态进程创建的开销。但是,更可取的方法是使用轻量级并发机制(例如,使用POSIX线程)来使上下文切换开销最小化。和进程一样,动态线程创建开销也可以通过在服务启动时将线程预先派生进线程池中来加以避免。
 
专用OS特性:OS供应商常常会提供能给出更好性能的专用编程接口。例如,Windows NT 4.0提供TransmitFile函数,使用Windows NT虚拟内存缓存管理器来获取文件数据。TransmitFile允许在文件数据之前和之后分别增加数据。这特别适用于Web服务器,因为它们通常与所请求文件一起发送HTTP头数据。因此,所有给客户的数据可以在单个的系统调用中发送,从而使模式切换开销得以最小化。
通常,这些接口必须相对于标准API仔细进行基准测试,以了解特定接口给出更好性能的条件。如2.4所示,在使用TransmitFile的情况下,我们的实验数据表明,在Windows NT上通过Socket传输大文件,异步形式的TransmitFile是最为高效的机制。
 
请求生存期系统调用开销:在Web服务器中,请求生存期被定义为服务器在它从客户接收HTTP请求之后、以及在它发送出所请求文件之前,所必须执行的一系列指令。执行请求生存期所用的时间直接影响客户观察到的响应时间。因此,在此路径上使系统调用开销和其他处理最小化是很重要的。下面描述在Web服务器中可以减少这样的开销的各种地方。
 
  • 减少同步:在处理并发时,常常需要通过同步来序列化对共享资源的访问(比如缓存式虚拟文件系统)。但是,使用同步会使性能恶化。因而,在请求生存期中使所获取(或释放)的锁的数目最小化是很重要的。在[3]中显示了每个请求所进行的平均锁操作数较低的服务器比进行大量锁操作的服务器执行得要好得多。
在某些情况下,获取和释放锁还可能导致占先(preemption)。因而,如果线程读进HTTP请求,随后试图获取一个锁,它就有可能会被占先,并可能在它被再次分派之前等待相对较长的时间。这会增加Web客户所经受的响应延迟。
  • 缓存文件:如果服务器不进行文件缓存,至少会带来两方面的开销。首先是来自open系统调用的开销。其次,反复使用read和write系统调用来访问文件系统会带来累积的开销,除非文件小到足以在单次调用中被获取或存储。使用在大多数形式的UNIX和Windows NT上可用的内存映射文件,可以有效地进行缓存。
  • 使用“集中-写”(gather-write):在UNIX系统中,writev系统调用允许在单个系统调用中将多个缓冲区写入设备。这对于Web服务器来说是有用的,因为除了所请求的文件,典型的服务器响应还含有许多行头信息。通过使用“集中-写”,不需要在发送前将这些头的行连接进单个缓冲区,从而避免了不必要的数据复制。
  • 预先计算的HTTP响应:典型的HTTP请求使得服务器发回HTTP头,其中含有HTTP成功代码和所请求文件的MIME类型(例如,text/plain)。因为这样的响应是预期情况的一部分,它们可以被预先计算。当文件进入缓存时,响应的HTTP响应也可以和文件存储在一起。于是当HTTP请求到达时,头在缓存中已直接可用了。
 
日志开销:大多数Web服务器允许管理员对他们所服务的不同页面的点击数进行日志记录。日志常常用于评估服务器在一天的不同时间里的负载情况。它还常常因为商业原因而使用,例如,网站可能基于页面的点击率来确定广告的费率。但是,因为以下原因,对HTTP请求进行日志记录会产生显著的开销:
 
  • 文件系统开销:繁忙的Web服务器执行相当多的I/O调用,从而压迫文件系统和底层硬件。将数据写到日志文件会增加这样的压力,从而导致更低的性能。将日志文件和HTTP文件放置在分开的文件系统上(且在分开的物理设备上,如果可能)可以限制这一开销。
  • 同步开销:典型的Web服务器有多个活动线程或进程在对请求进行服务。如果这些线程/进程需要将请求记录到公用的共享日志文件,对该日志文件的访问就需要被同步,也就是,在任何时刻至多只有一个线程/进程可以对该共享日志文件进行写操作。这样的同步引入了额外的开销,从而有害于性能。通过使用多个独立的日志文件,可以减少这种开销。如果使用了内存缓冲区,它们就应该被存储在线程专有存储(thread-specific storage)中,以消除锁定竞争。
  • 反向主机名查找:客户的IP地址对于Web服务器来说是在本地的。但是,在日志文件中主机名通常更为有用。因而,客户的IP地址需要被转换为相应的主机名。这通常是使用反向DNS查找来完成的。因为常常涉及网络I/O,这些查找非常昂贵。因此,它们应该被避免,或者异步地完成(使用线程或异步I/O)。
  • Ident查找:Ident协议[35]允许Web服务器获取给定HTTP连接的用户名。这通常涉及设置新的到用户机器的TCP/IP连接,因而也涉及了“往返旅程”(round-trip)延迟。还有,ident查找必须在HTTP连接仍在活动时执行,因此不能够“懒洋洋”地执行。因而,为获得高性能,只要可能,都应该避免进行这样的查找。
 
传输层优化:应该配置下面的传输层选项,以提高Web服务器在高速网络上的性能:
 
  • 侦听backlog大多数TCP实现都在驻留内核的“侦听队列”上缓冲到来的HTTP连接,以使服务器能够使用accept使它们出队、进行服务。如果TCP队列超出了listen调用的“backlog”参数,新的连接就将被TCP拒绝。因而,如果预计到来的连接的流量将会很大的话,就应该通过设置更大的backlog参数(这有可能需要修改OS内核)来增大内核队列的容量。
  • Socket发送缓冲区:每个Socket都有一个与之相关联的发送缓冲区,该缓冲区在数据正通过网络传输时持有这些由服务器发送的数据。为获得高性能,该缓冲区的大小应被设置为所允许的最大值(也就是,大缓冲区)。在Solaris,这个限制为64K。
  • Nagle算法(RFC 896):某些TCP/IP实现通过实现Nagle算法来避免拥塞(congestion)。这常常导致数据在实际通过网络发送之前、被网络层所迟滞。若干对响应时间有严格要求的应用(比如X-Windows)禁用了这一算法(例如,Solaris支持TCP_NO_DELAY Socket选项)。通过强制网络层尽可能快地发送数据,禁用这一算法可以改善响应时间。
 
2.5 结束语
 
在计算能力和网络带宽在过去十年间戏剧性增长的同时,开发通信软件所涉及的复杂性同样也发生了戏剧性增长。特别地,高性能Web服务器软件的设计和实现是昂贵而易错的。许多代价和工作都来自于对基本的设计模式和构架组件持续的重新发现和发明。而且,越来越多的硬件体系结构异种性和OS及网络平台间的差异使得从头开始构建正确、可移植和高效的Web服务器变得十分困难。
构建高性能Web服务器需要了解服务器中的每个子系统(例如,并发和事件分派、服务器请求处理、文件系统访问和数据传输)对于性能的影响。高效地实现和集成这些子系统要求开发者迎接各种设计挑战,并在可选的解决方案中进行选择。领会在这些可选方案之间进行的权衡对于提供最优性能来说是必需的。但是,在需求(不可避免地)变化时,开发特定设计所需的工作常常并非是经济的。例如,性能可能被证明为不足、可能需要另外的功能,或是软件需要被移植到不同的体系结构。
通过有效利用已被证明的设计模式和实现、以产生可被定制来满足新应用需求的可复用组件,面向对象应用构架和设计模式有助于减少开销、并改善软件的性能。在本论文中描述的JAWS构架演示了怎样简化和统一高性能Web服务器的开发。JAWS成功的关键是它能够捕捉常见的通信软件设计模式,并将这些模式统一进灵活的构架组件中;这些组件高效地封装并增强了低级的OS机制:并发、事件多路分离、动态配置、文件缓存,等等。这里给出的基准测试结果用于演示使用构架来开发高性能应用的有效性。它照亮了这一事实:可适应不同情况的软件与性能并非是对立的。
JAWS的源码和文档可在http://www.cs.wustl.edu/~schmidt/ACE.html找到。
 
参考文献
 
[1] J. Hu, I. Pyarali, and D. C. Schmidt, “Measuring the Impact of Event Dispatching and Concurrency Models on Web Server Performance Over High-speed Networks,” in Proceedings of the 2nd Global Internet Conference, IEEE, November 1997.
[2] I. Pyarali, T. H. Harrison, and D. C. Schmidt, “Design and Performance of an Object-Oriented Framework for High-Performance Electronic Medical Imaging,” USENIX Computing Systems, vol. 9, November/December 1996.
[3] J. Hu, S. Mungee, and D. C. Schmidt, “Principles for Developing and Measuring High-performance Web Servers over ATM,” in Proceeedings of INFOCOM ’98, March/April 1998.
[4] R. Johnson, “Frameworks = Patterns + Components,” Communications of the ACM, vol. 40, Oct. 1997.
[5] E. Gamma, R. Helm, R. Johnson, and J. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software. Reading, MA: Addison-Wesley, 1995.
[6] D. C. Schmidt and T. Suda, “An Object-Oriented Framework for Dynamically Configuring Extensible Distributed Communication Systems,” IEE/BCS Distributed Systems Engineering Journal (Special Issue on Configurable Distributed Systems), vol. 2, pp. 280–293, December 1994.
[7] D. C. Schmidt, “Applying Design Patterns and Frameworks to Develop Object-Oriented Communication Software,” in Handbook of Programming Languages (P. Salus, ed.), MacMillan Computer Publishing, 1997.
[8] D. C. Schmidt, “A Family of Design Patterns for Application-level Gateways,” The Theory and Practice of Object Systems (Special Issue on Patterns and Pattern Languages), vol. 2, no. 1, 1996.
[9] T. H. Harrison, D. L. Levine, and D. C. Schmidt, “The Design and Performance of a Real-time CORBA Event Service,” in Proceedings of OOPSLA ’97, (Atlanta, GA), ACM, October 1997.
[10] D. C. Schmidt and C. Cleeland, “Applying Patterns to Develop Extensible and Maintainable ORB Middleware,” Communications of the ACM, to appear, 1998.
[11] M. K. McKusick, K. Bostic, M. J. Karels, and J. S. Quarterman, The Design and Implementation of the 4.4BSD Operating System. Addison Wesley, 1996.
[12] “Information Technology – Portable Operating System Interface (POSIX) – Part 1: System Application: Program Interface (API) [C Language],” 1995.
[13] W. R. Stevens, UNIX Network Programming, Second Edition. Englewood Cliffs, NJ: Prentice Hall, 1997.
[14] D. C. Schmidt, “Reactor: An Object Behavioral Pattern for Concurrent Event Demultiplexing and Event Handler Dispatching,” in Pattern Languages of Program Design (J.O.Coplien and D. C. Schmidt, eds.), pp. 529–545, Reading, MA: Addison-Wesley, 1995.
[15] R. G. Lavender and D. C. Schmidt, “Active Object: an Object Behavioral Pattern for Concurrent Programming,” in Pattern Languages of Program Design (J. O. Coplien, J. Vlissides, and N. Kerth, eds.), Reading, MA: Addison-Wesley, 1996.
[16] D. C. Schmidt, “Experience Using Design Patterns to Develop Reuseable Object-Oriented Communication Software,” Communications of the ACM (Special Issue on Object-Oriented Experiences), vol. 38, October 1995.
[17] A. Stepanov and M. Lee, “The Standard Template Library,” Tech. Rep. HPL-94-34, Hewlett-Packard Laboratories, April 1994.
[18] D. C. Schmidt, “ACE: an Object-Oriented Framework for Developing Distributed Applications,” in Proceedings of the 6th USENIX C++ Technical Conference, (Cambridge, Massachusetts), USENIX Association, April 1994.
[19] D. C. Schmidt, “Acceptor and Connector: Design Patterns for Initializing Communication Services,” in Pattern Languages of Program Design (R. Martin, F. Buschmann, and D. Riehle, eds.), Reading, MA: Addison-Wesley, 1997.
[20] P. Jain and D. C. Schmidt, “Service Configurator: A Pattern for Dynamic Configuration of Services,” in Proceedings of the 3rd Conference on Object-Oriented Technologies and Systems, USENIX, June 1997.
[21] T. Harrison, I. Pyarali, D. C. Schmidt, and T. Jordan, “Proactor – An Object Behavioral Pattern for Dispatching Asynchronous Event Handlers,” in The 4th Pattern Languages of Programming Conference (Washington University technical report #WUCS-97-34), September 1997.
[22] I. Pyarali, T. H. Harrison, and D. C. Schmidt, “Asynchronous Completion Token: an Object Behavioral Pattern for Efficient Asynchronous Event Handling,” in Pattern Languages of Program Design (R. Martin, F. Buschmann, and D. Riehle, eds.), Reading, MA: Addison-Wesley, 1997.
[23] F. Buschmann, R. Meunier, H. Rohnert, P. Sommerlad, and M. Stal, Pattern-Oriented Software Architecture - A System of Patterns. Wiley and Sons, 1996.
[24] D. C. Schmidt, “GPERF: A Perfect Hash Function Generator,” in Proceedings of the 2nd C++ Conference, (San Francisco, California), pp. 87–102, USENIX, April 1990.
[25] P. Jain and D. C. Schmidt, “Service Configurator: A Pattern for Dynamic Configuration and Reconfiguration of Communication Services,” in The 3rd Pattern Languages of Programming Conference (Washington University technical report #WUCS-97-07), February 1997.
[26] T. Berners-Lee, R. T. Fielding, and H. Frystyk, “Hypertext Transfer Protocol – HTTP/1.0,” Informational RFC
1945, Network Working Group, May 1996. Available from http://www.w3.org/.
[27] R. Fielding, J. Gettys, J. Mogul, H. Frystyk, and T. Berners-Lee, “Hypertext Transfer Protocol – HTTP/1.1,” Standards Track RFC 2068, Network Working Group, January 1997. Available from http://www.w3.org/.
[28] D. C. Schmidt and C. D. Cranor, “Half-Sync/Half-Async: an Architectural Pattern for Efficient and Well-structured Concurrent I/O,” in Pattern Languages of Program Design (J. O. Coplien, J. Vlissides, and N. Kerth, eds.), Reading, MA: Addison-Wesley, 1996.
[29] J. C. Mogul, “Hinted caching in the Web,” in Proceedings of the Seventh SIGOPS European Workshop: Systems Support for Worldwide Applications, 1996.
[30] S. Williams, M. Abrams, C. R. Standridge, G. Abdulla, and E. A. Fox, “Removal Policies in Network Caches for World Wide Web Documents,” in Proceedings of SIGCOMM ’96, (Stanford, CA), pp. 293–305, ACM, August 1996.
[31] E. P. Markatos, “Main memory caching of web documents,” in Proceedings of the Fifth International World Wide Web Conference, May 1996.
[32] Gene Trent and Mark Sake, “WebSTONE: The First Generation in HTTP Server Benchmarking.” Silicon Graphics, Inc. whitepaper, February 1995. Available from http://www.sgi.com/.
[33] A. Carlton, “An Explanation of the SPECweb96 Benchmark.” Standard Performance Evaluation Corporation whitepaper, 1996. Available from http://www.specbench.org/.
[34] H. F. Nielsen, J. Gettys, A. Baird-Smith, E. Prud’hommeaux, H. W. Lie, and C. Lilley, “Network Performance Effects of HTTP/1.1, CSS1, and PNG,” in To appear in Proceedings of ACM SIGCOMM ’97, 1997.
[35] M. S. Johns, “Identification Protocol,” Network Information Center RFC 1413, Feb. 1993.
 
55/5<12345
 

评分:0

我来说两句

seccode

最新更新