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"
 * "http://www.w3.org/TR/html4/loose.dtd"> <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]);
}
}


} 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章