Java多線程 Web服務器簡單實現
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.net.URLDecoder; import java.util.StringTokenizer; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;/**
- 用Java語言實現HTTP服務器,首先啟動一個java.net.ServerSocket在提供服務的端口上監聽連接.向客戶返回文本時,可以用
- PrintWriter,但是如果返回二進制數據,則必須使用OutputStream.write(byte[])方法,返回的應答消息字符串可以使用
- String.getBytes()方法轉換為字節數組返回,或者使用PrintStream的print()方法寫入文本,用
- write(byte[])方法寫入二進制數據.
- 以工程所在目錄為web的根目錄。 在工程的根目錄下放一個大概如下的index.html
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "; <html> <head> <meta
- http-equiv="Content-Type" content="text/html; charset=gbk">
- <title>簡單的測試</title> </head> <body> 你好!這是一個 簡單的web服務器。<br>
- 這是一個圖片!<br>
- <form action="/index.html"> <img alt="" src="images/test.gif"><br>
- 姓名:<input type="text" name="name" /><br>
- 密碼:<input type="password" name="pass"></input><br>
- <input type="submit"/> </form> </body> </html>
- 放入圖片位置: 工程根目錄/images/test.gif <br>
- 打開瀏覽器輸入http://localhost/index.html 可以展示index.html
- @author rommel1 */ public class SimpleHttpServer {
ServerSocket serverSocket;// 服務器Socket ExecutorService pool = Executors.newFixedThreadPool(2);
/**
- 服務器監聽端口, 默認為 80. */ public static int PORT = 80;// 標準HTTP端口
/**
- 開始服務器 Socket 線程. */ public SimpleHttpServer() { try { serverSocket = new ServerSocket(PORT); } catch (Exception e) { System.out.println("無法啟動HTTP服務器:" + e.getMessage()); } if (serverSocket == null) System.exit(1);// 無法開始服務器
// new Thread(this).start(); System.out.println("HTTP服務器正在運行,端口:" + PORT); while (true) { pool.execute(new Process(serverSocket)); } }
/**
- 運行服務器主線程, 監聽客戶端請求并返回響應. */
/ */ /
- 啟動 HTTP 服務器
- @param args */ public static void main(String[] args) { try { if (args.length != 1) { System.out.println("這是一個簡單的web服務器 ,端口是: 80."); } else if (args.length == 1) { PORT = Integer.parseInt(args[0]); } } catch (Exception ex) { System.err.println("服務器初始化錯誤" + ex.getMessage()); }
new SimpleHttpServer(); } }
class Process extends Thread { private ServerSocket serverSocket;// 服務器Socket
Process(ServerSocket serverSocket) { this.serverSocket = serverSocket; }
public void run() { try { Socket client = null;// 客戶Socket client = serverSocket.accept();// 客戶機(這里是 IE 等瀏覽器)已經連接到當前服務器 if (client != null) { System.out.println("連接到服務器的用戶:" + client); try { // 第一階段: 打開輸入流 BufferedReader in = new BufferedReader( new InputStreamReader(client.getInputStream()));
System.out.println("客戶端發送的請求信息: ***"); // 讀取第一行, 請求地址 System.out.println("http協議頭部信息:"); String line = in.readLine(); System.out.println(line); String resource = line.substring(line.indexOf('/'), line.lastIndexOf('/') - 5); // 獲得請求的資源的地址 resource = URLDecoder.decode(resource, "gbk");// 反編碼
String method = new StringTokenizer(line).nextElement() .toString();// 獲取請求方法, GET 或者 POST
// 讀取瀏覽器發送過來的請求參數頭部信息 while ((line = in.readLine()) != null) { System.out.println(line);
if (line.equals("")) break; }
System.out.println("http協議頭部結束 ***"); System.out.println("用戶請求的資源是:" + resource); System.out.println("請求的類型是: " + method);
String params = null;
if (resource.indexOf("?") > -1) { params = resource.substring(resource.indexOf("?") + 1); resource = resource.substring(0, resource.indexOf("?")); }
// 顯示 POST 表單提交的內容, 這個內容位于請求的主體部分 if ("POST".equalsIgnoreCase(method)) { if (params != null) { params += "&" + in.readLine(); } else { params = in.readLine(); } }
System.out.println("打印提交的數據:"); printParams(params);
// 讀取資源并返回給客戶端 fileReaderAndReturn(resource, client); // 關閉客戶端鏈接 client.close(); System.out.println("客戶端返回完成!"); } catch (Exception e) { System.out.println("HTTP服務器錯誤:" + e.getMessage()); } }
} catch (Exception e) { System.out.println("HTTP服務器錯誤:" + e.getMessage()); } }
/**
- 讀取一個文件的內容并返回給瀏覽器端.
- @param fileName
- 文件名
- @param socket
- 客戶端 socket.
- @throws IOException */ void fileReaderAndReturn(String fileName, Socket socket) throws IOException { if ("/".equals(fileName)) {// 設置歡迎頁面,呵呵! fileName = "/index.html"; } fileName = fileName.substring(1);
PrintStream out = new PrintStream(socket.getOutputStream(), true); File fileToSend = new File(fileName);
String fileEx = fileName.substring(fileName.indexOf(".") + 1); String contentType = null; // 設置返回的內容類型 // 此處的類型與tomcat/conf/web.xml中配置的mime-mapping類型是一致的。測試之用,就寫這么幾個。 if ("htmlhtmxml".indexOf(fileEx) > -1) { contentType = "text/html;charset=GBK"; } else if ("jpegjpggifbpmpng".indexOf(fileEx) > -1) { contentType = "application/binary"; }
if (fileToSend.exists() && !fileToSend.isDirectory()) { // http 協議返回頭 out.println("HTTP/1.0 200 OK");// 返回應答消息,并結束應答 out.println("Content-Type:" + contentType); out.println("Content-Length:" + fileToSend.length());// 返回內容字節數 out.println();// 根據 HTTP 協議, 空行將結束頭信息
FileInputStream fis = null; try { fis = new FileInputStream(fileToSend); } catch (FileNotFoundException e) { out.println("<h1>404錯誤!</h1>" + e.getMessage()); } byte data[]; try { data = new byte[fis.available()];
fis.read(data); out.write(data); } catch (IOException e) { out.println("<h1>500錯誤!</h1>" + e.getMessage()); e.printStackTrace(); } finally { out.close(); try { fis.close(); } catch (IOException e) {
e.printStackTrace(); } } } else { out.println("<h1>404錯誤!</h1>" + "文件沒有找到"); out.close();
}
}
void printParams(String params) throws IOException { if (params == null) { return; } String[] maps = params.split("&"); for (String temp : maps) { String[] map = temp.split("="); System.out.println(map[0] + "==" + map[1]); } }
} </pre>