HTTP網絡協議與手寫Web服務容器

Http協議html

1.深刻概念
  Http:HyperText Transfer Protocol,便是超文本傳輸協議。java

2.淺出概念(使用瀏覽器訪問服務器端網頁時須要遵循的一系列規則)
  Http:將各類不一樣瀏覽器或各類自研客戶端的文字信息組織在一塊兒的網狀文本數據。
  協議:多方一塊兒約定的一系列規則,而後你們活動必須遵循這些規則,就像法律你們必須遵循才能享受法律提供的保護。

  舉個栗子:咱們平時去飯店吃飯一般會有如下幾個步驟:
  1.坐到合適的座位上。
  2.服務員拿出菜單點餐。
  3.服務員按照點餐菜單下單。
  4.服務員上菜。
  5.吃飯。
  6.買單走人。

  這是咱們吃飯一般的步驟,若是我把這些步驟和飯店約定好,每次到了這家飯店就按這個流程來執行,
  我要遵循這個步驟來吃飯,一樣飯店也要遵循這個步驟提供飯菜,那麼我和店家的協議就達成了,從而能夠愉快的吃飯。

  例如:我天天中午都會去這家飯店吃一份「蛋炒飯」,並按照上邊的步驟,且與商家協定好,商家也答應了,就成了所謂的「我和飯店的協議」。
  那麼到了12點我過去,商家就會主動提供一份「蛋炒飯」而且是加料的特殊待遇,那麼這個就是「我和店家提供午飯的協議」的體現。而其餘人12點過去
  是沒有現成蛋炒飯和加料服務的,由於他們沒有達成協議。

3.Http原理web

  在網絡上常常會碰見 WWW 服務應用系統,該應用系統最基本的傳輸單位是 Web 網頁。WWW 服務應用系統的工做方式是基於 B/S 模式,
  由 Web 瀏覽器即B和 Web服務器(服務器)即S來構成,二者之間採用超文本傳送協議(HTTP)進行通訊。
  HTTP 協議是基於 TCP/IP 協議之上的協議,爲瀏覽器和 Web 服務器之間的應用層協議,是一種通用的、無狀態的和麪向對象的協議。
  當經過 HTTP 協議鏈接服務器時,通常會經歷如下 4 個步驟。數據庫

(1)鏈接:Web 瀏覽器與 Web 服務器創建鏈接,打開一個名爲 socket(套接字)的虛擬文件,此文件的創建標誌着鏈接創建成功。數組

(2)請求:Web 瀏覽器經過 Socket 向 Web 服務器提交請求。HTTP 的請求通常是 GET或 POST 命令(POST 用於 FORM 參數的傳遞)。瀏覽器

(3)應答:Web 瀏覽器提交請求後,經過 HTTP 協議傳送給 Web 服務器。Web 服務器接到後,進行事務處理,處理結果又經過 HTTP 傳回給 Web 瀏覽器,從而在 Web 瀏覽器上顯示出所請求的頁面。緩存

(4)關閉鏈接:當應答結束後,Web 瀏覽器與 Web 服務器必須斷開,以保證其餘 Web瀏覽器可以與 Web 服務器創建鏈接。tomcat


  例如當 IE 瀏覽器與 www.test.com:8080/mydir/index.html 創建了鏈接,
  就會發送 GET命令 GET /mydir/index.html HTTP/1.0。主機名爲 www.test.com 的 Web 服務器就會從它的文檔空間中搜索子目錄 mydir 的文件 index.html。
  若是找到該文件,Web 服務器把該文件內容傳送給相應的 Web 瀏覽器。
  爲了可以讓瀏覽器知道傳送回文件的類型,Web 服務器首先傳送一些 HTTP 頭信息,而後傳送具體內容(即 HTTP 體信息),HTTP 頭信息和 HTTP 體信息之間用一個空行分開。服務器

  經常使用的 HTTP 頭信息以下。網絡

(1)HTTP 1.0 200 OK:這是 Web 服務器應答的第一行,列出服務器正在運行的 HTTP版本號和應答代碼。代碼「200 OK」表示請求完成。

