自己動手寫HTTP服務器

這是我的第一篇文章殴穴。和眾多程序員一樣,非常希望去分享自己的知識。但是萬事開頭難采幌,也可能是我自己水平的問題劲够,真是想不到要從什么內容開始。于是趁著有時間休傍,就自己搗鼓了一下HTTP服務器征绎。后來想想干脆就以自己手寫一個簡單的HTTP服務器的教程來開始我自己的寫作吧。本文中不足和錯誤的地方請各位看客多多指教磨取。下面就開始吧人柿。

HTTP簡介


當用戶在瀏覽器中輸入一個指向特定網頁的URL地址時,瀏覽器就會生成一個HTTP請求忙厌,因為瀏覽器需要將HTTP請求發(fā)送的服務器凫岖,所以這時瀏覽器會與服務器建立TCP連接,當TCP可靠連接建立之后逢净,瀏覽器會將生成的HTTP請求發(fā)送到服務器端哥放。這時服務器程序接收到了信息將要去識別這個信息的內容。服務器程序識別之后是一個HTTP的請求汹胃。就調用相應的服務程序婶芭,經過服務程序的分析和處理之后服務器端知道需要返回什么內容給瀏覽器了。當服務器返回了內容給瀏覽器后着饥,這時瀏覽器與服務器之間的數(shù)據(jù)交換完畢,這時TCP可靠連接就會斷開惰赋。如果用戶希望訪問新的網頁宰掉,瀏覽器就必須再次建立與服務器的連接了。

httpServer.jpg

開始之前我們準備好工具

  • java環(huán)境(JDK1.7)
  • eclipse
  • chrome瀏覽器

開始

使用eclipse建立項目結構如圖
HTTPServer.java為程序代碼
abc.html為需要請求的html頁面


Paste_Image.png

HTTPServer.java 代碼

