免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1817 | 回复: 0
打印 上一主题 下一主题

Java Web服务器工作原理 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2004-11-30 17:26 |只看该作者 |倒序浏览

by
Budi Kurniawan
摘要在本文中,你应经看到一个简单的超文本传输协议(HTTP)HTTP是允许web服务器和浏览器通过Internet发送和接收数据的协议。它是一个请求和响应的协议——客户端发出一个请求,服务器端对该请求作出响应。HTTP使用可靠的TCP连接,默认的端口号是80。HTTP最初的版本是HTTP/0.9,后来被HTTP/1.0替代。当前的版本是HTTP/1.1,由RFC2616定义。这部分简要介绍HTTP 1.1;足以使你能够明白web应用服务器发送的信息。如果你想了解更详细的关于HTTP 1.1的信息,可以参看RFC 2616。
在HTTP中,客户端总是通过建立一个连接并发送一个HTTP请求来发起一个事务。服务器没有固定的位置来连接一个客户端或者返回一个连接给客户端。客户端或服务器端都可以提前终止连接。例如:当使用一个web浏览器的时候,可以通过点极浏览器上的停止按钮来终止一个文件下载的操作,有效地关闭与web服务器的连接。
HTTP请求
一个HTTP请求由三个部分组成:
Method-URI-Protocol/Version Request headers Entity body
以下是一个HTTP请求的例子:
POST /servlet/default.jsp HTTP/1.1Accept: text/plain; text/html Accept-Language: en-gb Connection: Keep-Alive Host: localhost Referer: http://localhost/ch8/SendDetails.htm User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98) Content-Length: 33 Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate

LastName=Franks&FirstName=Michael
method-URI-Protocol/Version出现在请求的第一行。
POST /servlet/default.jsp HTTP/1.1POST是请求的method,/servlet/default.jsp表明了URI,HTTP/1.1是Protocol/Version部分。每个HTTP请求可以使用HTTP标准中指定的诸多方法中的一个。HTTP 1.1支持七种类型的请求:GET, POST, HEAD, OPTIONS, PUT, DELETE和TRACE。GET和POST是Internet应用软件中最常使用的。URI指定了一个Internet资源的完整路径。一个URI通常被作为相对于服务器的更目录的路径来解释。因此,它必须总是以斜线(“/”)开头。URL实际上是URI的一种。协议版本号表明所使用的HTTP协议的版本。请求的头包含了客户端环境和请求的实体的一些有用信息。例如,它可以包含浏览器适用的语言,请求实体的长度等等。每个头都通过换行来划分。在请求的头和实体之间有一个很重要的空行。它标明了请求主体的开始。一些Internet设计的书把这一空行当作是HTTP请求的第四个组成部分。在前面的HTTP请求中,请求的主体是下面简单的一行:LastName=Franks&FirstName=Michael典型的HTTP请求中请求的主体都会比这一行长得多。HTTP响应和请求类似,HTTP响应也包括三个部分:Protocol-Status code-Description Response headers Entity body
下面是一个HTTP响应的例子:
HTTP/1.1 200 OKServer: Microsoft-IIS/4.0Date: Mon, 3 Jan 1998 13:13:33 GMTContent-Type: text/htmlLast-Modified: Mon, 11 Jan 1998 13:23:42 GMTContent-Length: 112

Welcome to Brainy Software
响应头的第一行和请求头的第一行类似。第一行告诉你使用的HTTP协议的版本是1.1,请求成功(200=成功),并且没有错误。
响应头包含的有用信息类似请求的头。响应主体是内容为响应本身的HTML。头和主体通过CRLFs来划分。
Socket类
Socket是网络连接的终点。Socket是一个应用能够向网络进行读和写操作。两个居于两台不同的电脑上的应用程序可以以通过连接发送和接受byte流的方式来通信。如果想要发送信息到另外一个应用,你必须知道它的IP地址和它的socket的端口号。Java中,socket由java.net.Socket类来描述。
你可以用socket类的多个构造器中的一个来创建一个socket。其中的一个构造器接收主机名和端口号:
public Socket(String host, int port)
host是远程机器的IP地址,port是远程应用的端口号。例如,为了连接yahoo.com的80端口,你可以象下面这样创建socket:
new Socket("yahoo.com", 80);
一旦你成功创建一个socket的实例以后,你就可以用它来发送和接收bytes流了。为了发送byte流,你必须先调用socket类的getOutputStream方法来获得一个java.io.OutputStream对象。为了发送文本到一个远程应用,你应该从OutputStream的返回创建一个java.io.PrintWriter对象。为了从连接的另一端接收byte流,你可以调用socket的getInputStream方法,它会返回一个java.io.InputStream。
下面的程序片断创建一个可以和本地HTTP服务器通信、发送HTTP请求、接收响应的socket。它创建一个StringBuffer对象来保存响应内容,并输出到控制台。
Socket socket    = new Socket("127.0.0.1", "8080");OutputStream os   = socket.getOutputStream();boolean autoflush = true;PrintWriter out   = new PrintWriter( socket.getOutputStream(), autoflush );BufferedReader in = new BufferedReader(     new InputStreamReader( socket.getInputStream() ));

