一个简单的Web服务器(Web服务器如何工作)
new Socket("www.baidu.com", 80);一旦创建了Socket的实例,就可以使用该实例发送或接收字节流。要发送字节流,需要调用Socket类的getOutputStream()方法获取一个java.io.OutputStream对象。要发送文本到远程应用程序,通常需要使用返回的OutputStream对象创建一个java.io.PrintWriter对象。若想要从连接的另一端接收字节流,需要调用Socket类的getInputStream()方法,该方法会返回一个java.io.InputStream对象。
?
如果要想实现一个服务器应用程序,需要使用服务器套接字的实现(java.net.ServerSocket)。ServerSocket类和Socket类不同,服务器套接字要等待来自客户端的连接请求,当服务器套接字收到了连接请求以后,他会创建一个Socket实例来处理与客户端的通信。要创建一个服务器套接字,需要指定其主机名和监听的端口号。服务器套接字还有一个重要属性是backlog,表示在服务器在拒绝接受传入的请求之前,传入的连接请求的最大队列长度。ServerSocket类的实例化方式之一如下:
?
new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));创建了ServletSocket实例后,可以使其等待传入的连接请求,该链接请求会通过服务器套接字侦听的端口上绑定地址传入。这些工作可以通过调用ServerSocket类的accept方法完成。只有当接收到连接请求时,该方法才会返回,返回值是一个Socket实例。?
?
Web服务器应用程序实例如下:
1.Request类:
?
package com.demo.tomcat;import java.io.IOException;import java.io.InputStream;public class Request { /** * 从Socket中读取数据的缓冲区大小 */ private static final int SOCKET_BUFFER_SIZE = 1024; /** * 输入流(通过与客户端通信Socket中获取) */ private InputStream input; /** * Http请求的URI */ private String uri; /** * Constructor * @param input 输入流 */ public Request(InputStream input){ this.input = input; } /** * 解析Http请求的原始数据(例如,GET请求index.html的请求行为:"GET /index.html HTTP/1.1) */ public void parse(){ //读取Socket中的数据 StringBuffer sb = new StringBuffer(SOCKET_BUFFER_SIZE); int i; byte[] buf = new byte[SOCKET_BUFFER_SIZE]; try { i = input.read(buf); for(int j = 0; j < i; j++){ sb.append((char) buf[j]); } } catch (IOException e) { e.printStackTrace(); } //解析URI if(sb.length() > 0){ uri = parseURI(sb.toString()); } } /** * 获取请求的URI * @param requestStr * @return */ private String parseURI(String requestStr){ if(requestStr == null || requestStr.length() <= 0){ return null; } int index1,index2; index1 = requestStr.indexOf(' '); if(index1 != -1){ index2 = requestStr.indexOf(' ', index1 + 1); if(index2 > index1){ //截取字符串并返回 return requestStr.substring(index1 + 1, index2); } } return null; } public String getUri() { return uri; }}?
2.Response类:
?
package com.demo.tomcat;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.OutputStream;public class Response { /** * 读取数据缓冲区大小 */ private static final int BUFFER_SIZE = 1024; /** * 请求 */ private Request request; /** * 输出流 */ private OutputStream output; /** * Constructor * @param output 输出流 */ public Response(OutputStream output){ this.output = output; } public void setRequest(Request request){ this.request = request; } /** * 发送一个静态资源到浏览器 * @throws Exception */ public void sendStaticResource() throws Exception { //读取静态资源 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, ch); ch = fis.read(bytes, 0, BUFFER_SIZE); } } else { 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 (IOException e) { e.printStackTrace(); } finally { fis.close(); } }}?
3.HttpServer类:
?
package com.demo.tomcat;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;public class HttpServer { /** * 访问的根路径 */ public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot"; /** * 关闭服务请求命令 */ public static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; /** * 是否关闭服务 */ private Boolean shutdown = false; public static void main(String[] args){ HttpServer httpServer = new HttpServer(); httpServer.await(); } /** * 从accept方法返回的Socket中获取InputStream对象和OutputStream对象 */ public void await(){ //创建ServerSocket对象 ServerSocket serverSocket = null; //监听端口 int port = 8080; try { //实例化ServerSocket对象 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 request = new Request(input); request.parse(); //创建response,发送静态资源给浏览器 Response response = new Response(output); response.setRequest(request); response.sendStaticResource(); //关闭socket socket.close(); //是否关闭服务 shutdown = request.getUri().equals(SHUTDOWN_COMMAND); } catch (Exception e) { e.printStackTrace(); } } }}?
注意:需要在项目所在的路径下添加一个名为"webroot"的文件夹,该文件夹下放置你要访问你的文件(如test.txt),输入相应的URI(如http://lcoalhost:8080/test.txt),即可访问到该资源文件。
参考:深入剖析Tomcat第一章