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