python搭建简单的静态web服务器

python搭建简单的静态web服务器

[TOC]

储备知识

  • 一丢丢的python(io和多线程的知识)
  • 一丢丢的http协议
  • 一丢丢的tcp/ip协议(当然不了解也没关系)
  • 一丢丢的正则表达式知识

web服务器基本原理

  • 当在浏览器的地址栏输入一个ip与端口之后,浏览器就会通过tcp/ip协议与相应的主机端口进程建立联系。经历过三次握手之后就会将http请求发送到相应的服务器进程去,之前我们了解的http协议在服务进程收到的其实就是一串有特殊格式的字符串。

    当我们浏览器输入localhost:9876 后服务进程实际收到的如下:

大致流程

  1. 在服务端建立tcp服务进程,为了保证服务端可以同时处理多个请求,我们需要在每接受一个请求后为其单独使用一个线程(或者进程)为其进行服务。

    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("-------等待接受服务----------")
            client, client_address = server.accept()
            print("-------接受服务成功----------")
            # 如果使用进程服务,可以在在后面把client关闭。
            p = Thread(target=deal_socket, args=(client,))
            p.start()
    except Exception as e:
           print(e)
    finally:
           server.close()
           print("-------服务结束----------")
    

    这里的deal_socket函数就是我们为一个请求服务的函数,在一个单独的线程中运行。

  2. 在处理url请求的函数中,我们需要读取出客户端的http请求。

    def deal_socket(client):
        print("-------开启新的线程----------")
        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("-------关闭新的线程----------")
    
    • 在这里的data就是我们读取到的http服务请求,当其长度等于0时代表客户端已经关闭了tcp连接。
    • 这里的get_request_name_from_http()需要我们解析出请求的静态资源
    • 这里的writeHtml()将静态文本写回到客户端。
  3. get_request_name_from_http函数中我们需要从原始的url请求中解析出http请求中我们需要的请求资源部分,这里我们可以通过正则表达式完成简单的完成解析。

    def get_request_name_from_http(http):
        # 注意这里通过非贪婪模式匹配
        r = re.search(r"GET /(.+?) ", http)
        fileName = ""
        if r != None:
            fileName = r.group(1)
        return fileName
    
    • 请求的http大概格式是这样(当我们访问http://localhost:9876/html/index.html时)

      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
      

      第一行就是我们请求的静态资源,我们将其通过非贪婪模式的正则表达式扣出来。

  4. 在解析到请求的静态地址后就是简单的读取请求的文件,然后已http协议的格式返回回去就行了。

    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"))
    
    • 当请求的静态文件不存在时,将返回给客户端文件不存在。

    • 上面的相应格式是根据http相应报文的格式而定的,否则浏览器会不识别:

      在Windows中\r\n分别代表回车和换行,而现在在unix系统中\n就代表了回车换行。

完整代码

  • 下面是完整的服务代码,不到60行就可以完成一个简单的静态web服务器,这就是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("-------开启新的线程----------")
        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("-------关闭新的线程----------")
     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("-------等待接受服务----------")
                client, client_address = server.accept()
                print("-------接受服务成功----------")
                # 就这里和多线程不同,并且千万不能把client关掉
                p = Thread(target=deal_socket, args=(client,))
                p.start()
        except Exception as e:
            print(e)
        finally:
            server.close()
            print("-------服务结束----------")
      if name == "main":
        main()
    
  • 到此就用python构建了史上最挫的静态wen服务器了,直接在浏览其输入静态html请求就可以显示网页了:

    虽然很挫,不过web服务器的基本原理就是如此,牛逼的服务器也只是在这之上做了很多完善,下一篇我们将采用python提供的WSGI标准完成一个动态的web框架。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • web静态服务器 服务端: 1.1.1显示固定的页面 参考代码: import socket from multi...
    chen_000阅读 2,063评论 0 1
  • http://python.jobbole.com/85231/ 关于专业技能写完项目接着写写一名3年工作经验的J...
    燕京博士阅读 7,545评论 1 118
  • 1.1 回顾网络编程 1.2 http协议介绍 HTTP是Hyper Text Transfer Protocol...
    TENG书阅读 501评论 0 0
  • 今天早上在盘点部门主管的维持考核,一直到下午2点,下午跟娟儿到索菲亚酒店,参加芯美昕公司的说明会,跳出行业以外,去...
    卓彤的美好时光阅读 147评论 0 0