python搭建簡(jiǎn)單的靜態(tài)web服務(wù)器

python搭建簡(jiǎn)單的靜態(tài)web服務(wù)器

[TOC]

儲(chǔ)備知識(shí)

  • 一丟丟的python(io和多線程的知識(shí))
  • 一丟丟的http協(xié)議
  • 一丟丟的tcp/ip協(xié)議(當(dāng)然不了解也沒(méi)關(guān)系)
  • 一丟丟的正則表達(dá)式知識(shí)

web服務(wù)器基本原理

  • 當(dāng)在瀏覽器的地址欄輸入一個(gè)ip與端口之后,瀏覽器就會(huì)通過(guò)tcp/ip協(xié)議與相應(yīng)的主機(jī)端口進(jìn)程建立聯(lián)系搞莺。經(jīng)歷過(guò)三次握手之后就會(huì)將http請(qǐng)求發(fā)送到相應(yīng)的服務(wù)器進(jìn)程去焚志,之前我們了解的http協(xié)議在服務(wù)進(jìn)程收到的其實(shí)就是一串有特殊格式的字符串析藕。

    當(dāng)我們?yōu)g覽器輸入localhost:9876 后服務(wù)進(jìn)程實(shí)際收到的如下:

大致流程

  1. 在服務(wù)端建立tcp服務(wù)進(jìn)程椿肩,為了保證服務(wù)端可以同時(shí)處理多個(gè)請(qǐng)求,我們需要在每接受一個(gè)請(qǐng)求后為其單獨(dú)使用一個(gè)線程(或者進(jìn)程)為其進(jìn)行服務(wù)馏慨。

    server = socket(AF_INET, SOCK_STREAM)
    server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    address = ('', 9876)
    server.bind(address)
    server.listen(10)
    try:
        while True:
            print("-------等待接受服務(wù)----------")
            client, client_address = server.accept()
            print("-------接受服務(wù)成功----------")
            # 如果使用進(jìn)程服務(wù)音婶,可以在在后面把client關(guān)閉。
            p = Thread(target=deal_socket, args=(client,))
            p.start()
    except Exception as e:
           print(e)
    finally:
           server.close()
           print("-------服務(wù)結(jié)束----------")
    

    這里的deal_socket函數(shù)就是我們?yōu)橐粋€(gè)請(qǐng)求服務(wù)的函數(shù)倒谷,在一個(gè)單獨(dú)的線程中運(yùn)行蛛蒙。

  2. 在處理url請(qǐng)求的函數(shù)中,我們需要讀取出客戶端的http請(qǐng)求渤愁。

    def deal_socket(client):
        print("-------開(kāi)啟新的線程----------")
        try:
            data = client.recv(1024)
            if len(data) > 0:
                fileName = get_request_name_from_http(data.decode("utf-8"))
                writeHtml(client, fileName)
    
        finally:
            client.close()
            print("-------關(guān)閉新的線程----------")
    
    • 在這里的data就是我們讀取到的http服務(wù)請(qǐng)求牵祟,當(dāng)其長(zhǎng)度等于0時(shí)代表客戶端已經(jīng)關(guān)閉了tcp連接。
    • 這里的get_request_name_from_http()需要我們解析出請(qǐng)求的靜態(tài)資源
    • 這里的writeHtml()將靜態(tài)文本寫(xiě)回到客戶端抖格。
  3. get_request_name_from_http函數(shù)中我們需要從原始的url請(qǐng)求中解析出http請(qǐng)求中我們需要的請(qǐng)求資源部分诺苹,這里我們可以通過(guò)正則表達(dá)式完成簡(jiǎn)單的完成解析。

    def get_request_name_from_http(http):
        # 注意這里通過(guò)非貪婪模式匹配
        r = re.search(r"GET /(.+?) ", http)
        fileName = ""
        if r != None:
            fileName = r.group(1)
        return fileName
    
    • 請(qǐng)求的http大概格式是這樣(當(dāng)我們?cè)L問(wèn)http://localhost:9876/html/index.html時(shí))

      GET /html/index.html HTTP/1.1
      Host: localhost:9876
      Connection: keep-alive
      Cache-Control: max-age=0
      Upgrade-Insecure-Requests: 1
      User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36
      

      第一行就是我們請(qǐng)求的靜態(tài)資源雹拄,我們將其通過(guò)非貪婪模式的正則表達(dá)式扣出來(lái)筝尾。

  4. 在解析到請(qǐng)求的靜態(tài)地址后就是簡(jiǎn)單的讀取請(qǐng)求的文件,然后已http協(xié)議的格式返回回去就行了办桨。

    def writeHtml(client, fileName):
        rspHead = None
        rspBody = None
        if not os.path.exists(fileName):
            rspHead = "HTTP/1.1 404 error\r\nServer: foreverServer\r\n\r\n"
            rspBody = "file not found"
        else:
            rspHead = "HTTP/1.1 200 OK\r\nServer: foreverServer\r\n\r\n"
            html = open(fileName, 'r', encoding='UTF-8')
            rspBody = html.read()
        client.send((rspHead + rspBody).encode("utf-8"))
    
    • 當(dāng)請(qǐng)求的靜態(tài)文件不存在時(shí)筹淫,將返回給客戶端文件不存在。

    • 上面的相應(yīng)格式是根據(jù)http相應(yīng)報(bào)文的格式而定的呢撞,否則瀏覽器會(huì)不識(shí)別:

      ?

      在Windows中\(zhòng)r\n分別代表回車(chē)和換行损姜,而現(xiàn)在在unix系統(tǒng)中\(zhòng)n就代表了回車(chē)換行。

      ?