(2)MIME_Version:1.0:表示 MIME 類型的版本。

(3)content_type:這個頭信息很是重要,表示 HTTP 體信息的 MIME 類型。如content_type:text/html 表示傳送的數據是 HTML 文檔。

(4)content_length:長度值,表示 HTTP 體信息的長度(字節)。

4.客戶端和服務端詳解

  1)客戶端
  客戶端主要職能有兩個,一個向服務器發送請求,另外一個是接收服務器返回的報文並解釋成友善的信息供咱們閱讀。
  客戶端大概有如下幾類:瀏覽器、咱們本身寫的應用程序(桌面應用和APP應用)、其餘。咱們在平常生活中使用最多的就是瀏覽器了。

  下面咱們以IE爲示例:咱們在地址欄輸入網址並巧下回車,瀏覽器會爲咱們作以下的處理:

  1解析出協議(http)、域名(www.baidu.com)及訪問資源(index.html)
  2使用http協議並建立請求報文向服務器端發送請求
  3接收到服務器返回的內容並渲染展現。

  大部份客戶端的工做都由客戶端軟件進行了包裝和處理。但出於學習的目的咱們使用最原始的命令telnet來模擬http請求。telnet服務須要在控制面板打開
  點擊【開始】--【運行】--輸入cmd打開命令行窗口。在命令行窗口中輸入telnet www.baidu.com 80而後敲擊一下回車
  使用快捷鍵"Ctrl+]"(ctrl+右中括號)來打開本地回顯功能,這樣咱們能夠看到輸入到窗口的內容,不然輸入的內容不顯示。
  再次敲擊一下回車。
  此時出現空白窗口,咱們就能夠模擬http請求向服務器發送請求報文了。在窗口中輸入:
  GET /index.html HTTP/1.1
  Host:www.baidu.com
  注意此處敲擊兩下回車。成功後服務器返回的報文會顯示在命令行窗口

  小結:客戶端主要處理髮送請求及處理服務器返回的報文。


  2)傳輸內容
  (1)URL:URL是尋找信息時所須要的資源位置。經過URL客戶端才能找到網絡中的大量數據資源 。如:http://www.baidu.com:80/index.html
  URL分爲三個部分:
  第一部分http是URL的方案,方案告訴客戶端使用什麼樣的協議去訪問服務器了,也能夠是fpt或https等。
  第二部分www.baidu.com:80,指服務器的位置。
  第三部分 /index.html是資源路徑,說明了請求的是服務器上哪一個特定的本地資源。

  URL語法:<協議>://<用戶名>:<密碼>@主機:端口/路徑;參數?查詢
  幾乎沒有幾個URL包含了全部這些組件。
  協議:訪問服務器時使用的協議類型(FTP,HTTP,HTTPS)
  用戶名:有些協議須要使用用戶名,如FTP匿名用戶登陸:ftp://anonymous@cncoder.me
  密碼:有些協議須要使用密碼,如FTP用戶名密碼登陸:ftp://username:password@cncoder.me
  主機:資源服務器的域名或IP地址
  端口:服務器監聽的端口號,http協議默認是80端口。
  路徑:服務器上本地資源的路徑。用「/」來分格。如:/theme/image/logo.png
  參數:某些協議會輸入指定的參數,參數以name:value形式出現,中間用「;」來分格。
  查詢:用「?」與其餘的組件分格開,並用「&」來分隔查詢。如:?id=1&name=cncoder

  (2)報文:HTTP報文能夠分爲兩類:請求報文和響應報文,請求報文會向服務器請求一個動做,響應報文會將請求的結果返回給客戶端。請求報文和響應報文的結構基本相同。
  下面爲咱們獲取服務器上一張圖片的報文。
  請求報文:
  GET /Theme/Image/logo.png HTTP/1.1
  Host:www.cncoder.me
  響應報文:
  HTTP/1.1 200 OK
  Content-Type:image/gif
  Conetnt-Length4567

  請求報文的格式:
  <方法><資源路徑><協議版本>
  <報文頭信息>
  <報文體信息>

  響應報文格式:
  <協議版本><狀態碼><緣由短語>
  <報文頭信息>
  <報文體信息>

  請求報文和響應報文只有起始行的語法不一樣。


  常見請求報文頭信息
  Host:」 www.cncoder.me」
  User-Agent:"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0"
  Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
  Accept-Language:"zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"
  Accept-Encoding:"gzip, deflate"
  Connection:"keep-alive"

  常見響應頭信息
  Content-Encoding:"gzip"
  Content-Length:"1779"
  Content-Type:"text/html"
  Date:"Sun, 21 Aug 2016 11:45:07 GMT"
  Last-Modified:"Sun, 21 Aug 2016 11:33:32 GMT"
  Server:"Microsoft-IIS/7.5"
  X-Powered-By:"ASP.NET"


  (2.1)方法:請求的起始行以方法做爲起始,方法用來告訴服務器要如何作。如:GET /index.html HTTP/1.1 中的GET就是方法
  1.GET 請求指定的頁面信息,並返回實體主體。
  2.HEAD 相似於get請求,只不過返回的響應中沒有具體的內容,用於獲取報頭
  3.POST 向指定資源提交數據進行處理請求(例如提交表單或者上傳文件)。數據被包含在請求體中。POST請求可能會致使新的資源的創建和/或已有資源的修改。
  4.PUT 從客戶端向服務器傳送的數據取代指定的文檔的內容。
  5.DELETE 請求服務器刪除指定的頁面。
  6.CONNECT HTTP/1.1協議中預留給可以將鏈接改成管道方式的代理服務器。
  7.OPTIONS 容許客戶端查看服務器的性能。
  8.TRACE 回顯服務器收到的請求,主要用於測試或診斷。

  在開發過程當中咱們最經常使用的就是GET和POST方法。


  (2.2)狀態碼:當客戶端發起一次http請請求後,服務器會返回一個包含HTTP狀態碼的信息頭(server header)用以響應客戶端的請求。HTTP狀態碼的英文爲HTTP Status Code。
  1.100~199 信息,服務器收到請求,須要請求者繼續執行操做
  2.200~299 成功,操做被成功接收並處理
  3.300~399 重定向,須要進一步的操做以完成請求
  4.400~499 客戶端錯誤,請求包含語法錯誤或沒法完成請求
  5.500~599 服務器錯誤,服務器在處理請求的過程當中發生了錯誤

  經常使用狀態碼以下:
  200-請求成功

  403(禁止)服務器拒絕請求。
  404-請求的資源不存在
  500-內部服務器錯誤

  502(錯誤網關)服務器做爲網關或代理,從上游服務器收到無效響應。

  503(服務不可用)服務器目前沒法使用(因爲超載或停機維護)。一般,這只是暫時狀態。


