﻿<?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>IT博客-forrest-文章分类-JAVA</title><link>http://www.cnitblog.com/forrest/category/6386.html</link><description>对过去我已无法选择，但令我稍感安慰的是我还拥有现在，所以。。。。。
更弥足珍贵</description><language>zh-cn</language><lastBuildDate>Mon, 26 Sep 2011 09:32:04 GMT</lastBuildDate><pubDate>Mon, 26 Sep 2011 09:32:04 GMT</pubDate><ttl>60</ttl><item><title>http 协议的学习</title><link>http://www.cnitblog.com/forrest/articles/49181.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Wed, 17 Sep 2008 15:49:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/49181.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/49181.html</wfw:comment><comments>http://www.cnitblog.com/forrest/articles/49181.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/49181.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/49181.html</trackback:ping><description><![CDATA[概念：<br><font class="f14" id="zoom">&nbsp;&nbsp;&nbsp; 1.连接(Connection)：一个传输层的实际环流，它是建立在两个相互通讯的应用程序之间。<br><br>　　2.消息(Message)：HTTP通讯的基本单位，包括一个结构化的八元组序列并通过连接传输。<br><br>　　3.请求(Request)：一个从客户端到服务器的请求信息包括应用于资源的方法、资源的标识符和协议的版本号<br><br>　　4.响应(Response)：一个从服务器返回的信息包括HTTP协议的版本号、请求的状态(例如&#8220;成功&#8221;或&#8220;没找到&#8221;)和文档的MIME类型。<br><br>　　5.资源(Resource)：由URI标识的网络数据对象或服务。<br><br>　　6.实体(Entity)：数据资源或来自服务资源的回映的一种特殊表示方法，它可能被包围在一个请求或响应信息中。一个实体包括实体头信息和实体的本身内容。<br><br>　　7.客户机(Client)：一个为发送请求目的而建立连接的应用程序。<br><br>　　8.用户代理(Useragent)：初始化一个请求的客户机。它们是浏览器、编辑器或其它用户工具。<br><br>　　9.服务器(Server)：一个接受连接并对请求返回信息的应用程序。<br><br>　　10.源服务器(Originserver)：是一个给定资源可以在其上驻留或被创建的服务器。<br><br>　　11.代理(Proxy)：一个中间程序，它可以充当一个服务器，也可以充当一个客户机，为其它客户机建立请求。请求是通过可能的翻译在内部或经过传递到其它的服务器中。一个代理在发送请求信息之前，必须解释并且如果可能重写它。　代理经常作为通过防火墙的客户机端的门户，代理还可以作为一个帮助应用来通过协议处理没有被用户代理完成的请求。<br><br>　　12.网关(Gateway)：一个作为其它服务器中间媒介的服务器。与代理不同的是，网关接受请求就好象对被请求的资源来说它就是源服务器；发出请求的客户机并没有意识到它在同网关打交道。<br>　　网关经常作为通过防火墙的服务器端的门户，网关还可以作为一个协议翻译器以便存取那些存储在非HTTP系统中的资源。<br><br>
13.通道(Tunnel)：是作为两个连接中继的中介程序。一旦激活，通道便被认为不属于HTTP通讯，尽管通道可能是被一个HTTP请求初始化的。
当被中继的连接两端关闭时，通道便消失。当一个门户(Portal)必须存在或中介(Intermediary)不能解释中继的通讯时通道被经常使用。<br>　　14.缓存(Cache)：反应信息的局域存储。<br><br></font>历史上，先后问世了多个具有重大社会影响的电子通信技术。第一个这样的技术是19世纪70年代发明的电话。电话使得不在同一物理位置的两人得以实时地口头
交流。它对社会有重大的影响——有好的也有坏的。下一个电子通信技术是20世纪20年代及30年代问世的广播收音机/电视机。广播收音机/电视机使得人们
能收听收视大量的音频和视频信息。它对社会同样有重大的影响——有好的也有坏的。改变了人们的生活与工作方式的第三个重大通信技术是web。web最吸引
用户的也许是它的随选(on
demand)操作性。用户只在想要时收到所要的东西。这一点不同于广播收音机/电视机。广播收音机/电视机的用户是在其内容供应商播出内容期间被迫收听
收视。除了随选操作性，Web还有许多大家喜爱的其他精彩特性。任何个人都可以极其容易地在Web上公布任何信息;任何人都可能以极低的成本成为发行人。
超链接和搜索引擎帮助我们在Web站点的海洋中导航。图形和动画刺激着我们的感官。表单、Java小应用程序、Activex控件以及其他许多设备使得我
们能与Web页面和站点交互。Web还越来越普遍地提供存放在因特网中的、可随选访问(即点播)的大量音频和视频材料的菜单接口。
<p>　　<font color="#a00000">HTTP概貌</font></p>
<p>　　Web的应用层协议HTTP是Web的核心。HTTP在Web的客户程序和服务器程序中得以实现。运行在不同端系统上的客户程序和服务器程序通
过交换HTTP消息彼此交流。HTTP定义这些消息的结构以及客户和服务器如何交换这些消息。在详细解释HTTP之前，我们先来回顾一些web中的术语。</p>
<p>　　Web页面(web
page，也称为文档)由多个对象构成。对象(object)仅仅是可由单个URL寻址的文件，例如HTML文件、JPG图像、GIF图像、JAVA小应
用程序、语音片段等。大多数Web页面由单个基本HIML文件和若干个所引用的对象构成。例如，如果一个Web页面包含HTML文本和5个JPEG图像，
那么它由6个对象构成，即基本H1ML文件加5个图像。基本HTML文件使用相应的URL来引用本页面的其他对象。每个URL由存放该对象的服务器主机名
和该对象的路径名两部分构成。例如，在如下的URL中:</p>
<p>　　www.yesky.com/urlpath/picture.qif</p>
<p>　　www.yesky.com是一个主机名，/urlpath/picture.qif是一个路径名。浏览器是web的用户代理，它显示所请求的
Web页面，并提供大量的导航与配置特性。Web浏览器还实现HTTP的客户端，因此在web上下文中，我们会从进程意义上互换使用&#8220;浏览器&#8221;和&#8220;客户&#8221;
两词。流行的Web浏览器有Netscape
Communicator，firefox和微软的IE等。Web服务器存放可由URL寻址的Web对象。web服务器还实现HTTP的服务器端。流行的
Web服务器有Apache、微软的IIS以及Netscape Enterprise
Server。Netcraft提供了web服务器的概要剖析[Netcrft 2000]。</p>
<p>　　HTTP定义Web客户(即浏览器)如何从web服务器请求Web页面，以及服务器如何把Web页面传送给客户。下图展示了这种请求—响应行
为。当用户请求一个Web页面(譬如说点击某个超链接)时，浏览器把请求该页面中各个对象的HTTP请求消息发送给服务器。服务器收到请求后，以运送含有
这些对象HTTP响应消息作为响应。到1997年底，基本上所有的浏览器和Web服务器软件都实现了在RFC
1945中定义的HTTP/1.0版本。1998年初，一些Web服务器软件和浏览器软件开始实现在RFC
2616中定义的HTTP/1.1版本。H1TP/1.1与HTTP/1.0后向兼容;运行1.1版本的web服务器可以与运行1.0版本的浏览器&#8220;对
话&#8221;，运行1.1版本的浏览器也可以与运行1.0版本的Web服务器&#8220;对话&#8221;。</p>
<p align="center"><img src="http://server.chinabyte.com/imagelist/05/10/2bow0n1ay93c.gif" alt="" border="0"><br><font face="Verdana">图1 HTTP请求与响应行为</font></p>
<p>　　HTTP/1.0和HTTP/1.1都把TCP作为底层的传输协议。HTTP客户首先发起建立与服务器TCP连接。一旦建立连接，浏览器进程和
服务器进程就可以通过各自的套接字来访问TCP。如前所述，客户端套接字是客户进程和TCP连接之间的&#8220;门&#8221;，服务器端套接字是服务器进程和同一TCP连
接之间的&#8220;门&#8221;。客户往自己的套接字发送HTTP请求消息，也从自己的套接字接收HTTP响应消息。类似地，服务器从自己的套接字接收HTTP请求消息，
也往自己的套接字发送HTTP响应消息。客户或服务器一旦把某个消息送入各自的套接字，这个消息就完全落入TCP的控制之中。TCP给HTTP提供一个可
靠的数据传输服务;这意味着由客户发出的每个HTTP请求消息最终将无损地到达服务器，由服务器发出的每个HTTP响应消息最终也将无损地到达客户。我们
可从中看到分层网络体系结构的一个明显优势——HTTP不必担心数据会丢失，也无需关心TCP如何从数据的丢失和错序中恢复出来的细节。这些是TCP和协
议栈中更低协议层的任务。</p>
<p>　　TCP还使用一个拥塞控制机制。该机制迫使每个新的TCP连接一开始以相对缓慢的速率传输数据，然而只要网络不拥塞，每个连接可以迅速上升到相对较高的速率。这个慢速传输的初始阶段称为缓启动(slow start)。</p>
<p>　　需要注意的是，在向客户发送所请求文件的同时，服务器并没有存储关于该客户的任何状态信息。即便某个客户在几秒钟内再次请求同一个对象，服务器
也不会响应说:自己刚刚给它发送了这个对象。相反，服务器重新发送这个对象，因为它已经彻底忘记早先做过什么。既然HTTP服务器不维护客户的状态信息，
我们于是说HTTP是一个无状态的协议(stateless protocol)。</p>
&nbsp;<font color="#a00000">非持久连接和持久连接</font>
<p>　　HTTP既可以使用非持久连接(nonpersistent connection)，也可以使用持久连接(persistent connection)。HTTP/1.0使用非持久连接，HTTP/1.1默认使用持久连接。</p>
<p>　　<strong>非持久连接</strong></p>
<p>　　让我们查看一下非持久连接情况下从服务器到客户传送一个Web页面的步骤。假设该贝面由1个基本HTML文件和10个JPEG图像构成，而且所
有这些对象都存放在同一台服务器主机中。 再假设该基本HTML文件的URL为:www.yesky.com/somepath/index.html。</p>
<p>　　下面是具体步骡:</p>
<p>　　1.HTTP客户初始化一个与服务器主机www.yesky.com中的HTTP服务器的TCP连接。HTTP服务器使用默认端口号80监听来自HTTP客户的连接建立请求。</p>
<p>　　2.HTTP客户经由与TCP连接相关联的本地套接字发出—个HTTP请求消息。这个消息中包含路径名/somepath/index.html。</p>
<p>　　3.HTTP服务器经由与TCP连接相关联的本地套接字接收这个请求消息，再从服务器主机的内存或硬盘中取出对象/somepath/index.html，经由同一个套接字发出包含该对象的响应消息。</p>
<p>　　4.HTTP服务器告知TCP关闭这个TCP连接(不过TCP要到客户收到刚才这个响应消息之后才会真正终止这个连接)。</p>
<p>　　5.HTTP客户经由同一个套接字接收这个响应消息。TCP连接随后终止。该消息标明所封装的对象是一个HTML文件。客户从中取出这个文件，加以分析后发现其中有10个JPEG对象的引用。</p>
<p>　　6.给每一个引用到的JPEG对象重复步骡1-4。</p>
<p>　　浏览器在接收web页面的同时把它显示给用户。不同的浏览器可能会以略有不同的方式解释(也就是向用户显示)同一个web页面。HTTP与客户
如何解释Web页面没有任何关系，其规范([RFC 1945]和[RFC 2616I)仅仅定义HTTP客户程序和服务器程序之间的通信协议。</p>
<p>　　上述步骤之所以称为使用非持久连接，原因是每次服务器发出一个对象后，相应的TCP连接就被关闭，也就是说每个连接都没有持续到可用于传送其他
对象。每个TCP连接只用于传输一个请求消息和一个响应消息。就上述例子而言，用户每请求一次那个web页面，就产生11个TCP连接。</p>
<p>　　在上述步骡中，我们有意不说清客户是通过10个串行的TCP连接先后取得所有JPEG对象，还是通过并行的TCP连接同时取得其中某些JPEG
对象。实际上，现今的浏览器允许用户通过配置来控制并行连接的程度。大多数浏览器默认可以打开5到10个并行的TCP连接，每个连接处理一个请求—响应事
务。用户要是喜欢，可以把最大并行连接数设为l，那样的话这10个连接是串行地建立的。我们将在第3章看到，使用并行连接可以缩短响应时间。</p>
<p>　　继续介绍之前，先估算一下从客户请求基本HTML文件到它收到该文件所经历的时间。为此我们定义往返时间(round trip
time，简称RTT)，它是一个小分组从客户主机游动到服务器主机再返回客户主机所花的时间。RTT包括分组传播延迟、在中间路由器和交换机土的分组排
队延迟以及分组处理延迟。下面考虑用户点击某个超链接时会发生什么。用户的点击导致浏览器发起建立一个与Web服务器的TCP连接;这里涉及&#183;—次&#8220;三次
握手&#8221;过程——首先是客户向服务器发送一个小的冗余消息，接着是服务器向客户确认并响应以一个小的TCP消息，最后是客户向服务器回确认。三次握手过程的
前两次结束时，流逝的时间为1个RTT。此时客户把HTTP请求消息发送到TCP连接中，客户接着把三次握手过程最后一次中的确认捎带在包含这个消息的数
据分节中发送以去。服务器收到来自TCP连接的请求消息后，把相应的HTML文件发送到TCP连接中，服务器接着把对早先收到的客户请求的确认捎带在包含
该HTML文件的数据分节中发送出去。这个HTTP请求顺应交互也花去1个RTT时间。因此，总的响应时间粗略地算是2个RTT加上服务器发送这个
HTMI文件的时间。</p>
<p>　　<strong>持久连接</strong></p>
<p>　　非持久连接有些缺点。首先，客户得为每个待请求的对象建立并维护一个新的连接。对于每个这样的连接，TCP得在客户端和服务器端分配TCP缓冲
区，并维持TCP变量。对于有可能同时为来自数百个不同客户的请求提供服务的web服务器来说，这会严重增加其负担。其次，如前所述，每个对象都有2个
RTT的响应延长——一个RTT用于建立TCP连接，另—个RTT用于请求和接收对象。最后，每个对象都遭受TCP缓启动，因为每个TCP连接都起始于缓
启动阶段。不过并行TCP连接的使用能够部分减轻RTT延迟和缓启动延迟的影响。</p>
<p>　　在持久连接情况下，服务器在发出响应后让TCP连接继续打开着。同一对客户/服务器之间的后续请求和响应可以通过这个连接发送。整个Web页面
(上例中为包含一个基本HTMLL文件和10个图像的页面)自不用说可以通过单个持久TCP连接发送:甚至存放在同一个服务器中的多个web页面也可以通
过单个持久TCP连接发送。通常，HTTP服务器在某个连接闲置一段特定时间后关闭它，而这段时间通常是可以配置的。持久连接分为不带流水线
(without pipelining)和带流水线(with
pipelining)两个版本。如果是不带流水线的版本，那么客户只在收到前一个请求的响应后才发出新的请求。这种情况下，web页面所引用的每个对象
(上例中的10个图像)都经历1个RTT的延迟，用于请求和接收该对象。与非持久连接2个RTT的延迟相比，不带流水线的持久连接已有所改善，不过带流水
线的持久连接还能进一步降低响应延迟。不带流水线版本的另一个缺点是，服务器送出一个对象后开始等待下一个请求，而这个新请求却不能马上到达。这段时间服
务器资源便闲置了。</p>
<p>　　HTTP/1.1的默认模式使用带流水线的持久连接。这种情况下，HTTP客户每碰到一个引用就立即发出一个请求，因而HTTP客户可以一个接
一个紧挨着发出各个引用对象的请求。服务器收到这些请求后，也可以一个接一个紧挨着发出各个对象。如果所有的请求和响应都是紧挨着发送的，那么所有引用到
的对象一共只经历1个RTT的延迟(而不是像不带流水线的版本那样，每个引用到的对象都各有1个RTT的延迟)。另外，带流水线的持久连接中服务器空等请
求的时间比较少。与非持久连接相比，持久连接(不论是否带流水线)除降低了1个RTT的响应延迟外，缓启动延迟也比较小。其原因在于既然各个对象使用同一
个TCP连接，服务器发出第一个对象后就不必再以一开始的缓慢速率发送后续对象。相反，服务器可以按照第一个对象发送完毕时的速率开始发送下一个对象。</p>
<p><font color="#a00000">HTTP消息格式</font></p>
<p>　　HTTP规范1.0[RPcl945]和1.1[RFC 2616]定义了HTTP消息的格式。HTTP消息分为请求消息和响应稍息两类。下面我们分别进行介绍。</p>
<p>　　<strong>HTTP请求消息</strong></p>
<p>　　下面是一个典型的HTTP请求消息:</p>
<p>
</p>
<table style="table-layout: fixed;" align="center" border="0" cellpadding="6" cellspacing="0" width="95%">
    <tbody>
        <tr>
            <td bgcolor="#f3f3f3">
            <p>　　GET&nbsp;/somedir/page.html&nbsp;H7TP/1.1 <br>　　Host:www.yesky.com <br>　　Connection:close <br>　　User-agent:Mozilla/4.0 <br>　　Accept-language:zh-cn <br>　　(额外的回车符和换行符)</p>
            </td>
        </tr>
    </tbody>
</table>
<p>　　仔细检查这个简单的请求消息，我们可从中学到不少东西。首先，这个消息是用普通的ASCII文本书写的。其次，这个消息共有5行(每行以一个回
车符和一个换行符结束)，最后一行后面还有额外的一个回车特和换行符。当然，一个请求消息可以不止这么多行，也可以仅仅只有一行。该请求消息的第一行称为
请求行(request
line)，后续各行都称为头部行(header)。请求行有3个宁段:方法字段、URL字段、HTTP版本宇段。方法字段有若干个值可供选择，包括
GET、POST和HEAD。HTTP请求消息绝大多数使用GET方法，这是浏览器用来请求对象的方法，所请求的对象就在URL字段中标识。本例表明浏览
器在请求对象/somedir/page.html。版本字段是不言自明的;本例中浏览器实现的是HTTP/1.1版本。</p>
<p>　　现在看一下本例中的各个头部行。头部行Host:www.yesky.com定存放所请求对象的主机。请求消息中包含头部
Connection:close是在告知服务器本浏览器不想使用持久连接;服务器发出所请求的对象后应关闭连接。尽管产生这个请求消息的浏览器实现的是
HTTP/1.1版本，它还是不想使用持久连接。User-agent头部行指定用户代理，也就是产生当前请求的浏览器的类型。本例的用户代理是
Mozilla/4.0，它是Nelscape浏览器的一个版本。这个头部行很有用，因为服务器实际上可以给不同类型的用户代理发送同一个对象的不同版本
(这些不同版本位用同一个URL寻址)。最后，Accept-languag:头部行指出要是所请求对象有简体中文版本，那么用户宁愿接收这个版本;如果
没有这个语言版本，那么服务器应该发送其默认版本。Accept-languag:仅仅是HTTP的众多内容协商头部之一。</p>
<p>　　我们接着看一下下图所示的请求消息的一般格式。</p>
<p align="center"><img src="http://server.chinabyte.com/imagelist/05/10/lw24nu9mh14x.jpg" alt="" border="0"><br>图2:HTTP请求格式</p>
<p>　　上面的请求消息例子符合这个格式，不过一般格式中还有一个位于各个头部(及额外的回车符和换行符)之后的&#8220;附属体&#8221;(毗叮body)。附属体不
在GET方法中使用，而是在POST方法中使用。POST方法适用于需由用户填写表单的场合，如往google搜索引擎中填入待搜索的词。用户提交表单
后，浏览器就像用户点击了超链接那样仍然从服务器请求一个Web页面，不过该页面的具体内容却取决于用户填写在表单各个字段中的值。如果浏览器使用
POST方法提出该请求，那么请求消息附属体中包含的是用户填写在表单各个字段中的值。与GET方法类似的是HEAD方法，两者的差别只是服务器在对
HEAD方法的响应消息中去掉了所请求的对象，其他内容则与对GET方法的响应消息一样。HEAD方法通常用于HTTP服务器软件开发人员进行调试。</p>
<p>　　<strong>HTTP响应消息</strong></p>
<p>　　下面是一个典型的HTTP响应消息: </p>
<p>
</p>
<table style="table-layout: fixed;" align="center" border="0" cellpadding="6" cellspacing="0" width="95%">
    <tbody>
        <tr>
            <td bgcolor="#f3f3f3">
            <p>　　<br>　　HTTP/1.1&nbsp;200&nbsp;0K <br>　　Connectlon:close <br>　　Date:&nbsp;Thu,&nbsp;13&nbsp;Oct&nbsp;2005&nbsp;03:17:33&nbsp;GMT <br>　　Server:&nbsp;Apache/2.0.54&nbsp;(Unix) <br>　　Last—Nodified:Mon,22&nbsp;Jun&nbsp;1998&nbsp;09;23;24&nbsp;GMT <br>　　Content—Length:682l <br>　　Content—Type:text/html </p>
            <p>　　(数据&nbsp;数据&nbsp;数据&nbsp;数据&nbsp;数据&#8230;&#8230;&#8230;&#8230;)</p>
            </td>
        </tr>
    </tbody>
</table>
<p><font face="Verdana">　　这个响应消息分为3部分：1个起始的状态行(status line)，</font>6个头部行、1个包含所请求对象本身的附属体。状态行有3个字段:协议版本字段、状态码字段、原因短语字段。本例的状态行表明，服务器使用HTTP/1.1版本，响应过程完全正常(也就是说服务器找到了所请求的对象，并正在发送)。</p>
<p>　　现在看一下本例中的各个头部行。服务器使用Connectlon:close头部行告知客户自己将在发送完本消息后关闭TCP连接。Date:
头部行指出服务器创建并发送本响应消息的日期和时间。注意，这并不是对象本身的创建时间或最后修改时间，而是服务器把该对象从其文件系统中取出，插入响应
消息中发送出去的时间。Server:头部行指出本消息是由Apache服务器产生的;它与HTTP请求消息中的User-agent:头部行类似。
Last—Nodified:头部行指出对象本身的创建或最后修改日期或时间。Last—Nodified:头部对于对象的高速缓存至关重要，且不论这种
高速缓存是发生在本地客户主机上还是发生在网络高速缓存服务器主机(也就是代理服务器主机)上。Content—Length:头部行指出所发送对象的字
节数。Content—Type:头部行指出包含在附属体中的对象是HTML文本。对象的类型是由Content—Type:头部而不是由文件扩展名正式
指出的。</p>
<p>　　注意，如果服务器收到一个HTTP/1.0的请求，那么它即使是一个HTTP/1.1服务器，也不会使用持久连接。相反，这样的HTTP/1.1服务器会在发出所请求的对象后关闭TCP连接。这么做是必要的，因为HTTP/1.0客户期待服务器马上关闭连接。</p>
<p>　　我们接着看一下如下图所示的响应消息的一般格式。前面的响应消息例子完全符合这个格式。响应消息中的状态码和原因短语指示相应请求的处理结果，下面列出了一些常见的状态码和相应的原因短语:</p>
<p align="center"><img src="http://server.chinabyte.com/imagelist/05/10/0ovd0f8p6ri9.jpg" alt="" border="0"></p>
<p align="center"><font face="Verdana">图3:响应消息的一般格式</font><br></p>
<p>　　●200 0K;请求成功，所请求信息在响应消息中返回。</p>
<p>　　●301 Moved Permanently:所请求的对象己永久性迁移;新的URL在本响应消息的Location:头部指出。客户软件会自动请求这个新的URL。</p>
<p>　　●400 Bad Request;表示服务器无法理解相应请求的普通错误的状态码</p>
<p>　　●404 Not Found:服务器上不存在所请求的文档。</p>
<p>　　●HTTP Version Not Support:服务器不支持所请求的HTTP协议版本。</p>
<p>　　你想如何看到一个真实的H1TP应答消息呢?这非常简单。可以使用nc工具连接到你喜欢的服务器(nc/netcat是一个黑客很喜欢用的工
具，可以方便在主机之间建立TCP连接)，然后输入一行请求消息，用来请求位于该服务器上的某个对象。例如，如果你可以输入以下指令:</p>
<p>
</p>
<table style="table-layout: fixed;" align="center" border="0" cellpadding="6" cellspacing="0" width="95%">
    <tbody>
        <tr>
            <td bgcolor="#f3f3f3">　　nc&nbsp;www.yesky.com&nbsp;80 <br>　　GET&nbsp;/index.shtml&nbsp; HTTP/1.0</td>
        </tr>
    </tbody>
</table>
<p>　　(在输入第二行之后，敲两次回车)，这就打开了一个到主机www.yesky.com的端口80的TCP连接，然后发送HTTP
GET命令。你应该能看到包含着YESKY主页的基本HTML文件的应苔消息。如果你想只看到HTTP消息行而不接收该对象本身，那么就把上面的GET换
成HEAD。最后，看一下能得到什么样的应答消息。</p>
<p>　　在这里我们讨论了大量能够在HTTP请求和应答消息中使用的头部行。HTTP规范(尤其是HTTP/1.1)定义了更多可以由浏览器、Web服务器和网络缓冲服务器插入的头部行。</p>
<p>　　我们可以便用nc工具完全控制在请求消息中包含哪些头部，那么浏览器如何决定该在请求消息个包含哪些头部呢?Web服务器又是如何决定该在响应
消息中包含哪些头部?浏览器是根据自己的用户代理类型、所支持的HTTP版本(HTTP/1.0版本的浏览器自然不会产生HTTP/1.1版本的头部)、
用户对浏览器的配置(如所偏爱的语言)等因素生成请求消息中的各个头部的。web服务器有类似的情形:它们有不同的产品、版本和配置，所有这些因素都会影
响在响应消息中包含哪些头部。</p>
<p>　　本文讨论过的和即将讨论的用于HTTP请求消息和响应消息中的头部仅仅是很小的一部分，HTTP规范中定义了更多可用的头部，可以查阅相关的RFC文档进行更详细的了解。</p>
<p><font color="#a00000">用户—</font><font color="#993300">服务器</font><font color="#a00000">交互</font></p>
<p>　　<strong>身份认证和cookie</strong></p>
<p>　　我们已经知道HTTP服务器是无状态的。这样的处理可以简化服务器程序的设计，以便开发出更高性能的Web服务器软件。然而，一个Web站点往
往有标识其用户的需求，因为其web服务器可能希望限制用户的访问，也可能想要根据用户的身份来提供内容。HTTP提供了两种帮助服务器标识用户的机制:
身份认证和cookle。</p>
<p>　　身份认证许多web站点要求用户提供一个用户名—口令对才能访问存放在其服务器中的文档。这种要求称为身份认证
(authentication)。HTTP提供特殊的状态码和头部来帮助Web站点执行身份认证。我们通过查看一个例子来领会这些特殊的状态码和头部如
何工作。假设有—个客户在请求来自某个服务器的一个对象，而该服务器要求用户授予权限。</p>
<p>　　客户首先发送一个不合特殊头部的普通请求消息。服务器以空的附属体和一个&#8220;401Authorization
Required&#8221;状态码作为响应。服务器还在这个响应消息中包含&#8220;个WWW-Authenticate:头部，说明具体如何执行身份认证。这个头部的典
型值是指出用户需要提供一个用户名—口令对。</p>
<p>　　客户收到这个响应消息后提示用户输入用户名和口令，然后重新发送请求消息。这一回客户在请求消息中包含了一个Authorization:头部，其中包含有用户输入的用户名和口令。</p>
<p>　　取得第一个对象后，客户在同为请求该服务器上对象的后续请求中继续发送这个用户名—口令对。这个做法一般将持续到用户关闭浏览器为止。在浏览器
未被关闭之前，这个用户名—口令对是高速缓存着的，因此浏览器不会每请求一个对象就提示用户输入一次用户名和口令。通过上述方式，要求用户授权的Web站
点就能标识出每个请求的用户了。</p>
<p>　　我们需要知道，HTTP执行的是一种相当脆弱的身份认证方式，不难攻破。现代有很多更为安全的认证方式，我们会在以后介绍。</p>
<p>　　cookie是一种可让Web站点用来跟踪用户的候选机制，定义在RFC
2109中。有些Web站点使用cookie，其他Web站点则不用。下面查看一个例子。假设一个客户首次联系一个使用cookie的web站点。服务器
会在其响应中包含一个Set—Cookie:头部。该头部的值可以是一个由Web服务器产生的客户标识数.例如:</p>
<p>　　Set-Cookie:1678453</p>
<p>　　客户收到这个响应消息，看到其中的Set-Cookie:头部和标识数后，会在存放在客户主机中的某个特殊的cookie文件中添加一行。这一
行一般包含服务器主机的主机名和这个与用户关联的标识数。在一段时间(如一个星期)之后请求同一个服务器时，由同一个用户启动的新客户会在请求消息中包含
一个cookie头部，其值为早先由该服务器产生的标识数，例如:Cookie:1678453</p>
<p>　　在这种方式中，服务器并不知道提出请求的用户的用户名，但是它确实知道该用户与一个星期前提出请求的用户是同一个。</p>
<p>　　Web服务器有多个使用coohe的目的:</p>
<p>　　●如果服务器要求身份认证，但又不想在同一用户每次访问本Web站点时都麻烦他输入用户名和口令，那么可以设置一个cookie。</p>
<p>　　●如果服务器想要记住用户的偏好，以便在他们后续访问期间有目的地提供广告，那么可以设置一个cookie。</p>
<p>　　●如果web站点提供购物服务，那么服务器可以使用cookie跟踪用户购买的物品，就是建立一个虚拟的购物车。</p>
<p>　　需指出的是，cookie不适用于会从不同主机访问同一web站点的游动用户。这种情况下，该web站点会把同一个用户在不同主机上的使用看成是由新的用户执行的。</p>
<p><font color="#a00000">带条件的GET</font></p>
<p>　　Web高速缓存技术通过就近存取先前取得的对象来降低对象检索延迟，减少因特网上的web流量。Web的高速缓存既可以驻留在客户主机中，也可以驻留在中间网络高速缓存服务器主机中。我们将在稍后讨论网络高速缓存，这里只关注客户的高速缓存。</p>
<p>　　Web高速缓存在降低用户可感知的响应时间的同时，却引入了一个新的问题——高速缓存中存放的对象的拷贝可能是过期的。换句话说，存放在web
服务器中的对象可能己在客户高速缓存下它的一个拷贝之后被修改了。幸运的是，HTTP提供一个专门的机制，使得在允许客户进行高速缓存的同时，仍确保传递
给浏览器的所有对象都是最新的。这个机制称为带条件的0ET(conditional
GET)。满足条件(1)使用GET方法和(2)包含If-Modified-S1nce:头部的HTTP请求消息就是所谓的带条件的Get消息。</p>
<p>　　我们通过查看一个例子来说明带条件的GET如何工作，向服务器请求一个尚未高速缓存的对象:</p>
<p>
</p>
<table style="table-layout: fixed;" align="center" border="0" cellpadding="6" cellspacing="0" width="95%">
    <tbody>
        <tr>
            <td bgcolor="#f3f3f3">　　GET&nbsp;/fruit/kiwi.gif&nbsp;HTTP/1.0 <br>　　User—agent:&nbsp;Mozilla/4.0</td>
        </tr>
    </tbody>
</table>
<p>　　接着，web服务器把带这个对象的一个响应消息发送给客户:</p>
<p>
</p>
<table style="table-layout: fixed;" align="center" border="0" cellpadding="6" cellspacing="0" width="95%">
    <tbody>
        <tr>
            <td bgcolor="#f3f3f3">
            <p>　　HTTP/1.0&nbsp;200&nbsp;OK <br>　　Date:&nbsp;Thu,&nbsp;13&nbsp;Oct&nbsp;2005&nbsp;05:33:47&nbsp;GMT <br>　　Server:&nbsp;Apache/2.0.54&nbsp;(Unix) <br>　　Last-Modified:Thu,&nbsp;13&nbsp;Oct&nbsp;2005&nbsp;02:32:47&nbsp;GMT <br>　　Content-Type:image/gif </p>
            <p>　　(数据&nbsp;数据&nbsp;数据&nbsp;数据&nbsp;数据&#8230;&#8230;)</p>
            </td>
        </tr>
    </tbody>
</table>
<p>　　客户把这个对象显示给用户，同时把它保存在自己的本地高速缓存中客户还随该对象本身高速缓存最后修改日期与时间。一个星期之后，同一个用户请求
同一个对象，而该对象仍然存放在高速缓存中。既然web服务器中的该对象有可能已在最近一个星期被修改过，于是浏览器发出一个带条件的GET消息，执行判
定高速缓存的对象拷贝是否为最新的检查;</p>
<p>
</p>
<table style="table-layout: fixed;" align="center" border="0" cellpadding="6" cellspacing="0" width="95%">
    <tbody>
        <tr>
            <td bgcolor="#f3f3f3">　　GET&nbsp;/fruit/kiwi.gif&nbsp;HTTP/1.0 <br>　　User—agent:&nbsp;Mozilla/4.0 <br>　　If—Modlfied—Since:Thu,&nbsp;13&nbsp;Oct&nbsp;2005&nbsp;02:32:47&nbsp;GMT</td>
        </tr>
    </tbody>
</table>
<p>　　其中，If—Modlfied—Since:头部的值就等于一个星期前由服务器发送的Last-Modified:头部的值。这个带条件的
GET消息告知服务器，只有在该对象自所指定的时间以来被修改了的前提下才发送它。假设该对象在这段时间内未曾被修改过，那么服务器将发送一个附属体为空
的响应消息给客户;</p>
<p>
</p>
<table style="table-layout: fixed;" align="center" border="0" cellpadding="6" cellspacing="0" width="95%">
    <tbody>
        <tr>
            <td bgcolor="#f3f3f3">　　HTTP/1.0&nbsp;304&nbsp;Not&nbsp;Modified <br>　　Date:&nbsp;Thu,&nbsp;20&nbsp;Oct&nbsp;2005&nbsp;05:33:47&nbsp;GMT <br>　　Server:&nbsp;Apache/2.0.54&nbsp;(Unix)</td>
        </tr>
    </tbody>
</table>
<p>　　我们看到，web服务器仍然发送——个响应消息作为带条件的GET消息的响应，不过其中不包含所请求的对象。包含该对象只会浪费带宽，并延长用
户可感知的响应时间，特别是在该对象很大的时候。注意，这个响应消息的状态为&#8220;304 Not
Modified&#8221;，它告知客户可以放心使用所请求对象的高速缓存版本。</p>
<p><font color="#a00000">web高通缓存</font>服务器</p>
<p>　　web高速缓存服务器(Web
cache)是具有高速缓存功能的web代理服务器，它们在代表客户执行HTTP请求的问时，在自己的硬盘空间中保存近来请求到的对象的一个拷贝。如下图
所示，用户首先把他们的浏览器配置成所有的HTTP请求都定向到web高速缓存服务器。。这样配置过的浏览器以后产生的每一个请求首先到达的将是Web高
速缓存服务器。下面就以浏览器请求对象<a href="http://www.chinabyte.com/"><font color="#005a98">http://www.chinabyte.com/</font></a>例，具体说明其过程。</p>
<p align="center"><img src="http://server.chinabyte.com/imagelist/05/10/50p020x97m70.jpg" alt="" border="0"><br><font face="Verdana">图4：Web缓存服务器工作原理</font></p>
<p>　　●浏览器建立一个到Web高速缓存服务器的TCP连接，然后通过该连接向这个web高速缓存服务器发出一个访问所指对象的HTTP请求。</p>
<p>　　●Web高速缓存服务器查看本地是否存有该对象的一个拷贝。如果有的话，它就把该对象包含在一个HTTP响应消息中发送给客户浏览器。</p>
<p>　　●如果web高速缓存服务器找不到该对象的本地拷贝，它就建立一个到目标服务器即　　www.chinabyte.com的TCP连接。然后通
过该连接发出一个访问所指对象的HTTP请求。目标服务器接收到这个请求后，把所请求的对象包含在一个HTTP响应消息中发送给Web高速缓存服务器。</p>
<p>　　●web高速缓存服务器接收到这个对象后，在本地存放一个它的拷贝，再通过与客户浏览器之间的已有连接，把它的另一个拷贝包含在一个HTTP响应消息中发送给客户浏览器。</p>
<p>　　注意，web高速缓存服务器同时扮演服务器和客户两个角色。就从浏览器接收请求和往浏览器发送响应而言，它是服务器。就往目标服务器发送请求和从目标服务器接收响应而言，它是客户。</p>
<p>　　为什么要增添Web高速缓存服务器?它有哪些优势呢?在因特网中广泛地部署Web高速缓存服务器至少有3个理由。首先，web高速缓存服务器可
以充分地缩短客户请求的响应时间，特别是在客户与目标服务器之间的瓶颈带宽比它与高速缓存服务器之间的瓶颈带宽小得多的时候。如果在客户和高速缓存服务器
之间存在一个高速连接(实际情况也通常是这样)，而且高速缓存服务器上存有所请求的对象，那么它将迅速地把该对象递送给客户。其次，web高速缓存服务器
可以充分地降低相应机构在因特网访问链路上的流量(后面会有相应的示例)。这样降低流量后，该机构(譬如说公司或大学)就不必过快地升级带宽，从而节省了
费用。另外，web高速缓存服务器可以显著降低因特网的总体Web流量，从而改善所有应用的性能。第三，在因特网的机构、地区、国家等层次上密布web高
速缓存服务器主机可提供一个用于迅速散布内容的基础设施，即使是在低速访问链路之后的低速服务器主机上运行其Web站点的内容供应商也大受稗益。如果这些
资源不足的内容供应商突然有受欢迎的内容待散布，那么这些内容将会在较短时间内拷贝到大量的高速缓存服务器中，从而满足用户的强烈需求。</p>
<p>　　<strong>协同高速缓存</strong></p>
<p>　　因特网上位于不同地方的多个web高速缓存服务器可以协同改善整体性能。例如，机构内部的高速缓存服务器可以配置成把它的HTTP请求发送给某
个国家级主干ISP的高速缓存服务器。这种配置下，当机构内部高速缓存服务器中没有存放浏览器请求的对象时，它将把相应的HTTP请求转发给国家级高速缓
存服务器。国家级高速缓存服务器接着从本地硬盘或从目标服务器取得该对象，发送给机构内那高速缓存服务器，再由它转而发送给提出请求的浏览器。当一个对象
穿越—个机构内部或国家级高速缓存服务器时，这个高速缓存服务器将在本地硬盘中保存该对象的一个拷贝。穿越更高层的高速缓存服务器(例如国家级高速缓存服
务器)的优势在于它们拥有更大的用户群体，从而有更高的命中率。</p>
<p>　　协同高速缓存系统的一个例子是NLANR，它由位于美国境内的多个主干高速缓存服务器构成，为遍布全球的机构内部高速缓存服务器和地区级高速缓
存服务器提供服务。各个高速缓存服务器组合使用HTTP和1CP(Internet Caching
Protocol网际高速缓存协议)彼此交换对象。ICP是一个应用层协议，允许一个高速缓存服务器迅速查问另一个高速缓存服务器是否存有某个给定文档
[RFC
2186]。查问完之后，它就可以便用HTTP协议取回该对象。ICP在许多协同高速缓存系统中得到广泛使用，Squid软件完全支持它(Squid是一
个用于Web高速缓存的公共域软件)。</p>
<p>　　协同高速缓存的另一种形式涉及高速缓存服务器的群集，这些服务器往往位于同一个局域网内。当单个高速缓存服务器没有足够的能力处理流通量或提供
足够的存储容量时，往往改用高速缓存服务器群集。尽管群集是随流通量增长而扩张规模的自然方式，它却引入了新的问题:当一个浏览器请求某个特定对象时，它
应该向群集中的哪一个高速缓存服务器发出请求呢?通过使用散列选路办法，这个问题可以完美地得到解决(相关资料可在网上查找)。在最简单的散列选路方式
中，浏览器对URL作散列操作，然后根据散列结果把请求消息定向到群集中的某个高速缓存服务器。通过让所有的浏览器使用相同的散列函数，一个对象就只会存
在于同一群集中的某个高速缓存服务器L，而且如果该对象确实存在于这个群集中，那么浏览器总是能够把访问该对象的请求定向到正确的高速缓存服务器。散列选
路是高速缓存阵列选路协议(Cache Array Routing Protocol，简称CAD)的核心。</p>
<p>　　web高速缓存是一个丰富而复杂的主题，近些年来己围绕它展开了广泛的研究和产品开发。另外，高速缓存服务器现今己设计成可用来处理流式音频和视频数据。随着因特网开始为在其上大规模按需散布音乐、电视节目和电影提供基础设施，高速缓存有可能扮演越来越重要的角色。</p>
<br>思考 ：<br>现在在学习协议，考虑用手头的语言实现一个协议<br>java实现http协议<br>或者用动态语言实现：<br>python和groovy不知<br>是否方便实现。<br>仅仅是个想法<br>找到实现的代码了，不过是别人的，学习一下先：<br>一、HTTP协议的作用原理
<p>　　WWW是以Internet作为传输媒介的一个应用系统，WWW网上最基本的传输单位是Web网页。WWW的工作基于客户机/服务器计算模型，
由Web
浏览器(客户机)和Web服务器(服务器)构成，两者之间采用超文本传送协议（HTTP）进行通信。HTTP协议是基于TCP/IP协议之上的协议，是
Web浏览器和Web服务器之间的应用层协议，是通用的、无状态的、面向对象的协议。HTTP协议的作用原理包括四个步骤：</p>
<p>　　(1) 连接：Web浏览器与Web服务器建立连接，打开一个称为socket（套接字）的虚拟文件，此文件的建立标志着连接建立成功。</p>
<p>　　(2) 请求：Web浏览器通过socket向Web服务器提交请求。HTTP的请求一般是GET或POST命令（POST用于FORM参数的传递）。GET命令的格式为：</p>
<p>　　GET 路径/文件名 HTTP/1.0</p>
<p>　　文件名指出所访问的文件，HTTP/1.0指出Web浏览器使用的HTTP版本。</p>
<p>　　(3) 应答：Web浏览器提交请求后，通过HTTP协议传送给Web服务器。Web服务器接到后，进行事务处理，处理结果又通过HTTP传回给Web浏览器，从而在Web浏览器上显示出所请求的页面。<br>&nbsp;<br>　　例：假设客户机与<a href="http://www.mycompany.com:8080/mydir/index.html">www.mycompany.com:8080/mydir/index.html</a>建立了连接，就会发送GET命令：GET /mydir/index.html HTTP/1.0。主机名为<a href="http://www.mycompany.com/">www.mycompany.com</a>的Web服务器从它的文档空间中搜索子目录mydir的文件index.html。如果找到该文件，Web服务器把该文件内容传送给相应的Web浏览器。</p>
<p>　　为了告知 Web浏览器传送内容的类型，Web服务器首先传送一些HTTP头信息，然后传送具体内容（即HTTP体信息），HTTP头信息和HTTP体信息之间用一个空行分开。<br>常用的HTTP头信息有：</p>
<p>　　① HTTP 1.0 200 OK</p>
<p>　　这是Web服务器应答的第一行，列出服务器正在运行的HTTP版本号和应答代码。代码&#8220;200 OK&#8221;表示请求完成。</p>
<p>　　② MIME_Version:1.0</p>
<p>　　它指示MIME类型的版本。</p>
<p>　　③ content_type:类型</p>
<p>　　这个头信息非常重要，它指示HTTP体信息的MIME类型。如：content_type:text/html指示传送的数据是HTML文档。</p>
<p>　　④ content_length:长度值</p>
<p>　　它指示HTTP体信息的长度（字节）。</p>
<p>　　(4) 关闭连接：当应答结束后，Web浏览器与Web服务器必须断开，以保证其它Web浏览器能够与Web服务器建立连接。</p>
<p>　　二、Java实现Web服务器功能的程序设计</p>
<p>　　根据上述HTTP协议的作用原理，实现GET请求的Web服务器程序的方法如下：</p>
<p>　　(1) 创建ServerSocket类对象，监听端口8080。这是为了区别于HTTP的标准TCP/IP端口80而取的；</p>
<p>　　(2) 等待、接受客户机连接到端口8080，得到与客户机连接的socket；</p>
<p>　　(3) 创建与socket字相关联的输入流instream和输出流outstream；</p>
<p>　　(4) 从与socket关联的输入流instream中读取一行客户机提交的请求信息，请求信息的格式为：GET 路径/文件名 HTTP/1.0</p>
<p>　　(5) 从请求信息中获取请求类型。如果请求类型是GET，则从请求信息中获取所访问的HTML文件名。没有HTML文件名时，则以index.html作为文件名；</p>
<p>　　(6) 如果HTML文件存在，则打开HTML文件，把HTTP头信息和HTML文件内容通过socket传回给Web浏览器，然后关闭文件。否则发送错误信息给Web浏览器；</p>
<p>　　(7) 关闭与相应Web浏览器连接的socket字。</p>
<p>　　下面的程序是根据上述方法编写的、可实现多线程的Web服务器，以保证多个客户机能同时与该Web服务器连接。</p>
<p>　　程序1:WebServer.java文件<br>　　// WebServer.java 用JAVA编写Web服务器<br>　　import java.io.*;<br>　　import java.net.*;<br>　　public class WebServer {<br>　　　public static void main(String args[]) {<br>　　　　int i=1, PORT=8080;<br>　　　　ServerSocket server=null;<br>　　　　Socket client=null;<br>　　　　try {<br>　　　　　server=new ServerSocket(PORT); <br>　　　　　System.out.println("Web Server is listening on port "+server.getLocalPort());<br>　　　　　for (;;) {<br>　　　　　　client=server.accept(); // 接受客户机的连接请求<br>　　　　　　new ConnectionThread(client,i).start(); <br>　　　　　　i++;<br>　　　　　}<br>　　　　} catch (Exception e) {System.out.println(e);}<br>　　　}<br>　　}</p>
<p>　　/* ConnnectionThread类完成与一个Web浏览器的通信 */<br>　　class ConnectionThread extends Thread {<br>　　　Socket client; // 连接Web浏览器的socket字<br>　　　int counter; // 计数器<br>　　　public ConnectionThread(Socket cl,int c) {<br>　　　　client=cl;<br>　　　　counter=c;<br>　　　}<br>　　　public void run() // 线程体<br>　　　{<br>　　　　try {<br>　　　　　String destIP=client.getInetAddress().toString(); // 客户机IP地址<br>　　　　　int destport=client.getPort(); // 客户机端口号<br>　　　　　System.out.println("Connection "+counter+":connected to "+destIP+" on port "+destport+".");<br>　　　　　PrintStream outstream=new PrintStream(client.getOutputStream());<br>　　　　　DataInputStream instream=new DataInputStream(client.getInputStream());<br>　　　　　String inline=instream.readLine(); // 读取Web浏览器提交的请求信息<br>　　　　　System.out.println("Received:"+inline);<br>　　　　　if (getrequest(inline)) { // 如果是GET请求<br>　　　　　　String filename=getfilename(inline);<br>　　　　　　File file=new File(filename);<br>　　　　　　if (file.exists()) { // 若文件存在，则将文件送给Web浏览器<br>　　　　　　　System.out.println(filename+" requested.");<br>　　　　　　　outstream.println("HTTP/1.0 200 OK");<br>　　　　　　　outstream.println("MIME_version:1.0");<br>　　　　　　　outstream.println("Content_Type:text/html");<br>　　　　　　　int len=(int)file.length();<br>　　　　　　　outstream.println("Content_Length:"+len);<br>　　　　　　　outstream.println("");<br>　　　　　　　sendfile(outstream,file); // 发送文件<br>　　　　　　　　outstream.flush();<br>　　　　　　} else { // 文件不存在时<br>　　　　　　　String notfound="&lt;html&gt;&lt;head&gt;&lt;title&gt;Not Found&lt;/title&gt;&lt;/head&gt;<br>　　　　　　　&lt;body&gt;&lt;h1&gt;Error 404-file not found&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;";<br>　　　　　　　outstream.println("HTTP/1.0 404 no found");<br>　　　　　　　outstream.println("Content_Type:text/html");<br>　　　　　　　outstream.println("Content_Length:"+notfound.length()+2);<br>　　　　　　　outstream.println("");<br>　　　　　　　outstream.println(notfound);<br>　　　　　　　outstream.flush();<br>　　　　　　}<br>　　　　　}<br>　　　　　long m1=1; <br>　　　　　while (m1&lt;11100000) {m1++;} // 延时<br>　　　　　client.close();<br>　　　　} catch (IOException e) {<br>　　　　　System.out.println("Exception:"+e);<br>　　　　}<br>　　　}</p>
<p>　　　/* 获取请求类型是否为&#8220;GET&#8221; */<br>　　　boolean getrequest(String s) { <br>　　　　if (s.length()&gt;0)<br>　　　　{<br>　　　　　if (s.substring(0,3).equalsIgnoreCase("GET")) return true;<br>　　　　}<br>　　　　return false;<br>　　　}</p>
<p>　　　/* 获取要访问的文件名 */<br>　　　String getfilename(String s) {<br>　　　　String f=s.substring(s.indexOf(' ')+1);<br>　　　　f=f.substring(0,f.indexOf(' '));<br>　　　　try {<br>　　　　　if (f.charAt(0)=='/')<br>　　　　　f=f.substring(1);<br>　　　　} catch (StringIndexOutOfBoundsException e) {<br>　　　　　System.out.println("Exception:"+e);<br>　　　　}<br>　　　　if (f.equals("")) f="index.html";<br>　　　　return f;<br>　　　}</p>
<p>　　　/*把指定文件发送给Web浏览器 */ <br>　　　void sendfile(PrintStream outs,File file) {<br>　　　　try {<br>　　　　　DataInputStream in=new DataInputStream(new FileInputStream(file));<br>　　　　　int len=(int)file.length();<br>　　　　　byte buf[]=new byte[len];<br>　　　　　in.readFully(buf);<br>　　　　　outs.write(buf,0,len);<br>　　　　　outs.flush();<br>　　　　　in.close();<br>　　　　} catch (Exception e) {<br>　　　　　System.out.println("Error retrieving file.");<br>　　　　　System.exit(1);<br>　　　　}<br>　　　}<br>　　}</p>
<p>　　程序中的ConnectionThread线程子类用来分析一个Web浏览器提交的请求，并将应答信息传回给Web浏览器。其中，
getrequest()方法用来检测客户的请求是否为&#8220;GET&#8221;；getfilename(s)方法是从客户请求信息s中获取要访问的HTML文件名；
sendfile()方法把指定文件内容通过socket传回给Web浏览器。</p>
<p>　　对上述程序的getrequest()方法和相关部分作修改，也能对POST请求进行处理。</p>
<p>　　三、运行实例</p>
<p>　　为了测试上述程序的正确性，将编译后的WebServer.class、ConnectionThread.class和下面的index.html文件置于网络的某台主机的同一目录中（如：主机NT40SRV的C：\JWEB目录）。</p>
<p>　　程序2：index.html文件<br>　　&lt;HTML&gt;<br>　　&lt;HEAD&gt;<br>　　&lt;META HTTP-EQUIV="Content-Type" content="text/html; charset=gb_2312-80"&gt;<br>　　&lt;TITLE&gt;Java Web服务器&lt;/TITLE&gt;<br>　　&lt;/HEAD&gt;<br>　　&lt;BODY&gt;<br>　　&lt;h3&gt;这是用JAVA写出的WEB服务器主页&lt;/h3&gt;<br>　　1998年8月28日<br>　　&lt;hr&gt;<br>　　&lt;/BODY&gt;<br>　　&lt;/HTML&gt;<br>　　首先在该主机上用java命令运行WebServer.class:<br>　　C:\jweb&gt;java webserver</p>
<p>　　然后在客户机运行浏览器软件，在URL处输入WebServer程序所属的URL地址（如：<a href="http://nt40srv:8080/index.html">http://nt40srv:8080/index.html</a>），就在浏览器窗口显示出指定的HTML文档。</p>
<p>　　注意，不能缺省端口号8080，如缺省，则运行该主机的正常WEB服务器。</p>
<p>　　说明，不具备网络条件的可在安装了Windows 95的单机上进行测试，方法是用localhost或127.0.0.1代替URL地址的域名部分，即URL地址为<a href="http://localhost:8080/">http://localhost:8080</a>。</p>
<br>  <img src ="http://www.cnitblog.com/forrest/aggbug/49181.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2008-09-17 23:49 <a href="http://www.cnitblog.com/forrest/articles/49181.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 中的 io 系统总结(zhailu)</title><link>http://www.cnitblog.com/forrest/articles/39989.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Wed, 20 Feb 2008 09:52:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/39989.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/39989.html</wfw:comment><comments>http://www.cnitblog.com/forrest/articles/39989.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/39989.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/39989.html</trackback:ping><description><![CDATA[<div class="postbody">
<p style="font-size: 10pt;" align="center">&nbsp;<o:p></o:p></p>
<p style="font-size: 10pt;"><o:p>&nbsp;</o:p> Java 流在处理上分为字符流和字节流。字符流处理的单元为 2 个字节的 Unicode 字符，分别操作字符、字符数组或字符串，而字节流处理单元为 1 个字节，操作字节和字节数组。 <o:p></o:p></p>
<p style="font-size: 10pt;">Java 内用 Unicode
编码存储字符，字符流处理类负责将外部的其他编码的字符流和 java 内 Unicode 字符流之间的转换。而类
InputStreamReader 和 OutputStreamWriter
处理字符流和字节流的转换。字符流（一次可以处理一个缓冲区）一次操作比字节流（一次一个字节）效率高。&nbsp;<o:p>&nbsp;</o:p> </p>
<p style="font-size: 10pt;">( 一 )<o:p></o:p> </p>
<p style="font-size: 10pt;">以字节为导向的 stream------InputStream/OutputStream </p>
<p style="font-size: 10pt;">InputStream 和 OutputStream 是两个 abstact 类，对于字节为导向的 stream 都扩展这两个鸡肋（基类 ^_^ ） ;<o:p></o:p> </p>
<p style="font-size: 10pt;">1, &nbsp;&nbsp; InputStream </p>
<p style="font-size: 10pt;"><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></v:path><o:lock v:ext="edit" aspectratio="t"></o:lock></v:shapetype><o:p></o:p></p>
<p style="font-size: 10pt;"><o:p><img src="http://www.blogjava.net/images/blogjava_net/sinojava/etc/42134.gif" alt="42134.gif" border="0" height="199" width="462">&nbsp;</o:p> </p>
<p style="font-size: 10pt;">1.1<o:p></o:p> </p>
<p style="font-size: 10pt;">ByteArrayInputStream -- 把内存中的一个缓冲区作为 InputStream 使用 .<o:p></o:p> </p>
<p style="font-size: 10pt;">construct---<o:p></o:p> </p>
<p style="font-size: 10pt;">(A)ByteArrayInputStream(byte[]) 创建一个新字节数组输入流（ ByteArrayInputStream ），它从指定字节数组中读取数据（ 使用 byte 作为其缓冲区数组） <o:p></o:p></p>
<p style="font-size: 10pt;">(B)---ByteArrayInputStream(byte[], int, int) 创建一个新字节数组输入流，它从指定字节数组中读取数据。 <o:p></o:p></p>
<p style="font-size: 10pt;">---mark:: 该字节数组未被复制。 <o:p></o:p></p>
<p style="font-size: 10pt;">1.2<o:p></o:p> </p>
<p style="font-size: 10pt;">StringBufferInputStream -- 把一个 String 对象作为 InputStream .<o:p></o:p> </p>
<p style="font-size: 10pt;">construct---<o:p></o:p>&nbsp;&nbsp;</p>
<p style="font-size: 10pt;">StringBufferInputStream(String) 据指定串创建一个读取数据的输入流串。 <o:p></o:p></p>
<p style="font-size: 10pt;"><o:p>&nbsp;</o:p> </p>
<p style="font-size: 10pt;">注释：不推荐使用 StringBufferInputStream 方法。 此类不能将字符正确的转换为字节。 <o:p></o:p></p>
<p style="font-size: 10pt;">同 JDK 1.1 版中的类似，从一个串创建一个流的最佳方法是采用 StringReader 类。 </p>
<p style="font-size: 10pt;">1.3<o:p></o:p> </p>
<p style="font-size: 10pt;">FileInputStream -- 把一个文件作为 InputStream ，实现对文件的读取操作 </p>
<p style="font-size: 10pt;">construct---<o:p></o:p> </p>
<p style="font-size: 10pt;">(A)FileInputStream(File name) 创建一个输入文件流，从指定的 File 对象读取数据。 <o:p></o:p></p>
<p style="font-size: 10pt;">(B)FileInputStream(FileDescriptor) 创建一个输入文件流，从指定的文件描述器读取数据。 <o:p></o:p></p>
<p style="font-size: 10pt;">(C)-FileInputStream(String&nbsp; name) 创建一个输入文件流，从指定名称的文件读取数据。 </p>
<p style="font-size: 10pt;">method ---- read() 从当前输入流中读取一字节数据。 <o:p></o:p></p>
<p style="font-size: 10pt;">read(byte[]) 将当前输入流中 b.length 个字节数据读到一个字节数组中。 <o:p></o:p></p>
<p style="font-size: 10pt;">read(byte[], int, int) 将输入流中 len 个字节数据读入一个字节数组中。 </p>
<p style="font-size: 10pt;">1.4</p>
<p style="font-size: 10pt;">PipedInputStream ：实现了 pipe 的概念，主要在线程中使用 . 管道输入流是指一个通讯管道的接收端。 <o:p></o:p></p>
<p style="font-size: 10pt;">一个线程通过管道输出流发送数据，而另一个线程通过管道输入流读取数据，这样可实现两个线程间的通讯。 <o:p></o:p></p>
<p style="font-size: 10pt;">construct---<o:p></o:p> </p>
<p style="font-size: 10pt;">PipedInputStream() 创建一个管道输入流，它还未与一个管道输出流连接。 <o:p></o:p></p>
<p style="font-size: 10pt;">PipedInputStream(PipedOutputStream) 创建一个管道输入流 , 它已连接到一个管道输出流。 </p>
<p style="font-size: 10pt;">1.5<o:p></o:p> </p>
<p style="font-size: 10pt;">SequenceInputStream ：把多个 InputStream 合并为一个 InputStream . &#8220;序列输入流&#8221;类允许应用程序把几个输入流连续地合并起来， <o:p></o:p></p>
<p style="font-size: 10pt;">并且使它们像单个输入流一样出现。每个输入流依次被读取，直到到达该流的末尾。 <o:p></o:p></p>
<p style="font-size: 10pt;">然后&#8220;序列输入流&#8221;类关闭这个流并自动地切换到下一个输入流。 </p>
<p style="font-size: 10pt;">construct---<o:p></o:p> </p>
<p style="font-size: 10pt;">SequenceInputStream(Enumeration) 创建一个新的序列输入流，并用指定的输入流的枚举值初始化它。 <o:p></o:p></p>
<p style="font-size: 10pt;">SequenceInputStream(InputStream, InputStream) 创建一个新的序列输入流，初始化为首先 读输入流 s1, 然后读输入流 s2 。 </p>
<p style="font-size: 10pt;">（二） OutputSteam<o:p></o:p> </p>
<p style="font-size: 10pt;"><o:p></o:p></p>
<p style="font-size: 10pt;"><img src="http://www.blogjava.net/images/blogjava_net/sinojava/etc/42135.gif" alt="42135.gif" border="0" height="142" width="458"> <br>2.1<o:p></o:p> </p>
<p style="font-size: 10pt;">ByteArrayOutputStream ： 把信息存入内存中的一个缓冲区中 . 该类实现一个以字节数组形式写入数据的输出流。 <o:p></o:p></p>
<p style="font-size: 10pt;">当数据写入缓冲区时，它自动扩大。用 toByteArray() 和 toString() 能检索数据。 <o:p></o:p></p>
<p style="font-size: 10pt;">constructor <o:p></o:p></p>
<p style="font-size: 10pt;">(A)--- ByteArrayOutputStream() 创建一个新的字节数组输出流。 <o:p></o:p></p>
<p style="font-size: 10pt;">(B)--- ByteArrayOutputStream() 创建一个新的字节数组输出流。 <o:p></o:p></p>
<p style="font-size: 10pt;">(C)--- ByteArrayOutputStream(int) 创建一个新的字节数组输出流，并带有指定大小字节的缓冲区容量。 <o:p></o:p></p>
<p style="font-size: 10pt;">toString(String) 根据指定字符编码将缓冲区内容转换为字符串，并将字节转换为字符。 <o:p></o:p></p>
<p style="font-size: 10pt;">write(byte[], int, int) 将指定字节数组中从偏移量 off 开始的 len 个字节写入该字节数组输出流。 <o:p></o:p></p>
<p style="font-size: 10pt;">write(int) 将指定字节写入该字节数组输出流。 <o:p></o:p></p>
<p style="font-size: 10pt;">writeTo(OutputStream) 用 out.write(buf, 0, count) 调用输出流的写方法将该字节数组输出流的全部内容写入指定的输出流参数。 </p>
<p style="font-size: 10pt;">2.2<o:p></o:p>&nbsp;&nbsp;</p>
<p style="font-size: 10pt;">FileOutputStream: 文件输出流是向 File 或 FileDescriptor 输出数据的一个输出流。 </p>
<p style="font-size: 10pt;">constructor <o:p></o:p></p>
<p style="font-size: 10pt;">(A)FileOutputStream(File&nbsp; name) 创建一个文件输出流，向指定的 File 对象输出数据。 <o:p></o:p></p>
<p style="font-size: 10pt;">(B)FileOutputStream(FileDescriptor) 创建一个文件输出流，向指定的文件描述器输出数据。 <o:p></o:p></p>
<p style="font-size: 10pt;">(C)FileOutputStream(String&nbsp; name) 创建一个文件输出流，向指定名称的文件输出数据。 <o:p></o:p></p>
<p style="font-size: 10pt;">(D)FileOutputStream(String, boolean) 用指定系统的文件名，创建一个输出文件。 </p>
<p style="font-size: 10pt;">2.3<o:p></o:p> </p>
<p style="font-size: 10pt;">PipedOutputStream: 管道输出流是指一个通讯管道的发送端。 一个线程通过管道输出流发送数据， <o:p></o:p></p>
<p style="font-size: 10pt;">而另一个线程通过管道输入流读取数据，这样可实现两个线程间的通讯。 <o:p></o:p></p>
<p style="font-size: 10pt;">constructor<o:p></o:p> </p>
<p style="font-size: 10pt;">(A)PipedOutputStream() 创建一个管道输出流，它还未与一个管道输入流连接。 <o:p></o:p></p>
<p style="font-size: 10pt;">(B)PipedOutputStream(PipedInputStream) 创建一个管道输出流，它已连接到一个管道输入流。 </p>
<p style="font-size: 10pt;">( 二 )<o:p></o:p> </p>
<p style="font-size: 10pt;">以字符为导向的 stream Reader/Writer<o:p></o:p> </p>
<p style="font-size: 10pt;">以 Unicode 字符为导向的 stream ，表示以 Unicode 字符为单位从 stream 中读取或往 stream 中写入信息。 <o:p></o:p></p>
<p style="font-size: 10pt;">Reader/Writer 为 abstact 类 <o:p></o:p></p>
<p style="font-size: 10pt;">以 Unicode 字符为导向的 stream 包括下面几种类型： </p>
<p style="font-size: 10pt;">1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Reader<o:p></o:p> </p>
<p style="font-size: 10pt;"><o:p></o:p></p>
<p style="font-size: 10pt;"><o:p><img src="http://www.blogjava.net/images/blogjava_net/sinojava/etc/42136.gif" alt="42136.gif" border="0" height="169" width="462">&nbsp;</o:p> </p>
<p style="font-size: 10pt;">1.1 <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp; CharArrayReader ：与 ByteArrayInputStream 对应此类实现一个可用作字符输入流的字符缓冲区 <o:p></o:p></p>
<p style="font-size: 10pt;">constructor<o:p></o:p> </p>
<p style="font-size: 10pt;">CharArrayReader(char[]) 用指定字符数组创建一个 CharArrayReader 。 <o:p></o:p></p>
<p style="font-size: 10pt;">CharArrayReader(char[], int, int) 用指定字符数组创建一个 CharArrayReader<o:p></o:p> </p>
<p style="font-size: 10pt;">1.2<o:p></o:p> </p>
<p style="font-size: 10pt;">StringReader ： 与 StringBufferInputStream 对应其源为一个字符串的字符流。 <o:p></o:p></p>
<p style="font-size: 10pt;">StringReader(String) 创建一新的串读取者。</p>
<p style="font-size: 10pt;">1.3<o:p></o:p> </p>
<p style="font-size: 10pt;">FileReader ： 与 FileInputStream 对应 </p>
<p style="font-size: 10pt;">1.4<o:p></o:p> </p>
<p style="font-size: 10pt;">PipedReader ：与 PipedInputStream 对应 </p>
<p style="font-size: 10pt;">2.&nbsp; Writer <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;<img src="http://www.blogjava.net/images/blogjava_net/sinojava/etc/42137.gif" alt="42137.gif" border="0" height="222" width="465"> <o:p></o:p></p>
<p style="font-size: 10pt;">2.1&nbsp; &nbsp; CharArrayWrite ： 与 ByteArrayOutputStream 对应 <o:p></o:p></p>
<p style="font-size: 10pt;">2.2&nbsp;&nbsp; StringWrite ：无与之对应的以字节为导向的 stream <o:p></o:p></p>
<p style="font-size: 10pt;">2.3&nbsp; FileWrite ： 与 FileOutputStream 对应 <o:p></o:p></p>
<p style="font-size: 10pt;">2.4&nbsp; PipedWrite ：与 PipedOutputStream 对应 </p>
<p style="font-size: 10pt;">（三） </p>
<p style="font-size: 10pt;">两种不现导向的 stream 之间的转换&nbsp;&nbsp;</p>
<p style="font-size: 10pt;">3.1<o:p></o:p> </p>
<p style="font-size: 10pt;">InputStreamReader 和 OutputStreamReader ： </p>
<p style="font-size: 10pt;">把一个以字节为导向的 stream 转换成一个以字符为导向的 stream 。 </p>
<p style="font-size: 10pt;">InputStreamReader 类是从字节流到字符流的桥梁：它读入字节，并根据指定的编码方式，将之转换为字符流。 <o:p></o:p></p>
<p style="font-size: 10pt;">使用的编码方式可能由名称指定，或平台可接受的缺省编码方式。 </p>
<p style="font-size: 10pt;">InputStreamReader 的 read() 方法之一的每次调用，可能促使从基本字节输入流中读取一个或多个字节。 <o:p></o:p></p>
<p style="font-size: 10pt;">为了达到更高效率，考虑用 BufferedReader 封装 InputStreamReader ， <o:p></o:p></p>
<p style="font-size: 10pt;">BufferedReader in = new BufferedReader(new InputStreamReader(System.in));<o:p></o:p> </p>
<p style="font-size: 10pt;">例如： // 实现从键盘输入一个整数 <o:p></o:p></p>
<p style="font-size: 10pt;">String s = null;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <o:p></o:p></p>
<p style="font-size: 10pt;">InputStreamReader re = new InputStreamReader(System.in); <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedReader br = new BufferedReader(re); </p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try { <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s = br.readLine(); <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("s= " + Integer.parseInt(s)); <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; br.close(); <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (IOException e) <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace(); <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (NumberFormatException e)// 当应用程序试图将字符串转换成一种数值类型，但该字符串不能转换为适当格式时，抛出该异常。 <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(" 输入的不是数字 "); <o:p></o:p></p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p style="font-size: 10pt;">InputStreamReader(InputStream) 用缺省的字符编码方式，创建一个 InputStreamReader 。 <o:p></o:p></p>
<p style="font-size: 10pt;">InputStreamReader(InputStream, String) 用已命名的字符编码方式，创建一个 InputStreamReader 。 <o:p></o:p></p>
<p style="font-size: 10pt;"><o:p>&nbsp;</o:p> </p>
<p style="font-size: 10pt;">OutputStreamWriter 将多个字符写入到一个输出流，根据指定的字符编码将多个字符转换为字节。 <o:p></o:p></p>
<p style="font-size: 10pt;">每个 OutputStreamWriter 合并它自己的 CharToByteConverter, 因而是从字符流到字节流的桥梁。</p>
<p style="font-size: 10pt;">（四） <o:p></o:p></p>
<p style="font-size: 10pt;">Java IO 的一般使用原则 ：&nbsp;&nbsp;</p>
<p style="font-size: 10pt;">一、按数据来源（去向）分类： <o:p></o:p></p>
<p style="font-size: 10pt;">1 、是文件： FileInputStream, FileOutputStream, ( 字节流 )FileReader, FileWriter( 字符 )<o:p></o:p> </p>
<p style="font-size: 10pt;">2 、是 byte[] ： ByteArrayInputStream, ByteArrayOutputStream( 字节流 )<o:p></o:p> </p>
<p style="font-size: 10pt;">3 、是 Char[]: CharArrayReader, CharArrayWriter( 字符流 )<o:p></o:p> </p>
<p style="font-size: 10pt;">4 是 String: StringBufferInputStream, StringBufferOuputStream ( 字节流 )StringReader, StringWriter( 字符流 )<o:p></o:p> </p>
<p style="font-size: 10pt;">5 、网络数据流： InputStream, OutputStream,( 字节流 ) Reader, Writer( 字符流 )<o:p></o:p> </p>
<p style="font-size: 10pt;">二、按是否格式化输出分： <o:p></o:p></p>
<p style="font-size: 10pt;">1 、要格式化输出： PrintStream, PrintWriter<o:p></o:p> </p>
<p style="font-size: 10pt;">三、按是否要缓冲分： <o:p></o:p></p>
<p style="font-size: 10pt;">1 、要缓冲： BufferedInputStream, BufferedOutputStream,( 字节流 ) BufferedReader, BufferedWriter( 字符流 )<o:p></o:p> </p>
<p style="font-size: 10pt;">四、按数据格式分： <o:p></o:p></p>
<p style="font-size: 10pt;">1 、二进制格式（只要不能确定是纯文本的） : InputStream, OutputStream 及其所有带 Stream 结束的子类 <o:p></o:p></p>
<p style="font-size: 10pt;">2 、纯文本格式（含纯英文与汉字或其他编码方式）； Reader, Writer 及其所有带 Reader, Writer 的子类 </p>
<p style="font-size: 10pt;">五、按输入输出分： <o:p></o:p></p>
<p style="font-size: 10pt;">1 、输入： Reader, InputStream 类型的子类 <o:p></o:p></p>
<p style="font-size: 10pt;">2 、输出： Writer, OutputStream 类型的子类 </p>
<p style="font-size: 10pt;">六、特殊需要： <o:p></o:p></p>
<p style="font-size: 10pt;">1 、从 Stream 到 Reader,Writer 的转换类： InputStreamReader, OutputStreamWriter<o:p></o:p> </p>
<p style="font-size: 10pt;">2 、对象输入输出： ObjectInputStream, ObjectOutputStream<o:p></o:p> </p>
<p style="font-size: 10pt;">3 、进程间通信： PipeInputStream, PipeOutputStream, PipeReader, PipeWriter<o:p></o:p> </p>
<p style="font-size: 10pt;">4 、合并输入： SequenceInputStream<o:p></o:p> </p>
<p style="font-size: 10pt;">5 、更特殊的需要： PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader<o:p></o:p> <br></p>
<p style="font-size: 10pt;">决定使用哪个类以及它的构造进程的一般准则如下（不考虑特殊需要）： <o:p></o:p></p>
<p style="font-size: 10pt;">首先，考虑最原始的数据格式是什么： 原则四 <o:p></o:p></p>
<p style="font-size: 10pt;">第二，是输入还是输出：原则五 <o:p></o:p></p>
<p style="font-size: 10pt;">第三，是否需要转换流：原则六第 1 点 <o:p></o:p></p>
<p style="font-size: 10pt;">第四，数据来源（去向）是什么：原则一 <o:p></o:p></p>
<p style="font-size: 10pt;">第五，是否要缓冲：原则三 （特别注明：一定要注意的是 readLine() 是否有定义，有什么比 read, write 更特殊的输入或输出方法） <o:p></o:p></p>
<p style="font-size: 10pt;">第六，是否要格式化输出：原则二 </p>
</div><img src ="http://www.cnitblog.com/forrest/aggbug/39989.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2008-02-20 17:52 <a href="http://www.cnitblog.com/forrest/articles/39989.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何将System.out的内容重定向输出到一个界面上的文本框中</title><link>http://www.cnitblog.com/forrest/articles/35021.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Thu, 18 Oct 2007 02:25:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/35021.html</guid><description><![CDATA[<span class="javascript" id="text50260">import javax.swing.JFrame;<br>import javax.swing.JTextArea;<br>import java.io.PrintStream;<br>class StreamToTextArea extends JFrame {<br>&nbsp;&nbsp;//declare PrintStream and JTextArea<br>&nbsp;&nbsp;&nbsp;&nbsp;private static PrintStream ps = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;private JTextArea textPane = new JTextArea();&nbsp;&nbsp;//constructor<br>&nbsp;&nbsp;&nbsp;&nbsp;public StreamToTextArea() {<br><br>&nbsp;&nbsp;&nbsp;&nbsp;setSize( 310, 180 );<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getContentPane().add(textPane);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//this is the trick: overload the println(String)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//method of the PrintStream<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//and redirect anything sent to this to the text box<br>&nbsp;&nbsp;&nbsp;&nbsp;ps =  new PrintStream(System.out) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void println(String x) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;textPane.append(x + "\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public PrintStream getPs() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return ps;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;public static void main(String args[]) {<br>&nbsp;&nbsp;&nbsp;&nbsp;//create object<br>&nbsp;&nbsp;&nbsp;&nbsp;StreamToTextArea blah = new StreamToTextArea();<br>&nbsp;&nbsp;&nbsp;&nbsp;//show it<br>&nbsp;&nbsp;&nbsp;&nbsp;blah.show();<br>&nbsp;&nbsp;&nbsp;&nbsp;//redirect the output stream<br>&nbsp;&nbsp;&nbsp;&nbsp;System.setOut(blah.getPs());<br>&nbsp;&nbsp;&nbsp;&nbsp;//print to the text box<br>&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("IT'S ALIVE!!");<br>&nbsp;&nbsp;&nbsp;&nbsp;//print to the terminal (not a string)<br>&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(1);<br>&nbsp;&nbsp;&nbsp;&nbsp;//print the same thing to the text box (now a string)<br>&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("" + 1);<br>&nbsp;&nbsp;}<br>}<br><br>// There are still many other ways to do same thing</span><img src ="http://www.cnitblog.com/forrest/aggbug/35021.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2007-10-18 10:25 <a href="http://www.cnitblog.com/forrest/articles/35021.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>