【原創】自己動手實現靜態資源服務器


引言

本文利用java自帶的socket編程實現了一個簡單的靜態資源服務器,可以響應靜態資源。本文一共有兩個版本的源碼。第一個版本名為Server_v1,該版本實現了一個簡單的socket的服務器,幫助讀者回憶socket編程。第二個版本名為Server_v2,該版本是對第一版的改良,給出了改良思路,做出了必要的封裝,讓其能夠響應css、html、jpg等靜態資源。

正文

版本一

該版本實現一個簡單的socket服務器,針對瀏覽器的請求,能夠返回相應的頁面。
其源碼如下:

package mytomcat_v1;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;

/**
 * 
 * @author zhengrongjun
 * @version v1.0
 */
public class Server_V1 {

	public static void main(String[] args) {
		ServerSocket serverSocket = null;
		Socket client = null;
		try {
			serverSocket = new ServerSocket(9999);
			// 不斷接收客戶連接
			while (true) {
				// 服務器阻塞等待客戶端socket連接過來
				client = serverSocket.accept();
				// 對客戶端里面端請求信息進行處理
				InputStream in = client.getInputStream();
				// 定義一個讀取緩沖池 主要是在inputstram流中讀取字節
				byte[] buff = new byte[1024];
				int len = in.read(buff);
				if (len > 0) {
					String msg = new String(buff, 0, len);
					System.out.println("===="+msg+"======");
					OutputStream out = client.getOutputStream();
					//構建響應信息
					StringBuffer sb = new StringBuffer();
					sb.append("HTTP/1.1 200 OK\n");
					sb.append("Content-Type: text/html; charset=UTF-8\n");
					sb.append("\n");
					String html="<html><head><title>賣燒餅咯</title></head></html><body>小曲經常在"
							   +"<font size='14' color='red'>"
							   +new Date()
							   +"</font>"
							   +"<br/>賣燒餅</body></html>";
					sb.append(html);
					out.write(sb.toString().getBytes());
					out.flush();
					out.close();
				}
			}
		} catch (Exception e) {

		}

	}

}

執行效果如下圖所示,打開chrome瀏覽器,在導航欄輸入

http://localhost:9999/docs/index.html

顯示如下圖所示
image

控制台輸出如下圖所示

====GET /docs/index.html HTTP/1.1
Host: localhost:9999
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
======

版本二

該版本在版本一的基礎上進行優化,使其能夠有效的響應靜態資源

(1)步驟一

先看第一部分代碼優化,如下圖所示
image
紅框的部分,我們可以理解為對請求信息對處理,因此我們模仿Tomcat構造一個HttpRequst來處理這一段邏輯。

另外,我們需要對靜態資源進行響應,因此我們需要獲取輸入內容的靜態資源地址,即以下部分的內容。
image
獲取以上紅框請求地址內容的代碼如下

uri = msg.substring(msg.indexOf("/"),msg.indexOf("HTTP/1.1") - 1);

綜上所述,我們有HttpRequest類如下所示

package mytomcat_v2;

import java.io.IOException;
import java.io.InputStream;

/**
 * 對客戶端進行處理對業務類
 * 
 * @author zhengrongjun
 *
 */
public class HttpRequest {
	private String uri;

	public String getUri() {
		return uri;
	}

	public HttpRequest(InputStream in) throws IOException {
		// 對我們對請求字節流進行解析
		resolverRequest(in);

	}

	private void resolverRequest(InputStream in) throws IOException {
		// TODO Auto-generated method stub
		byte[] buff = new byte[1024];
		int len = in.read(buff);
		if (len > 0) {
			String msg = new String(buff, 0, len);
			System.out.println("====" + msg + "======");
			// 解析出來 uri
			uri = msg.substring(msg.indexOf("/"), msg.indexOf("HTTP/1.1") - 1);
		} else {
			System.out.println("bad Request!");
		}
	}

}

(2)步驟二

接下來是第二部分的代碼優化,如下圖所示
image
以上紅框部分主要是對輸出信息進行響應,我們模仿tomcat構造一個HttpResponse對象封裝該部分邏輯。
另外,我們獲取用戶請求的資源文件路徑,根據該路徑找到相應靜態文件。將該文件寫入文件流,輸出。
因此,我們有HttpResponse對象如下所示

package mytomcat_v2;
/**
 * 封裝http響應信息
 * @author zhengrongjun
 *
 */

import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

public class HttpResponse {

	private OutputStream os = null;

	public HttpResponse(OutputStream os) {
		this.os = os;
	}

	public void writerFile(String path) throws IOException {
		FileInputStream fileInputStream = new FileInputStream(path);
		byte[] buff = new byte[1024];
		int len = 0;
		// 構建響應信息
		StringBuffer sb = new StringBuffer();

		sb.append("HTTP/1.1 200 OK\n");
		sb.append("Content-Type: text/html; charset=UTF-8\n");
		sb.append("\n");
		os.write(sb.toString().getBytes());
		while ((len = fileInputStream.read(buff)) != -1) {
			os.write(buff, 0, len);
		}
		fileInputStream.close();
		os.flush();
		os.close();
	}
}

(3)步驟三

接下來我們構建測試類,構建之前我們先去找一些靜態資源文件。作者直接去apache的官網下把tomcat給下了下來,然后去如下目錄拷貝靜態資源文件

apache-tomcat-8.5.28/webapps/docs

將整個docs 文件夾拷貝至你的項目的根目錄下

apache-tomcat-8.5.28/webapps/ROOT/favicon.ico

將favicon.ico圖片拷貝至你的根目錄下
靜態資源在你的項目中的結構如下圖所示
image

現在上我們的Server_V2的代碼

package mytomcat_v2;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;

/**
 * 
 * @author zhengrongjun
 * @version v2.0
 */
public class Server_V2 {

	public static void main(String[] args) {
		ServerSocket serverSocket = null;
		Socket client = null;
		try {
			serverSocket = new ServerSocket(9999);
			// 不斷接收客戶連接
			while (true) {
				// 服務器阻塞等待客戶端socket連接過來
				client = serverSocket.accept();
				// =========請求類處理=======
				InputStream in = client.getInputStream();
				HttpRequest request = new HttpRequest(in);
				String requestUri = request.getUri();
				// =========響應類處理=======
				OutputStream os = client.getOutputStream();
				HttpResponse response = new HttpResponse(os);
				//請求格式是/html/login.html這種,需要把開頭的/刪除
				response.writerFile(requestUri.substring(1));
				client.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

測試結果如下:
在瀏覽器輸入

http://localhost:9999/docs/ssl-howto.html

效果如下
image
你會驚奇的發現樣式並不能識別,因此我們對響應頭的部分邏輯進行修改

sb.append("HTTP/1.1 200 OK\n");
sb.append("Content-Type: text/html; charset=UTF-8\n");
sb.append("\n");

部分修改為

if(path.endsWith("css")) {
			sb.append("HTTP/1.1 200 OK\n");
			sb.append("Content-Type: text/css; charset=UTF-8\n");
			sb.append("\n");
		}else {
			sb.append("HTTP/1.1 200 OK\n");
			sb.append("Content-Type: text/html; charset=UTF-8\n");
			sb.append("\n");
		}

繼續啟動測試,效果如下
image
已經能夠正常顯示

總結

本文給出了兩個版本的靜態資源的服務器源碼,希望讀者能夠有所收獲。


免責聲明!

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



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