tomcat学习之HTTP应用

1 概述

tomcat启动的最后时刻,会启用一个ServerSocket,来接收全部的Web请求(其中大多数是浏览器的请求),处理请求后输出响应到客户端,好比浏览器。 java

Tomcat支持http应用层协议,浏览器向tomcat请求资源大多数用的也是http协议。 浏览器

本文的重点是,经过简单的类来模拟tomcat服务,其中特别须要注意的是示例代码的开发须要遵循HTTP协议。 tomcat

2 代码展现

2.1 TestSocket服务类

TestSocket类用来模拟tomcat服务,运行他的main方法,能够启动服务。TestSocket的关键方法和属性说明以下: 服务器

名称 异步

类型 socket

说明 ide

serverSocket this

属性 spa

用于监听全部的socket链接,这里用于监听来自浏览器的socket链接。 .net

poolExecuter

属性

提供接受者,接受者这里用于接收socket后,返回响应报文。这种设计思路可以让tomcat服务器不阻塞的接收socket请求

requestCount

属性

用于统计请求的次数。

initPoolExecuter

方法

初始化线程池

startServer

方法

启动服务

     

完整的代码以下:

package socket;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import thread.Acceptor;

public class TestSocket {

	public TestSocket(){
		initPoolExecuter();
		startServer();
	}
	
	private ServerSocket serverSocket;
	
	private ThreadPoolExecutor poolExecuter;
	
	private int requestCount = 0;
	
	public void initPoolExecuter(){
		LinkedBlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
		poolExecuter = new ThreadPoolExecutor(2, 2, 60, TimeUnit.MINUTES, workQueue);
	}
	
	public void startServer(){
		try {
			System.out.println("tomcat服务已经启动");
			serverSocket = new ServerSocket(8080, 2);
			while(true){
				Socket socket = serverSocket.accept();
				
				handlerSocket(socket);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 处理请求
	 * @param socket
	 * @throws IOException
	 */
	public void handlerSocket(Socket socket) throws IOException{
		requestCount++;
		System.err.println("第"+requestCount+"次来自客户端的请求");
		poolExecuter.submit(new Acceptor(socket));
	}
	
	public static void main(String[] args) {
		new TestSocket();
	}
}

2.2 Acceptor接收类

Acceptor是Runnable的实现类,即线程,在TestSocket中经过poolExecuter提供出来,这种设计的思路能够实现tomcat接收请求和处理请求的异步。

Acceptor类须要作的事情,从socket的InputStream中读取数据,作完数据处理后,经过socket的OutputStream输出响应结果。本例子中也只是简单的输出了InputStream中全部的数据信息,而后定义了一个响应报文返回给浏览器。

关键须要阐述的两点,tomcat的socket请求来源于浏览器,tomcat中inputStream中拿到的是浏览器发起请求时的请求报文,该报文遵循HTTP协议规范;在tomcat处理完请求,输出响应数据的时候,tomcat也应该按照HTTP协议的规范,生成响应报文,输出到浏览器,这样浏览器才能正确的解析tomcat返回的处理结果。

完整的代码以下:

package thread;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Acceptor implements Runnable {

	private Socket socket;
	
	public Acceptor(Socket socket){
		this.socket = socket;
	}
	
	@Override
	public void run() {
		OutputStream outStream = null;
		try{
			InputStream inStream = socket.getInputStream();
			
			byte[] read = new byte[inStream.available()];
			inStream.read(read);
			
			System.err.println("打印请求报文:");
			System.out.write(read);
			
			String response = "HTTP/1.1 200 OK\n"
					+ "Content-type:text/plain\n"
					+ "Content-length:12\n"
					+"\n"
					+ "hello world!";
			
			System.err.println("打印返回报文:");
			System.out.println(response);
			outStream = socket.getOutputStream();
			
			outStream.write(response.getBytes());
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				outStream.flush();
				outStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
	}

}

3 待想通的问题

了解HTTP协议,以及浏览器遵循HTTP协议向tomcat发起socket请求后,模拟tomcat的服务及请求过程就是件比较简单的事情。若是tomcat在处理完请求后,不按照HTTP协议的规范生成响应报文,这样不一样浏览器对tomcat的输出的渲染是不同的,总的来讲,都是会存在问题的。

关于浏览器访问tomcat服务的时候,不一样浏览器请求ServerSocket的次数是不同的,其中的缘由,我想多是各种型浏览器的实现不太同样。具体的现象是使用360极速浏览器访问tomcat服务,一次请求过程,能够监控到最多3次socket链接,有时候是两次;可是使用IE8访问tomcat服务,一次请求过程,只有一次socket链接。虽然发起请求时,不通浏览器发起socket的次数不同,可是只要遵循HTTP协议输出响应报文,最终的效果都是同样的,在浏览器上只显示响应报文的实体部份内容。

第二个问题是关于thread代码执行顺序的问题。个人代码以下:

System.err.println("打印请求报文:");

System.out.write(read);

System.err.println("打印返回报文:");

System.out.println(response);

上述代码的输出结果常常是:

这样代码和输出是对应不上的,这地方我猜想是Thread的问题。

最后欢迎你们一块儿探讨这其中存在的问题。

相关文章
相关标签/搜索