seannell

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

HTTP Server程序

    本文中我们构建一个完整的Http Server应用程序,它接收来自浏览器的HTTP请求,并将服务器端的资源发送给浏览器。如果浏览器请求的资源不存在,就返回404错误。

    实际上,一个http server就是一个socket服务端,接收来自socket客户端的请求。下面我们看一下服务器端如何编制。

    以下是服务端的代码源码。

package com.my.server;
    
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

import com.my.server.entity.Request;
import com.my.server.entity.Response;
    
public class HttpServer {

	  /** WEB_ROOT is the directory where our HTML and other files reside.
	   *  For this package, WEB_ROOT is the "webroot" directory under the working
	   *  directory.
	   *  The working directory is the location in the file system
	   *  from where the java command was invoked.
	   */
	  public static final String WEB_ROOT =
			System.getProperty("user.dir") + File.separator  + "webroot";
	
	  // shutdown command
	  private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
	
	  // the shutdown command received
	  private boolean shutdown = false;
	
	  public static void main(String[] args) {
	    HttpServer server = new HttpServer();
	    server.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();
		    input = socket.getInputStream();
		    output = socket.getOutputStream();
	    
		    // create Request object and parse
		    Request request = new Request(input);
		    request.parse();
		    
		    // create Response object
		    Response response = new Response(output);
		    response.setRequest(request);
		    response.sendStaticResource();
		    
		    // Close the socket
		    socket.close();
		    
		    //check if the previous URI is a shutdown command
		    shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
	      }catch (Exception e) {
		    e.printStackTrace();
		    continue;
	      }
	    }
	  }
}

Request对象

    在上述HTTP Server程序中,接收一个请求流,并将请求转换成一个Request对象,以方便http处理request(即parse方法)。请求对象以及parse方法的源码如下所示。

package com.my.server.entity;

import java.io.InputStream;
import java.io.IOException;

public class Request {

  private InputStream input;
  private String uri;

  public Request(InputStream input) {
	this.input = input;
  }

  public void parse() {
    // Read a set of characters from the socket
    StringBuffer request = new StringBuffer(2048);
    int i;
    byte[] buffer = new byte[2048];
    try {
      i = input.read(buffer);
    }
    catch (IOException e) {
      e.printStackTrace();
      i = -1;
    }
    for (int j=0; j<i; j++) {
      request.append((char) buffer[j]);
    }
    uri = parseUri(request.toString());
  }

  private String parseUri(String requestString) {
    int index1, index2;
    index1 = requestString.indexOf(' ');
    if (index1 != -1) {
      index2 = requestString.indexOf(' ', index1 + 1);
      if (index2 > index1)
    return requestString.substring(index1 + 1, index2);
    }
    return null;
  }

  public String getUri() {
	return uri;
  }
}

Response对象

    同样,在上述HTTP Server程序中,会返回给浏览器一个响应,这个响应是通过Response对象生成的。Response对象先接收一个Request对象,从request对象中读取请求的文件,并从本地文件中读取文件流,然后将文件流返回给浏览器,也就是response.sendStaticResource()实现的方法。下面是Response的详细内容。

package com.my.server.entity;

import java.io.OutputStream;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.File;

import com.my.server.HttpServer;

/* HTTP Response = Status-Line
 *(( general-header | response-header | entity-header ) CRLF)
  CRLF
  [ message-body ]
  Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
 */

public class Response {

  private static final int BUFFER_SIZE = 1024;
  Request request;
  OutputStream output;

  public Response(OutputStream output) {
	this.output = output;
  }

  public void setRequest(Request request) {
    this.request = request;
  }

  public void sendStaticResource() throws IOException {
    byte[] bytes = new byte[BUFFER_SIZE];
    FileInputStream fis = null;
    try {
      File file = new File(HttpServer.WEB_ROOT, request.getUri());
      if (file.exists()) {
	    fis = new FileInputStream(file);
	    int ch = fis.read(bytes, 0, BUFFER_SIZE);
	    while (ch!=-1) {
	      output.write(bytes, 0, ch);
	      ch = fis.read(bytes, 0, BUFFER_SIZE);
	    }
      }else {
	    // file not found
	    String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
	      "Content-Type: text/html\r\n" +
	      "Content-Length: 23\r\n" +
	      "\r\n" +
	      "<h1>File Not Found</h1>";
	    output.write(errorMessage.getBytes());
      }
    }
    catch (Exception e) {
      // thrown if cannot instantiate a File object
      System.out.println(e.toString() );
    }
    finally {
      if (fis!=null)
    fis.close();
    }
  }
}

    如果我们的程序目录是这样的:

程序目录结构

    而index.html文件的内容是这样的:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	你们好,能不能显示中文呢?
</body>
</html>

    那么在启动java程序后,我们就可以通过浏览器访问地址:
    http://localhost:8080/index.html
    来访问资源,页面会显示为

index.html页面

posted on 2015-03-29 23:07  seannell  阅读(363)  评论(0编辑  收藏  举报