Tomcat是一个jsp和servlet的容器,缺少了这个容器,web程序就不能得以实现。
学过Java的人都知道socket吧?tomcat其实就是一个ServerSocket服务器,一个普通的HTTP请求的过程是:
三次握手建立连接——浏览器发送请求——服务器响应
我们平时通过浏览器去访问资源的时候,需要在地址栏上输入url地址,其实你访问url地址就是你访问该服务器上的资源。为什么称作访问资源呢?我们称互联网上的各种各样的文件叫做资源,平时我们在建立一个网站的时候,需要建立那些html文件、图片文件等,都是资源,当我们请求资源的时候过程是这样子的:我们从浏览器中输入远程服务器上该资源的位置,也就是URI(统一资源定位符),当tomcat服务器接收到这个HTTP请求之后呢,就会解析报文里面的uri,得到这个Uri之后,服务器就会在webroot相应的目录下找到该资源,并且通过IO流去读取这个文件,然后把这个文件以流的形式返回给浏览器。当然,我们需要指定contentType来确定输出的是什么流,假如是普通的text/html,则返回的也就是基于浏览器解析的数据,让浏览器解析成为我们可以看到的页面。
下面我们来写一个简单的web服务器来说明:
先是一个HttpServer类:
package com.ccw.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 java.net.UnknownHostException;
import com.ccw.request.Request;
import com.ccw.response.Response;
public class HttpServer {
private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";
private boolean isShutdown = false;
private int portNum = 8888;
public void start() {
ServerSocket serverSocket = null;
int port = portNum;
try {
serverSocket = new ServerSocket(port, 1,
InetAddress.getByName("127.0.0.1"));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
while (!isShutdown) {
Socket socket = null;
InputStream is = null;
OutputStream os = null;
try {
//等待请求
System.out.println("=====等待请求======");
socket = serverSocket.accept();
System.out.println("=====建立请求======");
is = socket.getInputStream();
os = socket.getOutputStream();
Request request = new Request(is);
//解析请求
request.parse();
Response response = new Response(os);
response.setRequest(request);
//响应
response.sendResponse();
System.out.println("======返回响应信息=======");
socket.close();
System.out.println("======连接关闭=======");
isShutdown = request.getUri().equals(SHUTDOWN_COMMAND);
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
public static void main(String[] args) {
HttpServer server = new HttpServer();
server.start();
System.out.println("==========启动成功=========");
}
}
接下来分别是Request类和Response类:
Request:
此类有两个方法,parse()方法用来解析请求中的信息,此处使用字符串来存储请求报文数据,parseUri()方法则是在请求报文中解析出Uri来
package com.ccw.request;
import java.io.IOException;
import java.io.InputStream;
public class Request {
//用来读取请求中的数据
private InputStream is;
private String uri;
public Request(InputStream is) {
this.is=is;
}
/**
* 解析请求
*/
public void parse() {
//以字符串的形式存储request报文
StringBuffer request=new StringBuffer(2048);
int i;
byte[] buffer=new byte[2048];
try {
i=is.read(buffer);
} catch (IOException e) {
e.printStackTrace();
i=-1;
}
for(int j=0;j<i;j++){
request.append((char)buffer[j]);
}
System.out.println(request.toString());
uri=parseUri(request.toString());
}
/**
* 解析uri
* @param requestStr
* @return
*/
private String parseUri(String requestStr) {
int index1,index2;
index1=requestStr.indexOf(' ');
if(index1!=-1){
index2=requestStr.indexOf(' ', index1+1);
if(index2>index1){
return requestStr.substring(index1,index2);
}
}
return null;
}
public String getUri() {
return this.uri;
}
}
Response:
此类只有一个方法sendResponse(),用来响应请求,返回数据,根据请求中的uri到webroot目录下寻找资源,如果找到,使用输出流写出该资源文件;否则,使用输出流写出页面找不到的页面。
package com.ccw.response;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import com.ccw.request.Request;
import com.ccw.server.Constants;
public class Response {
//一次读取的长度
private static final int BUFFER_SIZE=1024;
Request request;
//用来写数据返回到页面
OutputStream os;
public Response(OutputStream os) {
this.os=os;
}
public void setRequest(Request request) {
this.request=request;
}
/**
* 响应请求
*/
public void sendResponse() {
byte[] bytes=new byte[BUFFER_SIZE];
FileInputStream fis=null;
try {
//在webroot目录下寻找所请求的资源
File file=new File(Constants.WEB_ROOT, request.getUri().trim());
System.out.println(Constants.WEB_ROOT+request.getUri().trim());
//如果资源存在,则返回数据
if(file.exists()){
fis=new FileInputStream(file);
int ch=fis.read(bytes,0,BUFFER_SIZE);
while(ch!=-1){
os.write(bytes, 0, BUFFER_SIZE);
ch=fis.read(bytes, 0, BUFFER_SIZE);
}
//否则返回404错误
}else{
String errorMsg="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>";
os.write(errorMsg.getBytes());
}
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}finally{
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
下面的是常量类:
package com.ccw.server;
import java.io.File;
public class Constants {
public static final String WEB_ROOT = System.getProperty("user.dir")
+ File.separator + "webroot";;
}
写完了这几个类之后,一个简单的web应用服务器就完成了啦
现在我们需要测试一下,首先在改项目下新建一个webroot文件夹来存放资源文件,然后在webroot目录下建立一个index.html文件,内容自定,然后执行HttpServer文件,在浏览器中输入http://localhost:8888/index.html,然后就可以访问啦。
这只是一个简单的web应用服务器,tomcat涉及到的知识远远不止这些,多用户访问还涉及到多线程编程,性能调优涉及到线程池等等。。