《How Tomcat Works》读书笔记(一)A Simple Web Server

一个基于JAVA的Web服务器主要使用两个重要类:java.net.Socket和java.net.ServerSocket。

因为web服务器使用HTTP与客户端进行通信,所以也称HTTP服务器。

1.1 HTTP

HTTP请求:
 Method—Uniform Resource Identifier (URI)—Protocol/Version
 Request headers
 Entity body
e.g. 

POST /examples/default.jsp HTTP/1.1
Accept: text/plain; text/html 
Accept-Language: en-gb
Connection: Keep-Alive 
Host: localhost 
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=liang&firstName=jianfeng

HTTP Method 包括 {GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE}
URI 统一资源标识符,一般为相对路径( 项目跟路径)。

Content-Length 内容的长度
消息实体和请求头之间有一个CRLF(回车/换行),告诉HTTP服务器哪里是消息实体的开始。

HTTP响应:
 

 Protocol—Status code—Description
 Response headers
 Entity body
e.g.

HTTP/1.1 200 OK 
Server: Microsoft-IIS/4.0 
Date: Mon, 5 Jan 2004 13:13:33 GMT 
Content-Type: text/html 
Last-Modified: Mon, 5 Jan 2004 13:13:12 GMT 
Content-Length: 112 <html> 
<head> <title>HTTP Response Example</title> </head>
<body> 
Welcome to Brainy Software 
</body> 
</html>

1.2 Socket类(客户端)

//通过new一个socket出来,与特点IP特点端口的服务器建立TCP连接,相当于一个通道。
Socket socket = new Socket("127.0.0.1", 8080);
OutputStream os = socket.getOutputStream(); 
boolean autoflush = true;
//通道有了,就可以进行通信了。通过sockket的输出流new一个PrintWriter出来就可以向通道中输入消息了。
PrintWriter out = new PrintWriter(socket.getOutputStream(), autoflush);
//通过socket的输入流new一个BufferedReader出来读取输入流中的消息。
BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//向通道输入请求消息,传递给服务器。
out.println("GET /index.jsp HTTP/1.1");
out.println("Host: localhost:8080");
out.println("Connection: Close");
out.println();
//从通道中读取服务器响应消息
boolean 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);
} 
//在控制台打印服务器响应消息
System.out.println(sb.toString()); 
socket.close();

1.3 SocketServer类(服务端)

//建立一个server监听本机的8080端口
ServerSocket server = new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));
//等待请求的到来。如果请求来了,就返回(生成)一个handleServer来出来客户端的请求。并返回响应。
Socket handleServer = server.accept();
//后续的处理与1.2相同
...


 

1.4 举个栗子
HttpServer

import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.File;
/**
* 静态Http服务器,动态的在下一章讲解。
**/
public class HttpServer {

	public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
	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);
		}
		while (true) {
			Socket socket = null;
			InputStream input = null;
			OutputStream output = null;
			try {
				socket = serverSocket.accept();
				input = socket.getInputStream();
				output = socket.getOutputStream();
				Request request = new Request(input);
                                //解析并处理请求
				request.parse();
				//生成响应
				Response response = new Response(output);
				response.setRequest(request);
				response.sendStaticResource();
                                //关闭通道
                                socket.close();
			} catch (Exception e) {
				e.printStackTrace();
				continue;
			}
		}
	}
}

Request.java

import java.io.InputStream;
import java.io.IOException;
/**
*请求对象,封装了输入流和URI
**/
public class Request {
	private InputStream input;
	private String uri;

	public Request(InputStream input) {
		this.input = input;
	}
	public void parse() {
		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]);
		}
		System.out.print(request.toString());
		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.java

import java.io.OutputStream;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.File;
/**
*响应对象,封装了请求对象和输出流
**/
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;
	}
        //把静态资源响应给客户端,如果没有返回404 File Not Found
	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 {
				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) {
	            e.printStackTrace();
		} finally {
		    if (fis != null)
		        fis.close();
		}
	}
}

浏览器输入http://localhost:8080/staticResource 试试看吧。

转载于:https://my.oschina.net/itjava/blog/102101

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值