一个Web服务器也被称为HTTP服务器,它通过HTTP协议与客户端通信。这个客户端通常指的是Web浏览器。一个基于Java的Web服务器用到二个重要的类,java.net.Socket与java.net.ServerSocket,并通过HTTP消息通信。因此,本文从讨论HTTP与这二个类开始,然后我将解释一个与本文相关的简单的Web应用。TheHypertextTransferProtocol(HTTP)HTTP是一种让Web服务器与浏览器(客户端)通过Internet发送与接收数据的协议。它是一个请求、响应协议--客户端发出一个请求,服务器响应这个请求。HTTP运用可靠的TCP连接,通常用的TCP80端口。它的第一个版本是HTTP/0.9,然后被HTTP/1.0取代。当前的版本是HTTP/1.1,由RFC2616(.pdf)定义。本节主要对应HTTP1.1,足够使你充分理解由Web服务器程序发出的消息。如果你对更加详细的知识有兴趣,可以参考RFC2616。在HTTP中,客户端总是通过建立一个连接与发送一个HTTP请求来发起一个事务。服务器不能主动去与客户端联系,也不能给客户端发出一个回叫连接。客户端与服务器端都可以提前中断一个连接。例如,当用一个浏览器下载一个文件时,你可以通过点击“停止”键来中断文件的下载,关闭与服务器的HTTP连接。HTTP请求一个HTTP请求包含三个部分:Method-URI-Protocol/Version方法-地址-版本Requestheader请求头Entitybody请求实体下面是一个HTTP请求实例:POST/servlet/default.jspHTTP/1.1Accept:text/plain;text/htmlAccept-Language:en-gbConnection:Keep-AliveHost:localhostReferer::Mozilla/4.0(compatible;MSIE4.01;Windows98)Content-Length:33Content-Type:application/x-=Franks&FirstName=MichaelTheMethod-URI-Protocol/Version在这个请求的第一行:POST/servlet/default.jspHTTP/1.1其中POST是请求的类型。每个客户端HTTP请求可以是HTTP规范中指定的许多请求类型中的一种。HTTP1.1支持七种类型的请求,它们是GET,POST,HEAD,OPTIONS,PUT,DELETE,TRACE。其中GET与POST是Internet应用中经常用到的二种请求类型。URI完整地指定了Internet资源。一个URI通常被解析为相对服务器的根目录。这样,它应该总是以一个'/'前缀开始。一个URL实际上是URI的一种类型。Version指的是该HTTP请求所用到的HTTP协议版本。请求头包含了客户端环境与请求实体的一些有用的信息。例如它包含浏览器设定的语言、实体的长度等等。每条请求头用回车换行符(CRLF)分开。一个非常重要的空行分开了请求头与实体,它标志着实体内容的开始。一些Internet开发书籍认为这个CRLF空行是HTTP请求的第四个部分。在上面的HTTP请求中,实体只是简单以下的一行:LastName=Franks&FirstName=Michael在一个典型的HTTP请求中,请求实体内容会长得多。HTTP响应与请求相似,HTTP响应也由三部分组成:Protocol-Statuscode-Description协议状态描述代码Responseheaders响应头Entitybody响应实体以下是一个HTTP响应的实例:HTTP/1.1200OKServer:Microsoft-IIS/4.0Date:Mon,3Jan199813:13:33GMTContent-Type:text/htmlLast-Modified:Mon,11Jan199813:23:42GMTContent-Length:112WelcometoBrainySoftware响应头的第一行类似请求头的第一行,告诉你所用的协议是HTTP1.1,请求成功(200=success),以及没有任何问题。响应头类似请求头也包含了一些有用的信息。响应的实体响应本身的HTML内容。头与实体之间由回车换行的空行(CRLF)分开。Socket类一个socket是一个网络连接的端点,它使得一个应用可以从网络读与写。在不同电脑上的二个应用软件能够通过收发字节流而彼此通信。要发一个信息到另一个应用程序,你需要知道它的IP地址,以及它的socket端口号。在Java中,一个socket用java.net.Socket来实现。要创建一个socket,你可以用Socket类中几个构建方法中的一个。其中一个接受主机名与端口号作为参数:newSocket(yahoo.com,80);一旦你成功地创建了一个Socket类的实例,你就可以用它去发送与接收字节流了。要发送字节流,你需要呼叫Socket类的getOutputStream方法来得到一个java.io.OutputSteam对象。要发送文本到远程的程序,你通常需要从返回的OutputStream创建一个java.io.PrintWriter对象。要从连接的另一端接收字节流,你需要呼叫Socket类的getInputStream方法,它返回一个java.io.InputStream对象。以下代码创建一个可以与本地HTTP服务器通信的socket(127.0.0.1表示一个本地的主机),发送一个HTTP请求,并接收从服务器的响应。它还创建一个StringBuffer对象来接受响应,并打印到控制台。Socketsocket=newSocket(127.0.0.1,8080);OutputStreamos=socket.getOutputStream();booleanautoflush=true;PrintWriterout=newPrintWriter(socket.getOutputStream(),autoflush);BufferedReaderin=newBufferedReader(newInputStreamReader(socket.getInputStream()));//sendanHTTPrequesttothewebserverout.println(GET/index.jspHTTP/1.1);out.println(Host:localhost:8080);out.println(Connection:Close);out.println();//readtheresponsebooleanloop=true;StringBuffersb=newStringBuffer(8096);while(loop){if(in.ready()){inti=0;while(i!=-1){i=in.read();sb.append((char)i);}loop=false;}Thread.currentThread().sleep(50);}//displaytheresponsetotheoutconsoleSystem.out.println(sb.toString());socket.close();注意要从web服务器得到正确的响应,你必须要发送用HTTP协议编译了的HTTP请求。如果你看了上面的HTTP部分,你应该能够理解上面代码中的HTTP请求。编者注:这篇文章节选自budi自己出版的书<Tomcat内幕>。你可以在他的网站得到更多的相关资料。基于Java的Web服务器工作原理2作者:fajaven译发文时间:2003.09.1217:00:38ServerSocket类Socket类描述的是“客户端”socket,当你需要创建与远程服务程序连接时需要用到它。如果你想实现一个服务程序,如HTTP服务器或者FTP服务器,则需要另外不同的方法。这是因为你的服务器必须随时服务,它不知道什么时候会有一个客户端程序需要连接它。因为这个目的,你需要用到java.net.ServerSocket这个类,它是服务器端socket的一个实现。服务器端socket等待来自客户端的连接请求。一旦它收到一个连接请求,它创建一个socket实例来与客户端进行通信。要创建服务器端socket,需要用到ServerSocket类提供的四个构建方法中的一个。你需要指定服务器端socket侦听的IP地址与端口号。比较典型地,这个IP地址可以是127.0.0.1,意思是该服务器端socket侦听的是本地机器。服务器端socket侦听的IP地址指的是绑定地址。服务器端socket另一个重要的属性是队列长度,即它拒绝请求前所接受的最大请求排队长度。ServerSocket类的构建方法之一如下:publicServerSocket(intport,intbackLog,InetAddressbindingAddress);对于这个构建方法,绑定地址必须是java.net.InetAddress类的实例。创建一个InetAddress类的对象的简单方法是呼叫其静态方法getByName,传递一个包含主机名的字符串。InetAddress.getByName(127.0.0.1);以下行的代码创建了一个服务器端socket,它侦听本地机器的8080端口,限制队列长度为1。newServerSocket(8080,1,InetAddress.getByName(127.0.0.1));一旦有了一个ServerSocket实例,就可以通过呼叫其accept方法来让它等待进来的链接请求。这个方法只有当接收到请求时才返回,它返回的是Socket类的实例。这个Socket对象就可以用来从客户端应用程序发送与接收字节流,正如上节据说的那样。实际上,accept方法是本文例子中用到的唯一方法。应用实例我们的web服务器程序是ex01.pyrmont包的一部分,它包含三个类:HttpServer;Request;Response。整个程序的入口(静态main方法)是HttpServer类。它创建一个HttpServer的实例,并呼叫其await方法。正如名字表达的,await在一个特定的端口等待HTTP请求,处理它们,并返回响应给客户端。它保持等待状态,直到收到停止命令。(用方法名await代替wait,是因为System中有一个重要的与线程相关的方法)这个程序只从一个特定的目录发送静态资源,如HTML与图像文件。它只支持没有文件头(如日期与cookie)的情况。现在我们将在如下的几节中看一下这三个类。HttpServer类HttpServer实现了一个web服务器,它可以提供(serve)特定目录及其子目录下的静态资源。这个特定的目录由publicstaticfinalWEB_ROOT指定。WEB_ROOT初始化如下:publicstaticfinalStringWEB_ROOT=System.getProperty(user.dir)+File.separator+webroot;代码列表中包含了一具叫做webroot的目录,里面有一些静态的资源,你可以用来测试本应用。你也可以看到一个servlet,在我的下一篇文章将会被用到:“Servlets容器是怎样工作的”。为了请求一个静态的资源,在浏览器的地址栏输入如是地址:如果你从不同的机器上发送请求到运行本应用的机器,则machinename是运行应用机器的机器名或IP地址,por