3)服務器

  (0)    服務器軟件一直在監聽端口是否有新的請求到達,如iis或tomcat在創建web站點後,默認會一直監聽80端口等待http請求到過服務器。
  (1)    創建鏈接:若是客戶端已經打開一條到服務器的持久鏈接,則能夠直接使用,不然,客戶端須要在服務器打開一條新的鏈接。
  (2)    接收請求報文:鏈接上有數據到過期,Web服務器會從網絡鏈接中讀取數據,並將請求報文中的內容解析出來。


  如請求報文
  GET /index.html HTTP/1.1CRLF
  Host:www.cncoder.me
  Accept:text/htmlCRLF


  接收後會被表示爲
  Name:Method  Value:GET
  Name:Uri  Value:index.html
  Name:Version  1.1
  Name:Host  Value:www.cncoder.me
  Name:Accept  Value:test/html
  (3)    處理請求:當請求被接收和表示後,服務器即可以根據請求報文進行處理了。如:POST方法中提出報文主體的數據並插入到數據庫中。
  (4)    訪問資源:請求處理完成後,好比Web會根據數據生成一系列的HTML頁面或圖片等信息。此步驟將訪問這些存儲在服務器上的物理文件。
  (5)    構建響應:Web服務器在識別資源後,構造響應報文。響應報文中包含狀態碼、首行、主體等內容。
  (6)    發送響應:服務器將響應的數據發送給客戶端機器。
  (7)    記錄日誌:請求結束會Web服務器會在日誌文件中添加一條請求記錄。

  (8)手寫WEB服務器

 

  (8.1)實現HTTP協議原理WEB服務器

  當建立實現 HTTP 協議的 Web 服務器時,通常都會根據 HTTP 協議的工做原理,經歷固定的步驟。具體步驟以下。
  (1)建立 ServerSocket 類對象,監聽端口 8080。這是爲了區別於 HTTP 的標準 TCP/IP端口 80 而取的。
  (2)等待、接受客戶機鏈接到端口 8080,獲得與客戶機鏈接的 socket。
  (3)建立與 socket 套接字相關聯的輸入流 instream 和輸出流 outstream。
  (4)從與 socket 關聯的輸入流 instream 中讀取一行客戶機提交的請求信息,請求信息的格式爲 GET 路徑/文件名 HTTP/1.0。
  (5)從請求信息中獲取請求類型。若是請求類型是 GET,則從請求信息中獲取所訪問的 HTML 文件名。沒有 HTML 文件名時,則以 index.html 做爲文件名。
  (6)若是 HTML 文件存在,則打開 HTML 文件,把 HTTP 頭信息和 HTML 文件內容經過 Socket 傳回給 Web 瀏覽器,而後關閉文件;不然發送錯誤信息給 Web 瀏覽器
  (7)關閉與相應 Web 瀏覽器鏈接的 socket 套接字。

  8.2構建步驟

  首先建立了一個實現與瀏覽器通訊的工具類,而後再建立了調用工具類的 Web 服務器類,最後爲了測試 Web 服務器的功能,建立了一個簡單的網頁。

 

  8.3使用JAVA實現

   建立CommunicateThread.java 類用來實現與瀏覽器的通訊功能

