day57 手写socket、路由系统、响应一个动态内容、链接数据库、django配置、及应用、DNS服务器
自定义一个简单的web框架
1纯生socket
import socket
def run():
sk = socket.socket()
sk.bind(('127.0.0.1', 8080))
sk.listen(5)
while True:
conn, addr = sk.accept()
data = conn.recv(8096)
# print(data)
conn.send(bytes('HTTP/1.1 200 OK\r\n\r\n', encoding='utf-8'))
conn.send(bytes('hello http', encoding='utf-8'))
if __name__ == '__main__':
run()
2根据输入不同的url,获得不一梓的相应内容
需要找到请求的uri,是/还是index/还是login
import socket
def run():
sk = socket.socket()
sk.bind(('127.0.0.1', 8989))
sk.listen(5)
while True:
conn, addr = sk.accept()
data = conn.recv(8096)
# print('收到的信息1', data)
# 拆分请求信息,拿到uri
# 拿到第一大块
header_list = str(data, encoding='utf-8').split('\r\n\r\n')[0]
# print('收到的信息2', header_list[0])
# 拿到第一大块的第一行
content_list = header_list.split('\r\n')[0] # GET / HTTP/1.1
# print(content_list)
uri = content_list.split(' ')[1] # /
print(uri)
res = None
if uri == '/xxx':
res = bytes('this is xxx', encoding='utf-8')
elif uri == '/ooo':
res = bytes('this is ooo', encoding='utf-8')
elif uri == '/':
res = bytes('ok', encoding='utf-8') # \r\n的斜杠不要写反了
else:
res = bytes('404', encoding='utf-8')
conn.send(bytes('HTTP/1.1 200 OK\r\n\r\n', encoding='utf-8')) # \r\n的斜杠不要写反了
conn.send(res)
conn.close()
if __name__ == '__main__':
run()
3.uri 和函数的对应关系, 一下if很啰嗦
路由系统 响应一个html文件给浏览客户端,【静态网站】fn1
import socket
def fn1():
# return bytes('this is xxx', encoding='utf-8')
fp = open('index_3.html', 'r', encoding='utf-8')
data = fp.read()
return bytes(data, encoding='utf-8') # 响应一个html文件给浏览客户端
def fn2():
return bytes('this is index', encoding='utf-8')
def fn3():
return bytes('this is kkk', encoding='utf-8')
routes = [
('/xxx', fn1),
('/index', fn2),
('/kkk', fn3)
]
def run():
sk = socket.socket()
sk.bind(('127.0.0.1', 8989))
sk.listen(5)
while True:
conn, addr = sk.accept()
data = conn.recv(8096)
# print('收到的信息1', data)
# 拆分请求信息,拿到uri
# 拿到第一大块
header_list = str(data, encoding='utf-8').split('\r\n\r\n')[0]
# print('收到的信息2', header_list[0])
# 拿到第一大块的第一行
content_list = header_list.split('\r\n')[0] # GET / HTTP/1.1
# print(content_list)
uri = content_list.split(' ')[1] # /
# print(uri)
func_name = None
for key in routes:
if uri in key:
func_name = key[1]
break
if func_name:
res = func_name()
else:
res = bytes('404 not found', encoding='utf-7')
conn.send(bytes('HTTP/1.1 200 OK\r\n\r\n', encoding='utf-8')) # \r\n的斜杠不要写反了
conn.send(res)
conn.close()
if __name__ == '__main__':
run()
4.响应一个动态文件给浏览客户端: fn2
import socket
import time
def fn1():
# return bytes('this is xxx', encoding='utf-8')
fp = open('index_3.html', 'r', encoding='utf-8')
data = fp.read()
return bytes(data, encoding='utf-8') # 响应一个html文件给浏览客户端
def fn2():
# return bytes('this is index', encoding='utf-8')
ctime = str(time.time())
fp = open('article_4.html', 'r', encoding='utf-8')
data = fp.read()
res = data.replace('@@content@@', ctime)
return bytes(res, encoding='utf-8')
def fn3():
return bytes('this is kkk', encoding='utf-8')
routes = [
('/xxx', fn1),
('/index', fn2),
('/kkk', fn3)
]
def run():
sk = socket.socket()
sk.bind(('127.0.0.1', 8989))
sk.listen(5)
while True:
conn, addr = sk.accept()
data = conn.recv(8096)
# print('收到的信息1', data)
# 拆分请求信息,拿到uri
# 拿到第一大块
header_list = str(data, encoding='utf-8').split('\r\n\r\n')[0]
# print('收到的信息2', header_list[0])
# 拿到第一大块的第一行
content_list = header_list.split('\r\n')[0] # GET / HTTP/1.1
# print(content_list)
uri = content_list.split(' ')[1] # /
# print(uri)
func_name = None
for key in routes:
if uri in key:
func_name = key[1]
break
if func_name:
res = func_name()
else:
res = bytes('404 not found', encoding='utf-7')
conn.send(bytes('HTTP/1.1 200 OK\r\n\r\n', encoding='utf-8')) # \r\n的斜杠不要写反了
conn.send(res)
conn.close()
if __name__ == '__main__':
run()
5.响应数据库内容
模板渲染
需要将html代码和mysql结果融合
def fn3():
# 通过pymysql拿到数据库中数据
# return bytes('this is kkk', encoding='utf-8')
import pymysql
conn = pymysql.connect(host='127.0.0.1', user='root', password='999', db='db4', charset='utf8')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql = 'select id, name, extra, type_id from user'
cursor.execute(sql)
res = cursor.fetchall()
print(res)
# [{'id': 1, 'name': 'egon', 'extra': '', 'type_id': 1},
# {'id': 2, 'name': 'jerry', 'extra': '', 'type_id': 2},]
# 将html代码和mysql结果融合
# 将该数据写入表格,替换
# 拼接
str_list = []
for user in res:
res_str = '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>' % (user['id'], user['name'], user['extra'], user['type_id'],)
str_list.append(res_str)
s = ''.join(str_list)
# 替换
fp = open('content_5.html', 'r', encoding='utf-8')
data = fp.read()
res = data.replace('@@content@@', s)
return bytes(res, encoding='utf-8')
6.server_jinjia表单
def fn4():
import pymysql
conn = pymysql.connect(host='127.0.0.1', user='root', password='999', db='db4', charset='utf8')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql = 'select id, name, extra, type_id from user'
cursor.execute(sql)
users = cursor.fetchall()
fp = open('contentjinja2_5.html', 'r', encoding='utf-8')
data = fp.read()
from jinja2 import Template
template = Template(data)
data = template.render(users=users)
Django的基础
web请求流程
所有的web应用本质上就是一个socket服务端,用户的浏览器就是一个socket客户端,即b/s架构,基于http协议,工作在应用层.
http协议
Hyper Text Transfer Protocol,超文本传输协议,是一种建立在TCP上的无状态,一次性连接.它限制每次连接只处理一个请求,当服务器返回本次请求的应答后便立即关闭连接,下次请求再重新建立连接。
1.客户端和服务器建立连接,
2.客户端发送一个HTTP请求,说明想要访问的资源和请求的动作,
3.服务端收到请求之后,服务端开始处理请求,并根据请求做出相应的动作访问服务器资源,最后通过发送HTTP响应把结果返回给客户端
4.客户端与服务器关闭连接
其中一个请求的开始到一个响应的结束称为事务,当一个事物结束后还会在服务端添加一条日志条目。
DNS工作流程
DNS协议:域名系统,域名和ip地址相互映射的一个分布式数据库(基于udp协议).
工作流程:
1.打开浏览器,输入网址,客户端发送请求.
2.收到请求后,先在本地DNS服务器缓存中查找有没有这条记录.如果有该纪录项,则本地的域名服务器就直接把查询的结果返回。
3.没有,就去根域名服务器中找域名中的顶级域名(.com, .net, .cn, .org),将顶级域名中的服务器地址返回给本地DNS服务器.
4.本地服务器拿到顶级域名服务器地址后,,给顶级域名服务器发送请求,顶级域名服务器查询域名对应的ip地址.
5.顶级域名服务器将请求中的二级域名信息返回给本地服务器
6.本地服务器拿到信息后,给二级域名发送请求.二级域名服务器查询域名对应的ip地址.
7.二级域名服务器将查找到的返回给本地DNS服务器
8.本地服务器将拿到的结果缓存在自己的服务器中,以便下次查找,同时将结果返回给客户端.
本地DNS的查找:
C: --> Windoes -->System32 --> drivers --> etc --> hosts
当在浏览器输入url,按下回车时,到返回页面,描述过程.
收到请求后,先在dns系统中查找域名所对应的ip地址,然后dns系统将查找到的ip地址返回给浏览器,浏览器拿到ip地址后,给ip相对应的服务器发送请求.
自定义web框架
import socket
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
connect,addr = server.accept()
buf = connect.recv(1024)
connect.send(bytes('HTTP1.1 200 OK\r\n\r\n', encoding='utf-8'))
connect.send(bytes('hello world', encoding=('utf-8')))
connect.close()
Http协议:
得到的数据
请求头:
GET / HTTP/1.1
Host: 127.0.0.1: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/75.0.3770.100 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Token: bdsjalbdjsalbdjsa
请求体:
bdsabdjsabjddas
响应头:
HTTP/1.1 200 OK
响应体:
自己看到的内容
http: 默认端口是80
Https: 默认的端口是443
状态码
1XX:通知
2XX: 成功 200 (ok)
3XX 重定向 302(Found) 304(Not Modified)
4XX:客户端错误 403(forbidden 禁止访问) 404(not found)
5XX 服务端错误 500 (服务端代码错误) 502 (网关错误 bad gateway)