// send an HTTP request to the web serverout.println("GET /index.jsp HTTP/1.1");out.println("Host: localhost:8080");out.println("Connection: Close");out.println();

// read the responseboolean loop    = true;StringBuffer sb = new StringBuffer(8096);

while (loop) {    if ( in.ready() ) {        int i=0;        while (i!=-1) {            i = in.read();            sb.append((char) i);        }        loop = false;    }    Thread.currentThread().sleep(50);}

// display the response to the out consoleSystem.out.println(sb.toString());socket.close();
注意要想从服务器得到正确的响应,你必须发送一个遵循HTTP协议的HTTP请求。如果你已经阅读了前面的“The Hypertext Transfer Protocol (HTTP)”部分,你就能够理解上面代码中的HTTP请求。
ServerSocket类
Socket类描绘一个“客户端”socket;一个在你想连接到一个远程服务器应用程序的任何时候创建的socket。如果你想实现的是一个服务器端应用,例如一个HTTP服务器或一个FTP服务器,你就得使用另外的方式。因为你的服务器并不知道什么时候一个客户端的应用会尝试连接它,所以它必须在任何时候都处于等待中。
为了达到这个目的,你需要使用java.net.ServerSocket类。它是一个服务器端socket的实现。服务器端socket等待客户端的连接请求。一旦它接收到一个连接请求,它就创建一个Socket的实例来处理和该客户端的通信。
你需要使用ServerSocket类提供的四个构造方法中的一个来创建一个服务器端socket。你必须指定服务器socket要监听的IP地址和端口号。典型IP地址是127.0.0.1,意味着服务器socket要在本机上监听。服务器socket兼听的IP地址被作为绑顶的地址引用。另一个服务器socket的特性是它的连接数,就是服务器socket开始拒绝受到的请求之前的连接请求队列的最大长度。
ServerSocket类的一个构造方法如下:
public ServerSocket(int port, int backLog, InetAddress bindingAddress);
在这个构造方法中,“bindingAddress”必须是一个的java.net.InetAddress实例。一个简单的创建InetAddress对象的方式是调用它的静态方法getByName,并传送一个包含主机名的字符串给该方法:
InetAddress.getByName("127.0.0.1");下面的一行代码创建一个在本机8080端口上监听的最大连接数为1的ServerSocket。new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));一旦你有了一个ServerSocket的实例,你就可以让它通过调用accept方法来等待连接请求。该方法只有当有一个连接请求的时候才返回一个Socket类的实例。这个Socket对象能被用来从客户端应用接收byte流,正如“Socket类”部分所描述的那样。实际上这个accept方法是贯穿这篇文章的应用所使用的唯一的方法。应用程序我们的web服务器应用程序是ex01.pyrmont包的一个部分,由三个类组成:HttpServer Request Response
这个应用程序的入口(那个静态的main方法)在HttpServer类里面。它创建一个HttpServer的实例并调用它的await方法。正如名字所暗示的,await在指定的端口等待和处理HTTP请求,并发送响应给客户端。在接收到一个shutdown的命令之前它会一直处于等待状态。(因为wait是System.Object类中一个为线程工作的重要的方法的名字,所以方法的名字用await代替了wait)
这个应用程序仅仅从一个指定的路径发送静态的资源,例如HTML和image文件。它不支持包头(例如日期和cookies)。
接下来的部分我们机来了解一下这三个类。
HttpServer类
HttpServer类描绘一个web服务器以及能够在制定的根路径WEB_ROOT和WEB_ROOT下的子目录下能够找到的静态资源。WEB_ROOT的初始化如下:
public static final String WEB_ROOT =        System.getProperty("user.dir") + File.separator  + "webroot";
代码的参数列表包含了一个你可以找到一些静态资源来测试这个应用程序的路径——webroot。在我的下一篇文章“How Servlet Containers Work”中你还将发现我们会用到的一个servlet。
如果你想请求一个静态资源,你可以在浏览器的地址栏输入以下URL:
http://machineName:port/staticResource
如果请求是从另外一台主机上发出,那么machineName就运行这个应用程序的主机的名字或IP地址。如果发送请求的是同一台主机,你可以用localhost作为machineName。port是,staticResource是被请求的保存于WEB_ROOT目录下的文件的文件名。
据个例子,如果你想使用同一台电脑来测试这个应用程序,让HttpServer发送文件index.html,可以使用下面的URL:
http://localhost:8080/index.html
要停止服务器的运行,可以在浏览器地址栏内在host:port部分之后输入宕机命令——一个预先定义的字符串。宕机命令在HttpServer类里面定义为一个名为SHUTDOWN的最终变量。  
private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
因此,要停止服务器时使用:
http://localhost:8080/SHUTDOWN
现在来看看表1.1中给出的await方法的代码。方法的说明在表后给出。
表1.1. HttpServer类的await方法
public void await() {    ServerSocket serverSocket = null;    int port = 8080;    try {        serverSocket =  new ServerSocket(port, 1,        InetAddress.getByName("127.0.0.1"));    }    catch (IOException e) {        e.printStackTrace();        System.exit(1);    }

    // Loop waiting for a request    while (!shutdown) {        Socket socket = null;        InputStream input = null;        OutputStream output = null;        try {            socket = serverSocket.accept();         &n


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/2560/showart_6955.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP