1. 程式人生 > >Java實現簡單的站點請求模式

Java實現簡單的站點請求模式

Java實現簡單的站點請求模式

概述

本次實現的是瀏覽器(客戶端)訪問特定站點ip和埠,自定義socket來監聽該請求,解析請求內容以及做出響應。

以下是在com.yzz.tomcat下的三個類
- HttpServer:socket監聽ip,接收客戶端請求。
- HttpRequest:解析客戶端HTTP請求。
- HttpResponse:對客戶端請求做出響應。

HttpServer

await()方法這裡麵包括了socket的建立,連線的監聽,對HTTP請求的解析以及對請求做出響應。

package com.yzz.tomcat.server;

import
java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import com.yzz.tomcat.request.HttpRequest; import com.yzz.tomcat.response.HttpResponse; public class HttpServer { //獲取專案中的檔案 public static
final String WEEB_ROOT = System.getProperty("user.dir")+File.separator+"webroot"; //關閉監聽字元 public static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; //是否監聽關閉 private boolean shutdown = false; /** * 這裡是對特定ip埠進行監聽 * 監聽8080埠 * ip是本地ip */ public void await(){ ServerSocket serverSocket = null
; int port = 8080; try{ serverSocket = new ServerSocket(port,100,InetAddress.getByName("127.0.0.1")); }catch (Exception e) { e.printStackTrace(); System.out.println("serverSocket獲取失敗"); } while(!shutdown){ Socket socket = null; InputStream input = null; OutputStream output = null; try { //The method blocks until a connection is made. socket = serverSocket.accept(); //設定讀取超時時間 socket.setSoTimeout(3000); //獲取出入輸出流 input = socket.getInputStream(); output = socket.getOutputStream(); //建立HttpRequest物件,呼叫parse()方法來解析HTTP請求 HttpRequest request = new HttpRequest(input); request.parse(); //新建HttpResponse物件,對請求進行對應的處理 HttpResponse response = new HttpResponse(output); response.setHttpRequest(request); //向客戶端傳送靜態的資源 response.sendStaticResource(); //在做出響應後,關閉socket連線 socket.close(); //判斷是否是客戶端發來的關閉監聽指令 shutdown = request.getUri().equals(SHUTDOWN_COMMAND); } catch (Exception e) { e.printStackTrace(); continue; } } } }

HttpRequest

這裡需要特別注意的是,在讀取HTTP請求內容的時候與普通的檔案流有所區別,詳情見註釋

package com.yzz.tomcat.request;

import java.io.InputStream;

public class HttpRequest {

    //socket連線的輸入流
    private InputStream inputStream;
    //統一欄位識別符號
    private String uri;
    //HTTP請求內容
    private StringBuffer request;

    public HttpRequest(InputStream inputStream) {
        this.inputStream = inputStream;
    }
    /**
     * 解析HTTP請求
     * 這裡只是對HTTP協議的第一行的URI做了解析,其他內容這裡並沒有做關注
     * 注意:socket的輸入流的檔案流有區別,檔案流可以迴圈讀取,直到出現某一個標誌位,結束
     *          但是socket的輸入流不滿足這種情況,當讀取完成之後,流會處於等待狀態,並沒有結束,因為是端對端的傳輸,不知道
     *         客戶端時候是傳輸完畢了,所以會處於無限期的等待狀態中。
     * 解決:目前的解決辦法是一次性讀完所有的HTTP請求資源,這裡是2048byte
     */
    public void parse() {
        request = new StringBuffer();
        try {
            if (null == inputStream)
                return;
            byte buf[] = new byte[2048];
            int len = 0;
            len = inputStream.read(buf);
            if(len != -1)
                request.append(new String(buf,0,len));
            System.out.println(request.toString());
            parseUri();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 解析URI
     */
    private void parseUri() {
        int index1;
        int index2;
        index1 = request.indexOf(" ");
        index2 = request.indexOf(" ", index1 + 1);
        if (index2 > index1)
            uri = request.substring(index1 + 1, index2);
        System.out.println("uri:"+uri);
    }

    public String getUri() {
        return uri;
    }

}

HttpResponse

響應做的比較簡單,請求的資源存在就將資源通過輸出流返回給客戶端,否則返回404頁面


package com.yzz.tomcat.response;

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

import com.yzz.tomcat.request.HttpRequest;
import com.yzz.tomcat.server.HttpServer;

public class HttpResponse {
    //socket連線輸出流
    private OutputStream out;
    //HTTP請求物件
    private HttpRequest httpRequest;
    //緩衝byte陣列長度
    public static final int BUFFER_SIZE = 1024;
    //404 URI
    public static final String PAGE_404 = "/404.html";
    public HttpResponse(OutputStream out) {
        this.out = out;
    }

    public void setHttpRequest(HttpRequest httpRequest) {
        this.httpRequest = httpRequest;
    }
    /**
     * 向客戶端響應靜態資源
     */
    public void sendStaticResource() {
        File file = new File(HttpServer.WEEB_ROOT, httpRequest.getUri());
        FileInputStream fis = null;
        if(!file.exists()){
            file = new File(HttpServer.WEEB_ROOT+PAGE_404);
        }
        try {
                fis = new FileInputStream(file);
                byte[] buf = new byte[BUFFER_SIZE];
                int len = 0;
                while ((len = fis.read(buf)) != -1) {
                    out.write(buf, 0, len);

            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(null != fis){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

演示

工程結構
這裡寫圖片描述
其中靜態資源存放在tomcat的webroot目錄下
結果
1.正常請求
這裡寫圖片描述
2.錯誤請求
這裡寫圖片描述
3.結束監聽
這裡寫圖片描述

總結

本次只是簡單的對socket進行了利用,對於響應還沒有加上HTTP規範,下片我們繼續來優化。