学习Tomcat源码(1) http协议 web服务器原理

HTTP是一种协议,允许web服务器和浏览器通过互联网进行发送和接受数据,它是一种请求和响应协议,客户端请求一个文件而服务器响应请求。

HTTP请求
一个HTTP请求包括三个组成部分:
 方法—统一资源标识符(URI)—协议/版本
 请求的头部
 主体内容
下面是一个HTTP请求的例子:

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=Franks&firstName=Michael

方法—统一资源标识符(URI)—协议/版本出现在请求的第一行。

POST /examples/default.jsp HTTP/1.1

这里POST是请求方法,/examples/default.jsp是URI,而HTTP/1.1是协议/版本部分。 每个HTTP请求可以使用HTTP标准里边提到的多种方法之一。HTTP 1.1支持7种类型的请求:GET, POST, HEAD, OPTIONS, PUT, DELETE和TRACE。GET和POST在互联网应用里边最普遍使用的。 URI完全指明了一个互联网资源。URI通常是相对服务器的根目录解释的,因此,始终一斜线/开头。统一资源定位器(URL)其实是一种URI。

请求的头部包含了关于客户端环境和请求的主体内容的有用信息。例如它可能包括浏览器设置的语言,主体内容的长度等等。每个头部通过一个回车换行符(CRLF)来分隔的。 对于HTTP请求格式来说,头部和主体内容之间有一个回车换行符(CRLF)是相当重要的。CRLF告诉HTTP服务器主体内容是在什么地方开始的。在一些互联网编程书籍中,CRLF还被认为是HTTP请求的第四部分。 在前面一个HTTP请求中,主体内容只不过是下面一行:

lastName=Franks&firstName=Michael 实体内容在一个典型的HTTP请求中可以很容易的变得更长。

HTTP响应
类似于HTTP请求,一个HTTP响应也包括三个组成部分:
 方法—统一资源标识符(URI)—协议/版本
 响应的头部
 主体内容
下面是一个HTTP响应的例子:

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>

响应头部的第一行类似于请求头部的第一行。第一行告诉你该协议使用HTTP 1.1,请求成功(200=成功),表示一切都运行良好。 响应头部和请求头部类似,也包括很多有用的信息。响应的主体内容是响应本身的HTML内容。头部和主体内容通过CRLF分隔开来。

实例

首先定义三个类:

 HttpServer
 Request
 Response

应用程序的入口点(静态main方法)可以在HttpServer类里边找到。main方法创建了一个HttpServer的实例并调用了它的await方法。await方法,顾名思义就是在一个指定的端口上等待HTTP请求,处理它们并发送响应返回客户端。它一直等待直至接收到shutdown命令。 应用程序不能做什么,除了发送静态资源,例如放在一个特定目录的HTML文件和图像文件。它也在控制台上显示传入的HTTP请求的字节流。不过,它不给浏览器发送任何的头部例如日期或者cookies。

HttpServer代码如下:

package ex01;
import java.net.*;
import java.io.*;
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";
	//shutdowm command
	private static final String SHUTDOWN_COMMAND="/SHUTDOWN";
	// the shutdown command received
	private boolean shutdown=false;
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HttpServer server=new HttpServer();
		server.await();
	}
	
	public void await(){
		ServerSocket serverSocket=null;
		int port=8081;
		try{
			serverSocket=new ServerSocket(port,1,
					InetAddress.getByName("127.0.0.1"));
			
		}catch(IOException e){
			e.printStackTrace();
			System.exit(1);
		}
		while(!shutdown){
			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();
				shutdown=request.getUri().equals(SHUTDOWN_COMMAND);
				
			}catch(Exception e){
				e.printStackTrace();
				continue;
			}
		}
	}

}


request代码:

package ex01;
import java.io.*;
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]);
		}
		System.out.println(HttpServer.WEB_ROOT);
		this.uri=parseUri(request.toString());
		System.out.println(uri);
	}
	
	public String parseUri(String requestString){
		int index1=0,index2=0;
		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代码:


package ex01;
import java.io.*;
/* *
 * 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, BUFFER_SIZE);
					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){
			e.printStackTrace();
			System.out.println("错误发生在这里"+e.toString() );
		}finally{
			if(fis!=null){
				fis.close();
			}
		}
	}
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值