📄 webserver.java~3~
字号:
package fu;import java.io.*;import java.net.*;import java.util.*;/* * Web服务器类 * 实现一个多线程的Web服务器,响应客户机GET、HEAD和POST方法的请求, * 返回响应的HTML、GIF或JPGE文件及相应的404、405、505等出错信息。 */public class WebServer { public static int MAXCONN = 10;// 最大连接数,常量 public static int POST = 8080;// 服务器端口,常量 private ServerSocket serverSocket;// 服务器套接字 private static int numOfConn = 0;// 连接数 private Socket[] connectionSocket;// 连接套接字 /* * 内部类 连接线程 为每个客户端连接建立新线程,实现HTTP请求的解析并进行HTTP响应。 */ private class ConnectionThread extends Thread { int id;// 连接序号 BufferedReader reader;// Input流 DataOutputStream writer;// Output流 String requestLine;// 请求行 String rlMethod;// 请求方法 String rlFileName;// 请求文件名 String rlHttpProtocolVersion;// 请求HTTP协议版本号 File requestFile;// 存放请求文件 byte[] fileInBytes;// 存放请求文件的字节格式 int statusCode;// 响应状态代码 String statusLine;// 响应状态行 String headerLine;// 响应首部行 String hlContentType;// 响应内容类型 String hlContentLength;// 响应内容长度 String spaceLine;// 空行 // /<summary>构造方法 初始化id</summary> // /<parameter="id">连接序号</parameter> public ConnectionThread(int id) { addConn(); this.id = id; } // /<summary>重写Thread.run()方法,运行线程</summary> public void run() { System.out.println("Connection" + id + " Start!"); // 建立输入输出流,读取请求报文的请求行 try { reader = new BufferedReader(new InputStreamReader( connectionSocket[id].getInputStream())); writer = new DataOutputStream(connectionSocket[id] .getOutputStream()); while (requestLine == null) { requestLine = reader.readLine(); } statusCode = parseRequestLine();// 解析请求行得出状态码 statusLine = statusMsg(statusCode);// 根据状态码得出状态行 } catch (IOException e) { System.out.println("That's an I/O Exception!\n" + e.getMessage()); statusCode = 400; statusLine = statusMsg(statusCode); } // 生成首部行和空行 if (statusCode == 200) { hlContentType = getContentType(); hlContentLength = getContentLength(); headerLine = hlContentType + hlContentLength; } spaceLine = "\r\n"; httpResponse();// 向客户终端套接字发送HTTP响应报文 // 断开连接 try { System.out.println("Connection" + id + " Finish!"); if (connectionSocket[id] != null) { connectionSocket[id].close(); connectionSocket[id] = null; delConn(); } } catch (IOException e) { System.out.println("That's an I/O Exception!\n" + e.getMessage()); } } // /<summary>向客户终端套接字写HTTP响应</summary> private void httpResponse() { try { writer.writeBytes(statusLine);// 写状态行 // 非正常状态代码时生成错误页面 if (statusCode != 200) { byte[] errorFile = "<html><head></head><body><p>ERROR!</body></html>" .getBytes(); writer.writeBytes(spaceLine); writer.write(errorFile); } else { // POST方法时写首部行和POST成功页面的实体 if (rlMethod.compareToIgnoreCase("POST") == 0) { byte[] postFile = "<html><head></head><body><p>Post Success!</body></html>" .getBytes(); writer.writeBytes("Content-Type:text/html\r\n"); writer.writeBytes("Content-Length:" + postFile.length + "\r\n"); writer.writeBytes(spaceLine); writer.write(postFile); } // GET方法时写首部行和请求文件的实体 if (rlMethod.compareToIgnoreCase("GET") == 0) { writer.writeBytes(headerLine); writer.writeBytes(spaceLine); writer.write(fileInBytes); } // HEAD方法时仅写状态行 } } catch (IOException e) { System.out.println("That's an I/O Exception!\n" + e.getMessage()); } } // /<summary>获得响应内容类型字符串</summary> // /<return>响应内容类型字符串</return> private String getContentType() { int index = requestLine.lastIndexOf('.'); String type = requestLine.substring(index + 1); if (type.compareToIgnoreCase("html") == 0) { return ("Content_Type:text/html\r\n"); } else if (type.compareToIgnoreCase("gif") == 0) { return ("Content_Type: image/gif\r\n"); } else if (type.compareToIgnoreCase("jpg") == 0) { return ("Content_Type: image/jpge\r\n"); } else { return ("Content_Type: text/text\r\n"); } } // /<summary>获得响应内容长度字符串</summary> // /<return>响应内容长度字符串</return> private String getContentLength() { long length = requestFile.length(); return ("Content-Length: " + length + "\r\n"); } // /<summary>根据状态码生成</summary> // /<parameter="statusCode">响应状态码</return> // /<return>响应内容类型字符串</return> private String statusMsg(int statusCode) { String statusWord; switch (statusCode) { case 200: statusWord = "OK"; break; case 404: statusWord = "Not Found"; break; case 405: statusWord = "Method Not Allowed"; break; case 505: statusWord = "HTTP Version not supported"; break; default: statusWord = "Bad Request"; } return (rlHttpProtocolVersion + " " + statusCode + " " + statusWord + "\r\n"); } // /<summary>解析请求报文的请求行</summary> // /<return>响应内容状态码</return> private int parseRequestLine() { try { StringTokenizer tokenized = new StringTokenizer(requestLine); rlMethod = tokenized.nextToken(); rlFileName = tokenized.nextToken(); rlHttpProtocolVersion = tokenized.nextToken(); if (!checkMethod()) { return (405); } if (!checkFileName()) { return (404); } if (!checkHttpProtocolVersion()) { return (505); } return (200); } catch (NullPointerException e) { System.out.println(e.getMessage()); return (400); } } // /<summary>检查请求方法是否合法</summary> // /<return>布尔值</return> private boolean checkMethod() { if (rlMethod.compareToIgnoreCase("GET") != 0 && rlMethod.compareToIgnoreCase("POST") != 0 && rlMethod.compareToIgnoreCase("HEAD") != 0) { return (false); } else { return (true); } } // /<summary>检查请求文件名是否合法</summary> // /<return>布尔值</return> private boolean checkFileName() { if (rlFileName.startsWith("/")) { rlFileName = rlFileName.substring(1); } try { requestFile = new File(rlFileName); fileInBytes = new byte[(int) requestFile.length()]; FileInputStream fileReader = new FileInputStream(requestFile); fileReader.read(fileInBytes); } catch (FileNotFoundException fnfe) { System.out.println("Can't find File!\n" + fnfe.getMessage()); return (false); } catch (IOException ioe) { System.out.println("That's an I/O Exception!\n" + ioe.getMessage()); return (false); } return (true); } // /<summary>检查请求HTTP协议版本是否合法</summary> // /<return>布尔值</return> private boolean checkHttpProtocolVersion() { if (rlHttpProtocolVersion.compareToIgnoreCase("HTTP/1.0") != 0 && rlHttpProtocolVersion.compareToIgnoreCase("HTTP/1.1") != 0) { return (false); } else { return (true); } } // /<summary>锁定方法增加连接数</summary> private synchronized void addConn() { numOfConn++; } // /<summary>锁定方法减少连接数</summary> private synchronized void delConn() { numOfConn--; } } // /<summary>构造方法 初始化套接字</summary> public WebServer() { try { serverSocket = new ServerSocket(POST, MAXCONN);// 建立服务套接字,绑定端口 } catch (IOException e) { System.out.println("Can't creat server socket!\n" + e.getMessage()); } connectionSocket = new Socket[MAXCONN];// 生成连接套接字 for (int i = 0; i < connectionSocket.length; i++) { connectionSocket[i] = null; } System.out.println("WebServer Start!"); } // /<summary>使监听套接字处于监听状态,监听到连接后新建连接线程并启用</summary> public void listen() { for (int i = 0; i < connectionSocket.length; i++) { // 连接数满时提示连接已满 暂停响应 if (numOfConn >= MAXCONN) { System.out.println("Connection is full!"); return; } else { try { if (connectionSocket[i] == null) { connectionSocket[i] = serverSocket.accept();// 监听 new ConnectionThread(i).start();// 新建线程并启用 } } catch (IOException e) { System.out.println("That's an I/O Exception!\n" + e.getMessage()); } } } } // /<summary>main入口,创建实例并使之处于监听状态</summary> public static void main(String args[]) { WebServer webServer = new WebServer(); System.out.println("WebServer Listening!"); while (true) { webServer.listen(); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -