4. web服务
4.1 HTTP协议
4.1.1 协议概述
-
用途 : 网页获取,数据的传输
-
特点
-
应用层协议,使用tcp进行数据传输
-
简单,灵活,很多语言都有HTTP专门接口
-
有丰富的请求类型
-
可以传输的数据类型众多
-
4.1.2 网页访问流程
-
客户端(浏览器)通过tcp传输,发送http请求给服务端
-
服务端接收到http请求后进行解析
-
服务端处理请求内容,组织响应内容
-
服务端将响应内容以http响应格式发送给浏览器
-
浏览器接收到响应内容,解析展示
4.1.2 HTTP请求
-
请求行 : 具体的请求类别和请求内容
GET / HTTP/1.1 请求类别 请求内容 协议版本
请求类别:每个请求类别表示要做不同的事情
GET : 获取网络资源 POST :提交一定的信息,得到反馈 HEAD : 只获取网络资源的响应头 PUT : 更新服务器资源 DELETE : 删除服务器资源
-
请求头:对请求的进一步解释和描述(例如什么时间用什么浏览器发给服务器的)
eg.Accept-Encoding: gzip 一行行键值对构成
-
空行
-
请求体: 请求参数或者提交内容
4.1.3 HTTP响应
-
响应行 : 反馈基本的响应情况
HTTP/1.1 200 OK 版本信息 响应码 附加信息
响应码 :
1xx 提示信息,表示请求被接收 2xx 响应成功 3xx 响应需要进一步操作,即二次处理重定向 4xx 客户端错误 5xx 服务器错误
-
响应头:对响应内容的描述 ----详细解释给你的响应是什么格式,大小等信息
eg.Content-Type: text/html ---以网页格式解析
-
空行
-
响应体:响应的主体内容信息
""" http 请求和响应 """ from socket import * # 创建tcp套接字 sock = socket() sock.bind(("0.0.0.0", 8888)) sock.listen(5) # 等待浏览器连接 connfd, addr = sock.accept() print("Connect from", addr) # 接收HTTP请求 request = connfd.recv(1024) print(request.decode()) # 组织响应格式 response = """HTTP/1.1 200 OK Content-Type:text/html Hello World """ connfd.send(response.encode()) # 发送响应 connfd.close() sock.close()
""" 练习: 根据所学http协议完成 通过浏览器访问服务端,请求根 则会 显示一张图片在浏览器上 ,图片自选 Content-Type:image/jpeg """ from socket import * def get_response(filename): response = "HTTP/1.1 200 OK\r\n" response += "Content-Type:image/jpeg\r\n" response += "\r\n" with open(filename, 'rb') as file: response = response.encode() + file.read() return response # 字节串 def main(): sock = socket() sock.bind(("0.0.0.0", 8000)) sock.listen(5) while True:#浏览器可以多个页面循环访问 connfd, addr = sock.accept() print("Connect from", addr) # 接收请求 request = connfd.recv(1024) print(request.decode()) response = get_response("yaya.jpeg")#前端工程师提供图像信息 connfd.send(response) # 字节串 if __name__ == '__main__': main()
4.2 web 服务项目实现
-
主要功能 : 【1】 接收客户端(浏览器)请求
【2】 解析客户端发送的请求
【3】 根据请求组织数据内容
【4】 将数据内容形成http响应格式返回给浏览器
-
主要特点 :
【1】 采用IO并发,可以满足多个客户端同时发起请求情况
【2】 通过类接口形式进行功能封装
【3】 做基本的请求解析,根据具体请求返回具体内容,同时可以满足客户端的网页效果加载
""" web sever 服务 """ from socket import * from select import select import os # 具体处理http请求 class Handle: def __init__(self, html): self.html = html def _response(self, status, filename): response = "HTTP/1.1 %s\r\n" % status response += "Content-Type:text/html\r\n" response += "\r\n" with open(filename, 'rb') as file: response = response.encode() + file.read() return response def _send_response(self, connfd, info): # 请求的是 首页 还是 其他网页 if info == '/': filename = self.html + "/index.html" else: filename = self.html + info # 判断是否存在 True / False if os.path.exists(filename): data = self._response("200 OK", filename) else: data = self._response("404 Not Found", self.html + "/404.html") connfd.send(data) # 发送响应 def handle(self, connfd): # 接收HTTP请求 request = connfd.recv(1024).decode() if not request: return # 获取请求内容 info = request.split(" ")[1] print('请求内容:', info) # 组织响应并发送 self._send_response(connfd, info) class WebServer: # 实例化对象过程中做好准备工作 def __init__(self, host='', port=0, html=None): self.host = host self.port = port self.address = (host, port) self.html = html # 用户提供的网页 self.rlist = [] self.handle = Handle(html) self.sock = self._create_socket() # 创建套接字 def _create_socket(self): sock = socket() sock.bind(self.address) sock.setblocking(False) # 非阻塞 return sock # 连接浏览器 def _connect(self): connfd, addr = self.sock.accept() connfd.setblocking(False) self.rlist.append(connfd) # 增加关注 # start启动函数过程中 搭建服务 IO并发模型 def start(self): self.sock.listen(5) print("Listen the port %d" % self.port) self.rlist.append(self.sock) # 初始关注监听套接字 # 循环接收监控IO发生 while True: rs, ws, xs = select(self.rlist, [], []) for r in rs: if r is self.sock: self._connect() # 处理连接 else: try: self.handle.handle(r) # 处理http请求 except: pass self.rlist.remove(r) # 短连接场景,处理完即关闭 r.close() if __name__ == '__main__': # 先想一下怎么用 # 什么需要用户决定: 服务器地址 内容 httpd = WebServer(host="0.0.0.0", port=8888, html="./static") httpd.start() # 启动服务
5. 高并发技术探讨
5.1 高并发问题
-
衡量高并发的关键指标
-
响应时间(Response Time) : 接收请求后处理的时间
-
同时在线用户数量:同时连接服务器的用户的数量
-
每秒查询率QPS(Query Per Second): 每秒接收请求的次数
-
每秒事务处理量TPS(Transaction Per Second):每秒处理请求的次数(包含接收,处理,响应)
-
吞吐量(Throughput): 响应时间+QPS+同时在线用户数量
-
-
多大的并发量算是高并发
-
没有最高,只要更高
比如在一个小公司可能QPS2000+就不错了,在一个需要频繁访问的门户网站可能要达到QPS5W+
-
C10K问题
早先服务器都是单纯基于进程/线程模型的,新到来一个TCP连接,就需要分配1个进程(或者线程)。而进程占用操作系统资源多,一台机器无法创建很多进程。如果是C10K就要创建1万个进程,那么单机而言操作系统是无法承受的,这就是著名的C10k问题。创建的进程线程多了,数据拷贝频繁, 进程/线程切换消耗大, 导致操作系统崩溃,这就是C10K问题的本质!
-
5.2 更高并发的实现
为了解决C10K问题,现在高并发的实现已经是一个更加综合的架构艺术。涉及到进程线程编程,IO处理,数据库处理,缓存,队列,负载均衡等等,这些我们在后面的阶段还会学习。此外还有硬件的设计,服务器集群的部署,服务器负载,网络流量的处理等。
实际工作中,应对更庞大的任务场景,网络并发模型的使用有时也并不单一。比如多进程网络并发中每个进程再开辟线程,或者在每个进程中也可以使用多路复用的IO处理方法。
前情回顾
1. IO多路复用
利用系统内核的IO监控功能 ,哪个IO就绪就处理哪个IO
对象,形成多个IO可以 "同时" 处理多个IO
IO多路是单进程,资源占用少,但是只能处理简单的IO操作
2. select epoll
select: 平台支持好,但是同时监控IO数量有限,效率没有
epoll高
epoll : 效率高,支持同时监控IO数量多,但是只用于Linux
3. 使用IO多路复用实现网络并发
4. HTTP 协议
应用层 tcp传输 简单方便 请求类型多
HTTP协议使用: 传输数据 访问网站
网页访问流程
练习: 根据所学http协议完成
通过浏览器访问服务端,请求根 则会
显示一张图片在浏览器上 ,图片自选
Content-Type:image/jpeg
webserver 模块
需求分析
接收客户端(浏览器)请求
解析客户端发送的请求
根据请求组织数据内容
将数据内容形成http响应格式返回给浏览器
技术 : IO多路复用并发网络 : select
TCP
模块封装 : 类
协议 : HTTP协议
类接口设计 :
socket : 生成对象,使用对象灵活的调用各种方法
组合,就会产生不同的功能效果
Process : 生成对象,调用方法启动功能 (如果多
调用方法也是为主体功能服务的),能为用户决定就帮他决定
不能替用户决定需要用户传参
核心编程
1. 网络编程
网络基础知识:
1. TCP/IP模型和OSI七层模型
2. 三次握手和四次挥手过程
3. tcp和udp的区别
4. http协议的特点和请求响应格式
socket 模块
tcp套接字编程 (重点)
udp套接字编程 (重点)
2. 进程和线程
基础概念
1. 进程与线程的特点和区别
2. 理解什么是进程和进程状态
多进程 (包括自定义进程类) 重点,难点
multiprocessing
多线程 (包括同步互斥方法) 重点
threading
GIL
3. IO模型
阻塞IO
非阻塞IO
IO多路复用 (重点,难点)
select
epoll
4. 网络并发模型
多进程多线程并发 (重点)
IO多路复用并发 (重点)
5. 综合代码
学生管理系统 :
文件 正则 函数编程
群聊聊天室 :
udp 多进程 函数编程
通信协议请求 "总分结构"
ftp文件服务器
tcp 多线程并发模型 面向对象
通信协议响应 请求应答的模式
webserver
tcp IO多路复用并发模型 设计类接口
类的设计思路
<核心编程 第三版>
<图解TCP/IP>
<图解HTTP>
作业: 1. webserver自己写一下
2. github.com
gitee.com