java實現簡單web服務器(分析+源代碼)


在日常的開發中,我們用過很多開源的web服務器,例如tomcat、apache等等。現在我們自己實現一個簡單的web服務器,基本的功能就是用戶點擊要訪問的資源,服務器將資源發送到客戶端的瀏覽器。為了簡化操作,這里不考慮資源不存在等異常情況。web服務基於的是HTTP協議,用戶在瀏覽器的地址欄輸入要訪問的地址,服務器如何得到該地址是個關鍵。先看下一般的HTTP請求和響應報文的一般格式:

HTTP 請求報文

\

 

HTTP 響應報文

\

 

web服務器獲取一個用戶的連接時,會初始化一個線程和用戶通信,代碼如下:

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;


//每有一個連接建立時,服務器分出一個通信的線程
public class CommunicateThread extends Thread{
	//與客戶端通信的套接字
	Socket client;
	
	public CommunicateThread(Socket s) {
		client = s;
	}
	
	//獲取瀏覽器請求資源的路徑
	public String getResourcePath(String s){
		// 一般的HTTP請求報文的第一行是“GET /index.html HTTP/1.1”
		// 我們要獲取的就是中間的"/indext.apsx"
		
		//獲取資源的位置
		String s1 = s.substring(s.indexOf(' ')+1);
		s1 = s1.substring(1,s1.indexOf(' '));
		
		//默認資源為index.html
		if(s1.equals(""))
			s1 = "index.html";
		
		return s1;
	}

	public void sendFile(PrintStream out,File file){
		try{
			DataInputStream in  = new DataInputStream(new FileInputStream(file));
			int len = (int)file.length();
			byte buf[] = new byte[len];
			in.readFully(buf);//讀取文內容到buf數組中
			out.write(buf,0,len);
			out.flush();
			in.close();
		}
		catch(Exception e){
			System.out.println(e.getMessage());
			System.exit(1);
			}
	}
	
	public void run(){
		try{
			//獲取用戶的IP地址和端口號
			String clientIP = client.getInetAddress().toString();
			int clientPort = client.getPort();
			//創建輸出流對象
			PrintStream out = new PrintStream(client.getOutputStream());
			//創建輸入流對象
			DataInputStream in = new DataInputStream(client.getInputStream());
			//讀取瀏覽器提交的請求
			String msg = in.readLine();
			
			
			//獲取文件路徑
			String fileName = getResourcePath(msg);
			System.out.println("The user asked for resource: "+fileName);
			File file = new File(fileName);
			
			if(file.exists()){
				//根據響應報文格式設置
				System.out.println(fileName+" start send");
				
				out.println("HTTP/1.0 200 OK"); 
				out.println("MIME_version:1.0");
				out.println("Content_Type:text/html");
				int len = (int) file.length();
				out.println("Content_Length:"+len);
				out.println("");//報文頭和信息之間要空一行
				
				//發送文件
				sendFile(out,file);
				
				out.flush();
			}	
			client.close();		
		}
		catch(Exception e){
			System.out.println(e.getMessage());
		}		
	}
	


}

服務器主要負責初始化套接字和線程,代碼如下:

import java.net.ServerSocket;
import java.net.Socket;


public class WebServer {


	public static void main(String[] args) {
		int Port = 12345;//端口號,由於這里是測試,所以不要使用常用端口
		//創建兩個套接字
		ServerSocket server = null;
		Socket client = null;
		try{
			server = new ServerSocket(Port);
			//服務器開始監聽
			System.out.println("The WebServer is listening on port "+server.getLocalPort());
			while(true){
				client = server.accept();
				//多線程運行
				new CommunicateThread(client).start();
			}
		}catch(Exception e){
			System.out.println(e.getMessage());
		}
	}

}

 

運行測試:

編寫一個index.html文件

This is the index of my WebServer


放到項目文件的根目錄,然后在瀏覽器地址欄輸入:“localhost:12345/index.html”,就可以看到位於服務器端的html文件了。注意由於服務器是死循環,重啟服務器會發現指定的端口已被綁定,只需要進入任務管理器,關閉" Java(TM) Platfrom SE binary"進程即可。最后結果如下所示: \

 

 

 

 

 

這個服務器程序很簡陋,還有很大的改進余地。大家可以自己嘗試改進。這里可以嘗試一下訪問其他的文件,發現時成功的,說明這服務器很不安全呀。

\

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM