用Python写一个简易的http服务器,初步支持WSGI协议

Python这匹黑马在最近几年可谓异军突起,借着人工智能的东风,不仅霸占人工智能,就连web和大数据都不放过。作web开发,http协议是必须遵守的,想要做动态页面,就需要用到模板或者框架,所以又得遵守WSGI协议(小声bb,我一个都不想遵守,但谁让咱不如别人呢),下面咱就来写个http服务器,去瞅瞅那啥啥啥协议长啥样,等有朝一日,咱说不定也能制定个协议(/斜眼笑)

首先咱来说说啥是http服务器
   说白辽,http服务器就是浏览器(或者某虫)向你的电脑的80端口(443?7890?爱啥啥)发送
一个具有一定格式的数据,然后某个程序刚好在那个端口守着,于是,浏览器发送的数据就被打劫下来
了。不巧刚好这个程序认识这种格式,就按照这种格式回了一些数据打发浏览器。这个程序就是所谓的
http服务器。相互发送数据的格式约定就称为http协议了。
http协议:
浏览器请求格式:
	请求包括请求头,(有或者没有)请求体,至少需要一行内容:
		GET / HTTP/1.1
	其中,GET表示请求方法,/ 表示请求资源,例如请求a/b/c/index.html,请求头就可以为:
		GET /a/b/c/index.html /HTTP/1.1
	其他的爱咋写咋写,只需要注意一点,请求头和请求体的区别方式,仅仅是一个空行,没空行?
	那就都当请求头好了。
	
http返回数据格式:
	返回同样包含响应头和响应内容,基本上都长一个样(毕竟都是http的崽)
	有一点不一样,响应头必须的一行是:
		HTTP/1.1 (200 OK)
	至于你想返回200,300,400随你咯。
	接下来空一行写下响应内容,也就是浏览器中看到的东西。
	能凑出响应头和响应内容的代码守着一个端口,就是http服务器了。
WSGI 协议
WSGI 协议指的就是--------->
	    http服务器中调用web框架中的application函数,传过去一个字典和一个http服务器中的一个
	函数的引用。application被调用时通过函数的引用可以得到响应头,调用结束得到响应内容。这
	套乱七八糟的调用就是WSGI 协议
下面就来看看具体代码实现
  • http 服务器
import socket
import threading
import re
import dynamic.Web_frame


class WSGIWebServer(object):
    def __init__(self):
        """创建监听套接字,初始化类"""

        self.tcp_link = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.tcp_link.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.tcp_link.bind(("", 80))
        self.tcp_link.listen(128)
        self.request_num = 1

    def __del__(self):
        """关闭监听套接字"""
        self.tcp_link.close()

    def get_request(self):
        """获取客户端请求,提取响应"""
        try:
            request = self.client_link.recv(4096).decode().splitlines()
            request_file = re.match(r"\w{1,10} /(.*) ", request[0]).group(1)
            return request_file
        except:
            return 500

    def select_file(self):
        """检查请求文件是否存在,如果存在返回文件内容,不存在则返回None"""

        response_file = self.get_request()
        if response_file == 500:
            return None
        elif response_file == "":
            response_file = "index.html"
        return response_file

    def open_file(self):
        """获取文件内容,如果不存在返回404"""

        file = self.select_file()
        if file is None:
            return "服务器错误,请稍后尝试".encode()
        elif not file.endswith(".py"):
            try:
                with open("./static/" + file, "rb") as f:
                    file_data = f.read()
            except:
                return ("404 Not Found".encode(), file)
            else:
                return (file_data, file)
        else:
            set_dict = dict()
            set_dict["PATH_INFO"] = file
            result = dynamic.Web_frame.application(set_dict, self.set_headers)
            return (result, file)

    def set_headers(self, status, headers):
        self.status = status
        self.headers = headers
        print(self.headers)
        print(self.status)

    def response_client(self):
        """响应客户端"""

        response_body, request_file = self.open_file()
        if request_file.endswith(".py"):
            response_headers = "HTTP/1.1 %s\r\n" % self.status
            for temp in self.headers:
                response_headers += "%s:%s\r\n" % (temp[0], temp[1])
            response_headers += "Content-Length:%d\r\n" % len(response_body)
            response_headers += "\r\n"
        else:
            response_headers = "HTTP/1.1 200 OK\r\n"
            response_headers += "Content-Length:%d\r\n" % len(response_body)
            response_headers += "\r\n"
            response_headers += 'Content-Type:text/html; charset=utf-8'
        self.client_link.send(response_headers.encode())
        self.client_link.send(response_body)

    def run_server(self):
        """调用接口,为客户端服务"""

        while True:
            self.client_link, self.client_addr = self.tcp_link.accept()
            process = threading.Thread(target=self.response_client())
            self.client_link.setblocking(False)
            process.start()
            print("\r请求次数:", self.request_num, end="")
            self.request_num += 1