完整代碼

  • 下面是完整的服務(wù)代碼殊霞,不到60行就可以完成一個(gè)簡(jiǎn)單的靜態(tài)web服務(wù)器摧阅,這就是python的魅力:

    from socket import *
    from threading import Thread
    import os
    import re
    
    def get_request_name_from_http(http):
        r = re.search(r"GET /(.+?) ", http)
        fileName = ""
        if r != None:
            fileName = r.group(1)
        return fileName
    
    def writeHtml(client, fileName):
        rspHead = None
        rspBody = None
        if not os.path.exists(fileName):
            rspHead = "HTTP/1.1 404 error\r\nServer: foreverServer\r\n\r\n"
            rspBody = "file not found"
        else:
            rspHead = "HTTP/1.1 200 OK\r\nServer: foreverServer\r\n\r\n"
            html = open(fileName, 'r', encoding='UTF-8')
            rspBody = html.read()
        client.send((rspHead + rspBody).encode("utf-8"))
    def deal_socket(client):
        print("-------開(kāi)啟新的線程----------")
        try:
            data = client.recv(1024)
            if len(data) > 0:
                fileName = get_request_name_from_http(data.decode("utf-8"))
                writeHtml(client, fileName)
    
        finally:
            client.close()
            print("-------關(guān)閉新的線程----------")
     def main():
         server = socket(AF_INET, SOCK_STREAM)
        server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        address = ('', 9876)
        server.bind(address)
        server.listen(10)
        try:
            while True:
                print("-------等待接受服務(wù)----------")
                client, client_address = server.accept()
                print("-------接受服務(wù)成功----------")
                # 就這里和多線程不同,并且千萬(wàn)不能把client關(guān)掉
                p = Thread(target=deal_socket, args=(client,))
                p.start()
        except Exception as e:
            print(e)
        finally:
            server.close()
            print("-------服務(wù)結(jié)束----------")
      if name == "main":
        main()
    
  • 到此就用python構(gòu)建了史上最挫的靜態(tài)wen服務(wù)器了绷蹲,直接在瀏覽其輸入靜態(tài)html請(qǐng)求就可以顯示網(wǎng)頁(yè)了:

    雖然很挫棒卷,不過(guò)web服務(wù)器的基本原理就是如此,牛逼的服務(wù)器也只是在這之上做了很多完善祝钢,下一篇我們將采用python提供的WSGI標(biāo)準(zhǔn)完成一個(gè)動(dòng)態(tài)的web框架比规。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市拦英,隨后出現(xiàn)的幾起案子蜒什,更是在濱河造成了極大的恐慌,老刑警劉巖疤估,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灾常,死亡現(xiàn)場(chǎng)離奇詭異霎冯,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)钞瀑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)沈撞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人雕什,你說(shuō)我怎么就攤上這事缠俺。” “怎么了监徘?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)吧碾。 經(jīng)常有香客問(wèn)我凰盔,道長(zhǎng),這世上最難降的妖魔是什么倦春? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任户敬,我火速辦了婚禮,結(jié)果婚禮上睁本,老公的妹妹穿的比我還像新娘尿庐。我一直安慰自己,他們只是感情好呢堰,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布抄瑟。 她就那樣靜靜地躺著,像睡著了一般枉疼。 火紅的嫁衣襯著肌膚如雪皮假。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 50,096評(píng)論 1 291
  • 那天骂维,我揣著相機(jī)與錄音惹资,去河邊找鬼。 笑死航闺,一個(gè)胖子當(dāng)著我的面吹牛褪测,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播潦刃,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼侮措,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了乖杠?” 一聲冷哼從身側(cè)響起萝毛,我...
    開(kāi)封第一講書(shū)人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎滑黔,沒(méi)想到半個(gè)月后笆包,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體环揽,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年庵佣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了歉胶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡巴粪,死狀恐怖通今,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肛根,我是刑警寧澤辫塌,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站派哲,受9級(jí)特大地震影響臼氨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜芭届,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一储矩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧褂乍,春花似錦持隧、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至褥实,卻和暖如春洁仗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背性锭。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工赠潦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人草冈。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓她奥,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親怎棱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子哩俭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)拳恋,斷路器凡资,智...
    卡卡羅2017閱讀 134,638評(píng)論 18 139
  • web靜態(tài)服務(wù)器 服務(wù)端: 1.1.1顯示固定的頁(yè)面 參考代碼: import socket from multi...
    chen_000閱讀 2,069評(píng)論 0 1
  • http://python.jobbole.com/85231/ 關(guān)于專業(yè)技能寫(xiě)完項(xiàng)目接著寫(xiě)寫(xiě)一名3年工作經(jīng)驗(yàn)的J...
    燕京博士閱讀 7,560評(píng)論 1 118
  • 1.1 回顧網(wǎng)絡(luò)編程 1.2 http協(xié)議介紹 HTTP是Hyper Text Transfer Protocol...
    TENG書(shū)閱讀 508評(píng)論 0 0
  • 今天早上在盤(pán)點(diǎn)部門(mén)主管的維持考核隙赁,一直到下午2點(diǎn)垦藏,下午跟娟兒到索菲亞酒店,參加芯美昕公司的說(shuō)明會(huì)伞访,跳出行業(yè)以外掂骏,去...
    卓彤的美好時(shí)光閱讀 150評(píng)論 0 0