public class CommunicateThread extends Thread {
    
    Socket client; // 建立鏈接 Web 瀏覽器的 Socket 類對象
    int counter; // 建立計數器對象

    public CommunicateThread(Socket cl, int c) {
        client = cl;
        counter = c;
    }
    //實現 run()方法
    public void run() {
    try {
            //獲取客戶端的 IP 地址變量
            String destIP = client.getInetAddress().toString();
            //獲取客戶機端口號
            int destport = client.getPort(); 
            //建立 PrintStream 輸出流對象
            PrintStream outstream = new PrintStream(client.getOutputStream());
            //建立輸入流的過濾對象
            DataInputStream instream = new DataInputStream(client.getInputStream());
            //讀取 Web 瀏覽器提交的請求信息
            String inline = instream.readLine();
            System.out.println("Received:" + inline);
            //判斷請求信息
            //當爲 GET 請求時
            if (getrequest(inline)) { 
            String filename = getfilename(inline); //獲取文件的名字
            File file = new File(filename); //建立網頁的 file 對象
            if (file.exists()) { //當文件存在,則回送給瀏覽器
            //設置返回信息
            System.out.println(filename + " requested.");
            outstream.println("HTTP/1.0 200 OK");
            outstream.println("MIME_version:1.0");
            outstream.println("Content_Type:text/html");
            int len = (int) file.length();
            outstream.println("Content_Length:" + len);
            outstream.println("");
            sendfile(outstream, file); //調用 sendfile()方法發送文件
            outstream.flush();
            } else { //當文件不存在時
            //建立顯示的內容
            String notfound = "<html><head><title>Not Found</title></head><body><h1>Error 404-file not found</h1></body></html>";
            //設置返回的信息
            outstream.println("HTTP/1.0 404 no found");
            outstream.println("Content_Type:text/html");
            outstream.println("Content_Length:"+notfound.length()+2);
            outstream.println("");
            outstream.println(notfound);
            outstream.flush();
            }
            }
            long time = 1;
            while (time < 11100000) {
            time++;
            } //延時
            client.close();
            } catch (IOException e) {
            System.out.println("Exception:" + e);
            }
            }

