标签:http java 使用 os 数据 io 2014 art
tomcat启动的最后时刻,会启用一个ServerSocket,来接收所有的Web请求(其中大多数是浏览器的请求),处理请求后输出响应到客户端,比如浏览器。
Tomcat支持http应用层协议,浏览器向tomcat请求资源大多数用的也是http协议。
本文的重点是,通过简单的类来模拟tomcat服务,其中特别需要注意的是示例代码的开发需要遵循HTTP协议。
TestSocket类用来模拟tomcat服务,运行他的main方法,可以启动服务。TestSocket的关键方法和属性说明如下:
| 名称 |
类型 |
说明 |
| serverSocket |
属性 |
用于监听所有的socket连接,这里用于监听来自浏览器的socket连接。 |
| 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();
}
}
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();
}
}
}
}
了解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的问题。
最后欢迎大家一起探讨这其中存在的问题。
tomcat学习之HTTP应用,布布扣,bubuko.com
标签:http java 使用 os 数据 io 2014 art
原文地址:http://my.oschina.net/psuyun/blog/294722