def main():
    """控制程序"""

    wsgi_web_server = WSGIWebServer()
    wsgi_web_server.run_server()


if __name__ == "__main__":
    main()

  • web框架
import time
import pymysql
import re

URL_DICT = dict()


def route(url):
   def set_func(func):
       URL_DICT[url] = func

       def get_func(*args, **kwargs):
           return func(*args, **kwargs)

       return get_func

   return set_func


def get_db_content(sql):
   connection = pymysql.connect(host="localhost", port=3306, user="root", password="cx2414672604", database="webdata",
                                charset="utf8")
   cursor = connection.cursor()
   sql_count = cursor.execute(sql)
   # print(sql_count)
   ret = cursor.fetchall()
   cursor.close()
   connection.close()
   return ret


@route("index.py")
def index():
   with open("./templates/index.html") as f:
       content = f.read()
   info = get_db_content("select * from info")
   # my_info = "hahahaha"

   my_info = """
   <tr>
           <th>%s</th>
           <th>%s</th>
           <th>%s</th>
           <th>%s</th>
           <th>%s</th>
           <th>%s</th>
           <th>%s</th>
           <th>%s</th>
           <th>添加</th>
   </tr>
   """
   html = ""
   for temp in info:
       html += my_info %(str(temp[0]), str(temp[1]), str(temp[2]), str(temp[3]), str(temp[4]), str(temp[5]), str(temp[6]),str(temp[7]))
   content = re.sub(r"\{%content%\}", html, content)

   return content.encode("gbk")


def login():
   pass


@route("center.py")
def center():
   with open("./templates/center.html") as f:
       content = f.read()

   info = get_db_content("select i.code,i.short,i.chg,i.turnover,i.price,i.highs,f.note_info from focus as f inner join info as i on f.info_id=i.id;")
   template = """
    <tr>
           <th>%s</th>
           <th>%s</th>
           <th>%s</th>
           <th>%s</th>
           <th>%s</th>
           <th>%s</th>
           <th style="color:red">%s</th>
           <th>修改备注</th>
           <th>del</th>
       </tr>
   """
   html = ""
   for temp in info:
       html += template %(str(temp[0]), str(temp[1]), str(temp[2]), str(temp[3]), str(temp[4]), str(temp[5]), str(temp[6]))
   content = re.sub(r"\{%content%\}", html, content)
   
   return content.encode("gbk")


def application(get_dict, get_fun):
   get_fun("200 OK", [('Content-Type', 'text/html; charset=gbk'), ('Connection', 'keep-alive')])
   file = get_dict["PATH_INFO"]
   return URL_DICT[file]()
   # try:
   #     return URL_DICT[file]()
   # except Exception as e:
   #     return ("产生异常:%s" % str(e)).encode()

其中涉及到数据库操作,以及一些HTML,js,css文件,所以直接运行会有问题,
看看思路就好,如果想要完整内容,
加QQ:914814442
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值