使用socket模拟tomcat实现静态资源处理

太过爱你忘了你带给我的痛 2022-05-11 04:46 109阅读 0赞

步骤:

1.服务端使用ServerSocket,监听指定的端口。
2.调用ServerSocket的accept方法接收客户端连接,得到Socket对象。
3.根据Socket对象的getInputStream()方法得到输入流,从而拿到浏览器发送的http请求的基本信息。

  1. GET /htmlfiles/test2.jsp HTTP/1.1
  2. Host: localhost:9191
  3. Connection: keep-alive
  4. Upgrade-Insecure-Requests: 1
  5. User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36
  6. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
  7. DNT: 1
  8. Accept-Encoding: gzip, deflate, br
  9. Accept-Language: zh-CN,zh;q=0.9
  10. Cookie: Hm_lvt_9bd56a6d0766b887592ee921aa94763f=1500436957; __atuvc=47%7C35; _ga=GA1.1.2016651800.1504071340; Hm_lvt_4e003ba2028a4a83d95714c602ee7df5=1507970222; Hm_lvt_47acec2d282c3986f1b600abdc11c7ab=1520665960,1521097911,1521252255,1521540649

4.解析http请求,提取要访问的资源文件的位置,使用Socket的getOutputStream拿到输出流,将文件的内容写到输出流。
5.资源请求完毕,关闭相关的流和Socket。

代码

  1. public class Server { public static void main(String[] args) { ServerSocket serverSocket = null; Socket socket = null; try { serverSocket = new ServerSocket(9191); System.out.println("Server已在端口9191启动!"); while (true) { socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); Request request = new Request(inputStream); OutputStream outputStream = socket.getOutputStream(); Response response = new Response(outputStream, request); response.response(); outputStream.close(); inputStream.close(); socket.close(); } } catch (IOException e) { e.printStackTrace(); } finally { try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
  2. public class Request { private String uri; public Request(InputStream in) { try { String content = IOUtils.getRequestContent(in); if (null == content || "".equals(content)) { System.out.println("Bad request."); return; } System.out.println("客户端请求:\n" + content); parseUri(content); } catch (IOException e) { e.printStackTrace(); } } private void parseUri(String content) { this.uri = content.substring(content.indexOf("/"),content.indexOf("HTTP/")-1); } public String getUri() { return uri; } public void setUri(String uri) { this.uri = uri; } }
  3. public class Response { private Request request; private OutputStream os; public Response(OutputStream os, Request request) { this.os = os; this.request = request; } public void response() { String uri = request.getUri(); if (null != uri && !"".equals(uri)) { if (isResource()) { String path = Http_Server.WEB_ROOT + uri.substring(1); if (IOUtils.isFileExist(path)) { IOUtils.writeFile(os, path); } else { String errorMessage = buildResponse("File Not Found","404",""); IOUtils.write(os, errorMessage.getBytes()); } } else { String errorMessage = buildResponse("动态请求暂不支持","200","OK"); IOUtils.write(os, errorMessage.getBytes()); } } } private String buildResponse(String content, String statusCode, String statusMsg) { String html = buildHTML(content); int chineseCount = StringUtils.getChineseCharCount(html); StringBuffer buffer = new StringBuffer(); buffer.append("HTTP/1.1 ") .append(statusCode).append(" ") .append(statusMsg).append("\r\n") .append("Content-Type: text/html\r\n") // .append("Content-Length: ") // .append(html.length()+2*chineseCount) // 1个中文字符占3个字节 .append("\r\n\r\n") .append(html); return buffer.toString(); } private String buildHTML(String content) { StringBuffer html = new StringBuffer(); html.append("<html>\n"); html.append("<head>\n"); html.append("<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n"); html.append("</head>\n"); html.append("<body>\n"); html.append("<h1>").append(content).append("</h1>\n"); html.append("</body>\n"); html.append("</html>"); return html.toString(); } private boolean isResource() { String[] suffixs = { "html", "js", "css", "jpg", "jpeg", "gif", "bmp"}; for (String suf : suffixs) { if (request.getUri().endsWith("." + suf)) { return true; } } return false; } }
  4. public class IOUtils { public static String getRequestContent(InputStream inputStream) throws IOException { byte[] data = new byte[2048]; int len = inputStream.read(data); if (len > 0) { return new String(data,0,len); } return null; } public static boolean isFileExist(String path) { File file = new File(path); return file.exists(); } public static byte[] getFileContent(String path) { try { File file = new File(path); if (file.exists()) { byte[] data = new byte[(int) file.length()]; FileInputStream fis = new FileInputStream(file); fis.read(data); return data; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } public static void write(OutputStream os,byte[] data) { try { os.write(data); os.flush(); } catch (IOException e) { e.printStackTrace(); } } public static void writeFile(OutputStream os,String path) { FileInputStream fis = null; try { int BUFFER_SIZE = 1024; fis = new FileInputStream(path); byte[] data = new byte[BUFFER_SIZE]; int len = fis.read(data,0,BUFFER_SIZE); boolean isFirst = true; while (len != -1) { if (isFirst) { os.write("HTTP/1.0 200 OK\r\n".getBytes()); os.write("\r\n".getBytes());;// 根据 HTTP 协议, 空行将结束头信息 isFirst = false; } os.write(data,0,len); len = fis.read(data,0,BUFFER_SIZE); os.flush(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
  5. public class Http_Server { public final static String WEB_ROOT = Http_Server.class.getResource("/").getPath(); }

测试HTML

  1. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>测试页面</title> <link href="/htmlfiles/css/test.css" rel="stylesheet"> </head> <body> <h1>这是测试页面。<br></h1> <a href="http://localhost:9191/htmlfiles/images/1.jpg">点击打开图片</a> </body> </html>

资源文件放在src目录下。如图:
41857555.jpg

测试

1.动态请求测试
4136960.jpg

2.不存在的静态文件
12083022.jpg

3.存在的静态文件
97192850.jpg

4.图片等二进制文件测试
37310765.jpg

注意

1.你得通过响应头告诉浏览器请求的状态码和资源类型,否则浏览器会告诉你这是无效的http响应。

  1. os.write("HTTP/1.0 200 OK\r\n".getBytes()); os.write("\r\n".getBytes());;// 根据 HTTP 协议, 空行将结束头信息

42783805.jpg

2.如果指定了Content-Length,需要注意中文1个字符占用3个字节,否则会导致浏览器显示不全。

  1. buffer.append("Content-Length: ") buffer.append(html.length()+2*chineseCount) // 1个中文字符占3个字节

发表评论

表情:
评论列表 (有 0 条评论,109人围观)

还没有评论,来说两句吧...

相关阅读