    boolean getrequest(String s) { // 判斷請求的類型是否爲 GET
        if (s.length() > 0) {
            if (s.substring(0, 3).equalsIgnoreCase("GET"))
                return true;
        }
        return false;
    }

    String getfilename(String s) { // 實現文件名的獲取
        String f = s.substring(s.indexOf(' ') + 1);
        f = f.substring(0, f.indexOf(' '));
        try {
            if (f.charAt(0) == '/')
                f = f.substring(1);
        } catch (StringIndexOutOfBoundsException e) {
            System.out.println("Exception:" + e);
        }
        if (f.equals(""))
            f = "index.html";
        return f;
    }

    void sendfile(PrintStream outs, File file) { // 實現發送文件到瀏覽器的功能
        try {
            // 對象 file 的輸入流對象
            DataInputStreamin = newDataInputStream(newFileInputStream(file));
            int len = (int) file.length(); // 獲取文件的長度
            byte buf[] = new byte[len]; // 建立字節數組
            in.readFully(buf); // 讀取內容存儲到數組 buf 中
            outs.write(buf, 0, len); // 輸出數組 buf 中的內容
            // 輸入流和輸出流
            outs.flush();
            in.close();
        } catch (Exception e) {
            System.out.println("Error retrieving file.");
            System.exit(1);
        }
    }
}

 

  代碼解析

  爲了便於實現相應功能,代碼中建立了 3 個方法
  getrequest()方法用來檢測客戶的請求是否爲 GET
  getfilename(s)方法是從客戶請求信息 s 中獲取要訪問的 HTML文件名
  sendfile()方法把指定文件內容經過 Socket 傳回給 Web 瀏覽器
  線程子類主要用來實現兩個功能,即分析 Web 瀏覽器提交的請求及把應答信息傳回給 Web 瀏覽器

 

  建立實現 Web 服務器的類WebServer.java 類用來實現 Web 服務器,該類主要經過調用 CommunicateThread 類

public class WebServer {
    public static void main(String args[]) {
        // 建立兩個端口號和鏈接次數的變量
        int i = 1, PORT = 8080;
        ServerSocket server = null; // 建立 ServerSocket 對象
        Socket client = null; // 建立 Socket 對象
        try {
            server = new ServerSocket(PORT); // 爲對象 ServerSocket 賦值
            // 輸出相應的信息
            System.out.println("Web Server is listening on port "+ server.getLocalPort());
            for (;;) { // 經過無限循環來不斷的接收監聽
                // 獲取客戶機的鏈接請求
                client = server.accept(); 
                // 建立 CommunicateThread 對象並啓動
                new CommunicateThread(client, i).start();
                i++; // 實現變量 i 的自增
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

  在上述代碼中首先建立 ServerSocket 對象,而後經過該對象的 accept()方法不停地接收請求,若是鏈接成功,則調用 CommunicateThread 類的 start()方法來處理請求。

 

  建立瀏覽器請求頁面

  當瀏覽器發送請求到 Web 服務器時,實際狀況是 Web 服務器會根據瀏覽器的請求返
  回相應的內容,本項目只是簡單地返回固定的名爲 index.html 的網頁

<HTML>
    <HEAD>
    <META HTTP-EQUIV="Content-Type" content="text/html; charset=utf-8">
    <TITLE>Java Web 服務器</TITLE>
    </HEAD>
    <BODY>
    <!--設置主題-->
    <h3>
    WEB 服務器主頁
    </h3>
    <hr> <!--設置橫線-->
    </BODY>
</HTML>

 

6.擴展內容引導 1.    Web的組件結構中還包含代理、緩存、網關、隧道。 2.    HTTP協議是創建在TCP/IP協議基礎之上。 3.    HTTP性能很大一方面在於創建鏈接。HTTP/1.0時使用Keep-Alive。HTTP/1.1使用管道鏈接。

相關文章
相關標籤/搜索