先简单说下几个概念,根据自己的理解,不正确请见谅。
首先要知道什么是web服务器,简单说web服务器就是可以使用HTTP传输协议与客户端进行通信的服务器。最初的web服务器只能用来处理静态页面,而tomcat服务器更加强大,不仅可以处理静态页面,还可以运行java类文件,动态创建页面并返回给浏览器,之所以说tomcat是个容器,就是可以运行servle类的容器,同时可以处理http请求,并返回相应内容。
http协议是应用层协议,底层使用tcp建立可靠传输连接。所谓协议就是规定了传输内容的规范或格式。先看一个浏览器的http请求:
1 POST /inner/index.html HTTP/1.1 2 Host: localhost:8080 3 Connection: keep-alive 4 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 5 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0 6 Accept-Encoding: gzip,deflate,sdch 7 Accept-Language: zh-CN,zh;q=0.8 8 9 name=ligen&age=21
http请求包括三部分:
1-7行可以归为请求头部分,然后8是空行用以区分实体部分,9行是请求实体内容
- (代码1)请求方法--uri--协议/版本
- (代码2-7)请求头
- (代码9)实体
第一行POST /inner/index.html HTTP/1.1,POST就是请求方法(还有get等请参考其它),然后是空格;/inner/index.html是请求的资源,一般是相对于根路径的,所以总是以“/”开头;最后是协议和版本。
http的响应格式与请求类似:
1 HTTP/1.1 200 OK 2 server:tomcat 3 Content-Type:text/html 4 Content-Length:100 5 6 <html> 7 ...... 8 </html>
第一行指定了协议和版本,接着是状态码200,服务器一切运行正常,与请求类似,响应实体部分与信息头部分通过一个空行分隔。
现在开始着手建立一个简单的web服务器,需要大家有socket基础(了解即可),服务器的基本功能就是基于客户端的请求,建立请求对象request,然后处理相应逻辑找到资源,并封装成response对象通过http将数据传回客户端。因为需要建立三个类:
- HttpServer 使用socket负责建立服务器,等待客户端连接,建立连接后,根据请求信息初始化Request、Response
- Request 获取socket的InputStream,封装了客户端的请求信息
- Response 对应Request的返回信息,获取socket的OutputStream处理返回数据
(一)HttpServer类
HttpServer主要建立本地8080端口服务器,等待连接请求,建立请求后使用socket的InputStream和OutputStream分别初始化Request和Response对象。
1 public class HttpServer { 2 pupublic void await() { 3 ServerSocket serverSocket = null; 4 int port = 8080; 5 try { 6 serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); 7 } catch (IOException e) { 8 e.printStackTrace(); 9 System.exit(1); 10 } 11 while (true){ 12 Socket socket = null; 13 InputStream inputStream = null; 14 OutputStream outputStream = null; 15 try { 16 socket = serverSocket.accept(); 17 inputStream = socket.getInputStream(); 18 outputStream = socket.getOutputStream(); 19 Request request = new Request(inputStream);//使用连接的inputStream初始化Request 20 request.Parse();//Parse用于解析原始HTTP请求数据 21 Response response = new Response(outputStream); 22 response.setRequest(request); 23 response.sendStaticResource(); 24 socket.close(); 25 } catch (IOException e) { 26 e.printStackTrace(); 27 } 28 } 29 } 30 }
(二)Request类
1 public class Request{ 2 3 private String uri; 4 private InputStream in; 5 6 public Request(InputStream in){ 7 this.in = in; 8 } 9 //根据请求头信息获取uri,如GET /index.html HTTP/1.1 ,可以返回/index.html 10 public String parseUri(String request){ 11 int index1,index2; 12 index1 = request.indexOf(" "); 13 if (index1 != -1){ 14 index2 = request.indexOf(" ", index1+ 1); 15 if (index1 < index2) 16 return request.substring(index1 + 1, index2); 17 } 18 return null; 19 } 20 //根据socket的InputStream读取整个字节流,存储在字节数组中,然后使用内存中的字节数组构建StringBUffer对象 21 public void Parse(){ 22 StringBuffer request = new StringBuffer(2048); 23 byte[] bs = new byte[2048]; 24 int i; 25 try { 26 i = in.read(bs); 27 } catch (IOException e) { 28 e.printStackTrace(); 29 i = -1; 30 } 31 32 for(int j=0; j<i; j++){ 33 request.append((char)bs[j]); 34 } 35 System.out.println(request.toString()); 36 uri = parseUri(request.toString()); 37 } 38 39 public String getUri() { 40 return uri; 41 } 42 }
(三)Response类
Response使用socket返回的OutputStream构建对象,setRequest()方法使用初始化后的Request对象出给Response,sendStaticResource()用于发送静态资源,如html文件。
1 public class Response implements ServletResponse{ 2 3 private static final int BUFFER_SIZE = 1024; 4 private Request request; 5 private OutputStream out; 6 private PrintWriter writer; 7 8 public Response(OutputStream out) { 9 this.out = out; 10 } 11 12 public void setRequest(Request request) { 13 this.request = request; 14 } 15 16 public void sendStaticResource() throws IOException{ 17 byte[] buffer = new byte[BUFFER_SIZE]; 18 FileInputStream fis = null; 19 File file = new File(Constant.WEB_ROOT, request.getUri()); 20 try { 21 fis = new FileInputStream(file); 22 int ch = fis.read(buffer, 0, BUFFER_SIZE); 23 while (ch != -1){ 24 out.write(buffer, 0, BUFFER_SIZE); 25 ch = fis.read(buffer, 0, BUFFER_SIZE); 26 } 27 } catch (FileNotFoundException e) {//当文件不存在时,返回错误信息 28 String html = "<h1>file not found</h1>"; 29 String errorMsg = "HTTP/1.1 404 file not found " + 30 "Content-Type: text/html " + 31 "Content-Length: " + html.getBytes().length + " " + 32 " " + 33 html; 34 out.write(errorMsg.getBytes()); 35 } 36 finally { 37 if(fis != null){ 38 fis.close(); 39 } 40 } 41 } 42 }
(四)创建MyServer类,启动服务器
1 public class MyServer { 2 public static void main(String[] args) { 3 HttpServer server = new HttpServer(); 4 server.await(); 5 } 6 }