package server;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class HTTPServer {
    public static void main(String[] args) {
        int port;
        ServerSocket serverSocket;
        try{
            port=Integer.parseInt(args[0]);
        }catch(Exception e){
            System.out.println("port=8080(默認)");
            port=8080;
            
        }
        
        try {
            serverSocket=new ServerSocket(port);
            System.out.println("服務器正在監(jiān)聽端口:"+serverSocket.getLocalPort());
            while(true){
                Socket socket=serverSocket.accept(); //沒有時會阻塞 程序停在此處
                System.out.println("建立了與客戶的一個新的TCP連接赁濒,該客戶的地址為:"+socket.getInetAddress()+":"+socket.getPort());
                try {
                    service(socket);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        
    }
    
    public static void service(Socket socket) throws Exception{
        InputStream socketIn=socket.getInputStream();
        Thread.sleep(500);   
        int size=socketIn.available();
        byte[] buffer=new byte[size];
        socketIn.read(buffer);
        String request=new String(buffer);
        System.out.println(request);
        //獲取HTTP請求的第一行
        String firstLineOfRequest=request.substring(0,request.indexOf("\r\n"));
        System.out.println("http請求的第一行:"+firstLineOfRequest);
        //解析HTTP請求的第一行
        String[] parts=firstLineOfRequest.split(" ");
        //獲取HTTP請求中的URI
        String uri=parts[1];
        /*決定HTTP響應正文的類型*/
        String contentType;
        if(uri.indexOf("html")!=-1||uri.indexOf("htm")!=-1)
            contentType="text/html";
        else if(uri.indexOf("jpg")!=-1||uri.indexOf("jpeg")!=-1)
            contentType="image/jpeg";
        else if(uri.indexOf("gif")!=-1)
            contentType="image/gif";
        else
            contentType="application/octet-stream"; //字節(jié)流類型
        
        /*創(chuàng)建HTTP響應結果*/
        //HTTP響應的第一行
        String responseFirstLine="HTTP/1.1 200 OK\r\n";
        
        String responseHeader="Content-type:"+contentType+"\r\n\r\n";
        
        InputStream in=HTTPServer.class.getResourceAsStream("/server"+uri);
        
        /*發(fā)送HTTP響應結果*/
        OutputStream socketOut=socket.getOutputStream();
        
        socketOut.write(responseFirstLine.getBytes());
        socketOut.write(responseHeader.getBytes());
        
        //發(fā)送正文
        int len=0;
        buffer=new byte[128];
        while((len=in.read(buffer))!=-1)
            socketOut.write(buffer,0,len);
        
        Thread.sleep(1000);
        socket.close();
        
    }

}

abc.html

this Html

程序默認監(jiān)聽端口8080
在一般情況下accept()函數(shù)是阻塞式的轨奄,當沒有socket連接的時候本線程是停在此處的。
當有一個TCP請求建立連接時這時服務器程序的accept()返回一個Socket對象拒炎。這個Socket對象就是在本程序中充當客戶端的角色對象挪拟。可以從此個對象中獲取輸入流讀取信息進來击你,也可以通過輸出流返回信息給客戶端玉组。

這里我們通過瀏覽器進行測試

將這個程序跑起來
我們使用瀏覽器進行請求http://localhost:8080/abc.html 請求自己服務器的abc.html

Paste_Image.png

查看控制臺打印出來的內容

port=8080(默認)
服務器正在監(jiān)聽端口:8080
建立了與客戶的一個新的TCP連接,該客戶的地址為:/0:0:0:0:0:0:0:1:52085
GET /abc.html HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8


http請求的第一行:GET /abc.html HTTP/1.1

從控制臺打印結果中我們可以看到HTTP協(xié)議的大致結構

  1. 請求行
  2. 消息報頭
  3. 請求正文

請求行中包括了本次HTTP協(xié)議是什么方式丁侄,以及uri定位地址在哪里 和一些關于HTTP規(guī)范版本的信息惯雳。

結語


文章內容比較簡單基礎,但這是關于底層的基礎內容鸿摇。我想這些機理還是很重要的石景,需要牢記于心,以便于掌控。這樣才能在碰到問題的時候迅速解決問題潮孽。

哈哈
謝謝大家閱讀揪荣!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市往史,隨后出現(xiàn)的幾起案子仗颈,更是在濱河造成了極大的恐慌,老刑警劉巖怠堪,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件揽乱,死亡現(xiàn)場離奇詭異,居然都是意外死亡粟矿,警方通過查閱死者的電腦和手機凰棉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陌粹,“玉大人撒犀,你說我怎么就攤上這事√椭龋” “怎么了或舞?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蒙幻。 經常有香客問我映凳,道長,這世上最難降的妖魔是什么邮破? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任诈豌,我火速辦了婚禮,結果婚禮上抒和,老公的妹妹穿的比我還像新娘矫渔。我一直安慰自己,他們只是感情好摧莽,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布庙洼。 她就那樣靜靜地躺著,像睡著了一般镊辕。 火紅的嫁衣襯著肌膚如雪油够。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天丑蛤,我揣著相機與錄音叠聋,去河邊找鬼。 笑死受裹,一個胖子當著我的面吹牛碌补,可吹牛的內容都是我干的虏束。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼厦章,長吁一口氣:“原來是場噩夢啊……” “哼镇匀!你這毒婦竟也來了?” 一聲冷哼從身側響起袜啃,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤汗侵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后群发,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晰韵,經...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年熟妓,在試婚紗的時候發(fā)現(xiàn)自己被綠了雪猪。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡起愈,死狀恐怖只恨,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情抬虽,我是刑警寧澤官觅,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站阐污,受9級特大地震影響休涤,放射性物質發(fā)生泄漏。R本人自食惡果不足惜笛辟,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一滑绒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧隘膘,春花似錦、人聲如沸杠览。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽踱阿。三九已至管钳,卻和暖如春鲁捏,著一層夾襖步出監(jiān)牢的瞬間侣灶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工捌年, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留佛点,地道東北人醇滥。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓黎比,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鸳玩。 傳聞我的和親對象是個殘疾皇子阅虫,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內容