-
不完善的web服务端实例
-
根据不同的路径返回不同的内容
-
返回html页面
-
总结
1.不完善的web服务端实例
a.尝试第一次连接:
#写客户端
import socket
#创建一个scoket实例对象
sk = socket.socket()
#绑定ip地址和端口
sk.bind(('127.0.0.1',8000))
#监听
sk.listen()
#写一个死循环,一直等待客户端来连接
while 1:
#获取与客户端的连接
conn, _ = sk.accept()
#接收客户端发来的消息
conn.recv(8888)
#给客户端回复消息
conn.send(b'successful')
#关闭
conn.close()
sk.close()
写好之后,运行。在浏览器中输入127.0.0.1:8000回车,发现该网页无法正常运作,第一次尝试失败。
b.为了发现错误原因,将接收到客户端消息打印出来,再次运行
data = conn.recv(8888)
print(data)
返回以下错误:
b'GET / HTTP/1.1
Host: 127.0.0.1:8001
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
'
整理以上错误信息,得到:
'
GET / HTTP/1.1 请求行
Host:127.0.0.1:8001 请求头
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
' 没有请求数据
原因分析:浏览器给我发的消息我收到了,但是我回复的东西浏览器不认识(没有遵从浏览器的协议),因此出现了问题
c.经过上述分析,加上以下内容,得到正常的显示
conn.send(b'http/1.1 200 OK
') #这里发送的是请求行,请求头部
conn.send(b'successful!') #这里发送的是请求数据
#浏览器和服务端通信都要遵循一个HTTP协议
关于HTTP协议:
1.浏览器往服务端发的叫做 请求(request)
请求的消息格式:
请求方法 路径 HTTP/1.1
k1:v1
k2:v2
请求数据
2.服务端往浏览器发的叫做 响应(response)
响应的消息格式:
HTTP/1.1 状态码 状态描述符
k1:v1
k2:v2
响应正文 <---html的内容
调试:
conn.send(b'http/1.1 200 OK
content-type:text/html; charset=utf8
')
conn.send(b'<h1>successful<h1>')
import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 7777))
sk.listen(5)
while 1:
conn, addr = sk.accept()
print(conn, addr)
data = conn.recv(1024)
conn.send(b'HTTP/1.1 200 OK
')
conn.send(b'<h1>hello world</h1>')
conn.close()
2.根据不同的路径返回不同的内容
把收到的数据转成字符串格式:
data_str = str(data, encoding='utf8')
import socket
#创建一个scoket实例对象
sk = socket.socket()
#绑定ip地址和端口
sk.bind(('127.0.0.1',8001))
#监听
sk.listen()
#写一个死循环,一直等待客户端来连接
while 1:
#获取与客户端的连接
conn, _ = sk.accept()
#接收客户端发来的消息
data = conn.recv(8888)
#把收到的数据转成字符串类型
data_str = str(data, encoding='utf8')
#用
去切割上面的字符串
li = data_str.split('
')
#print(li[0])
#按照空格切割上面的字符串
li2 = li[0].split()
path = li2[1]
conn.send(b'http/1.1 200 OK
content-type:text/html; charset=utf8
')
#根据不同的path返回不同的content
if path == '/':
conn.send(b'<h1>successful<h1>')
elif path == '/123/':
conn.send(b'<h1>nothing!<h1>')
else:
conn.send(b'<h1>404! not found!<h1>')
#关闭
conn.close()
sk.close()
优化上述代码:
if path == '/111/':
response = b'<h1>successful<h1>'
elif path == '/123/':
response = b'<h1>nothing!<h1>'
else:
response = b'<h1>404! not found!<h1>'
conn.send(response)
再次优化,写入函数:
def func1():
ret = 'hello {}'.format(url)
return bytes(ret, encoding='utf8')
def func2():
return b'<h1>nothing!<h1>'
if path == '/111/':
response = func1()
elif path == '/123/':
response = func2()
else:
response = b'<h1>404! not found!<h1>'
conn.send(response)
去掉if条件:
"""
完善的web服务端示例
函数版根据不同的路径返回不同的内容
进阶函数版 不写if判断了,用url名字去找对应的函数名
"""
import socket
# 生成socket实例对象
sk = socket.socket()
# 绑定IP和端口
sk.bind(("127.0.0.1", 8001))
# 监听
sk.listen()
# 定义一个处理/yimi/的函数
def yimi(url):
ret = 'hello {}'.format(url)
return bytes(ret, encoding="utf-8")
# 定义一个处理/xiaohei/的函数
def xiaohei(url):
ret = 'hello {}'.format(url)
return bytes(ret, encoding="utf-8")
# 定义一个专门用来处理404的函数
def f404(url):
ret = "你访问的这个{} 找不到".format(url)
return bytes(ret, encoding="utf-8")
url_func = [
("/yimi/", yimi),
("/xiaohei/", xiaohei),
]
# 写一个死循环,一直等待客户端来连我
while 1:
# 获取与客户端的连接
conn, _ = sk.accept()
# 接收客户端发来消息
data = conn.recv(8096)
# 把收到的数据转成字符串类型
data_str = str(data, encoding="utf-8") # bytes("str", enconding="utf-8")
# print(data_str)
# 用
去切割上面的字符串
l1 = data_str.split("
")
# print(l1[0])
# 按照空格切割上面的字符串
l2 = l1[0].split()
url = l2[1]
# 给客户端回复消息
conn.send(b'http/1.1 200 OK
content-type:text/html; charset=utf-8
')
# 想让浏览器在页面上显示出来的内容都是响应正文
# 根据不同的url返回不同的内容
# 去url_func里面找对应关系
for i in url_func:
if i[0] == url:
func = i[1]
break
# 找不到对应关系就默认执行f404函数
else:
func = f404
# 拿到函数的执行结果
response = func(url)
# 将函数返回的结果发送给浏览器
conn.send(response)
# 关闭连接
conn.close()
3.返回html页面
"""
完善的web服务端示例
函数版根据不同的路径返回不同的内容
进阶函数版 不写if判断了,用url名字去找对应的函数名
"""
import socket
# 生成socket实例对象
sk = socket.socket()
# 绑定IP和端口
sk.bind(("127.0.0.1", 8001))
# 监听
sk.listen()
# 定义一个处理/yimi/的函数
def yimi(url):
with open('html1.html','rb') as f:
ret = f.read()
return ret
# 定义一个处理/xiaohei/的函数
def xiaohei(url):
with open('html2.html','rb') as f:
ret = f.read()
return ret
# 定义一个专门用来处理404的函数
def f404(url):
ret = "你访问的这个{} 找不到".format(url)
return bytes(ret, encoding="utf-8")
url_func = [
("/yimi/", yimi),
("/xiaohei/", xiaohei),
]
# 写一个死循环,一直等待客户端来连我
while 1:
# 获取与客户端的连接
conn, _ = sk.accept()
# 接收客户端发来消息
data = conn.recv(8096)
# 把收到的数据转成字符串类型
data_str = str(data, encoding="utf-8") # bytes("str", enconding="utf-8")
# print(data_str)
# 用
去切割上面的字符串
l1 = data_str.split("
")
# print(l1[0])
# 按照空格切割上面的字符串
l2 = l1[0].split()
url = l2[1]
# 给客户端回复消息
conn.send(b'http/1.1 200 OK
content-type:text/html; charset=utf-8
')
# 想让浏览器在页面上显示出来的内容都是响应正文
# 根据不同的url返回不同的内容
# 去url_func里面找对应关系
for i in url_func:
if i[0] == url:
func = i[1]
break
# 找不到对应关系就默认执行f404函数
else:
func = f404
# 拿到函数的执行结果
response = func(url)
# 将函数返回的结果发送给浏览器
conn.send(response)
# 关闭连接
conn.close()
返回动态的html页面
动态的html页面本质上都是字符串在服务端的替换。
#插入动态事件戳
def yimi(url):
with open('html1.html','rb') as f:
ret = f.read()
import time
ret2 = ret.replace('@@xx@@', str(time.time()))
return bytes(ret2, encoding='utf-8')
4.总结:
1. web框架的本质:
socket服务端 与 浏览器的通信
2. socket服务端功能划分:
a. 负责与浏览器收发消息(socket通信) --> wsgiref/uWsgi/gunicorn...
b. 根据用户访问不同的路径执行不同的函数
c. 从HTML读取出内容,并且完成字符串的替换 --> jinja2(模板语言)
3. Python中 Web框架的分类:
1. 按上面三个功能划分:
1. 框架自带a,b,c --> Tornado
2. 框架自带b和c,使用第三方的a --> Django
3. 框架自带b,使用第三方的a和c --> Flask
2. 按另一个维度来划分:
1. Django --> 大而全(你做一个网站能用到的它都有)
2. 其他 --> Flask 轻量级