前倾回顾
1.总结进程线程的区别
2.网络通信模型
[1] 循环模型:循环接收请求处理请求,每次同时只能处理一个请求
[2]IO并发模型,可以同时处理多个IO请求
[3]多进程/多线程网络并发:可以互不影响处理多个任务
3.基于fork的多进程并发
4.ftp文件服务模型
*****************************************************
一.基于threading的多线程网络并发
[1]实现原理:每当一个客户端发起请求,就创建一个新的线程处理客户端具体请求,主线程循环等待处理其他客户端连接。
[2]实现步骤:
1.创建监听套接字
2.循环接收客户端请求连接
3.当有新的客户端连接创建线程处理客户端请求
4.主线程继续等待其他客户端连接
5.当客户端退出,则对应
二.集成模块完成多进程/多线程网并发
1. import sockectserver
*通过模块提供的不同的类的组合来完成多进程或者多线程
.tcp 或udp的网路并发模型
2.常用类说明
TCPServer:创建TCP服务端套接字
UDPServer:创建UDP服务端套接字
StreamRequestHandler:处理TCP客户端请求
DatageramRequestHandler:处理udp客户端请求
ForkingMinIn :创建多进程并发
ForkingTCPServer :ForkingMinIn + TCPServer
ForkingUDPServer :ForkingMinIn + UDPServer
ThreadingMixIn :创建多线程并发
ThreadingTCPServer :ThreadingMixIn + TCPServer
ThreadingUDPServer :ThreadingMixIn + UDPServer
3.步骤
1.创建服务器类,通过选择继承的类,决定创建TCP或者UDP,
多进程或者多线程确定定法类型
2.创建请求处理类,根据服务类型选择stream处理类还是Datager处理类。重写handle方法,左具体的请求处理
3. 通过服务器类创建服务器对象,并绑定请求处理类
4.通过富强武器对象,调用server_forever()启动服务
三.HTTPServer v2.0
1.主要功能:
1.接收客户端(浏览器)请求
2.解析客户端发送的请求
3.根据请求组织数据内容
4.将数据内容形参http响应格式返回给浏览器
2.升级点
1.采用多线程并发,可以满足多个客户端同时同时发起请求情况
2.做基本的请求解析,根据具体的请求返回具体内容,
同时满足客户端点单的非网页请求情况
3.通过类接口形式进行功能封装
3.技术点
1.HTTP协议要求数据传输使用tcp套接字
2.httpserver采用多线程并发网络模型
3.类的封装接口
4.http协议的请求和响应格式
http请求:
请求行:GET /abc.html HTTP/1.1
请求头:
空行
请求体
http响应:
响应行:HTTP/1.1 200 OK
响应头
空行
响应体:返回的数据内容
1 ''' 2 HTTP Server v2.0 3 *多线程并发 4 *基本的request解析 5 *能够反馈基本数据 6 *使用类封装 7 ''' 8 9 from socket import * 10 from threading import Thread 11 import sys 12 13 14 #封装具体的类作为THHP Server功能模块 15 class HTTPServer(object): 16 def __init__(self,server_addr,static_dir): 17 #添加对象属性 18 self.server_address = server_addr#属性 19 self.static_dir = static_dir 20 self.create_socket() 21 self.bind() 22 23 def create_socket(self): 24 self.sockfd = socket() 25 self.sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) 26 27 def bind(self): 28 self.sockfd.bind(self.server_address) 29 self.ip = self.server_address[0] 30 self.port =self.server_address[1] 31 #启动服务 32 def serve_forever(self): 33 self.sockfd.listen(5) 34 print('Listen the port %d'%self.port) 35 while True: 36 try: 37 connfd,addr = self.sockfd.accept() 38 except KeyboardInterrupt: 39 self.sockfd.close() 40 sys.exit("退出服务器") 41 except Exception as e: 42 print("Error:",e) 43 continue 44 #创建多线程处理请求 45 clientThread = Thread(target = self.handle,args=(connfd,)) 46 clientThread.setDaemon(True) 47 clientThread.start() 48 49 #具体处理thhp请求 50 def handle(self,connfd): 51 #接受HTTP请求 52 request = connfd.recv(4096) 53 #防止浏览器异常断开 54 if not request: 55 connfd.close() 56 return 57 #请求解析 58 requestHeaders = request.splitlines() 59 print(connfd.getpeername(),":",requestHeaders[0]) 60 #获取请求内容 61 getRequest = str(requestHeaders[0]).split(' ')[1] 62 63 if getRequest =='/' or getRequest[-5:]=='.html': 64 self.get_html(connfd,getRequest) 65 else: 66 print("想获取其他内容") 67 connfd.close() 68 69 def get_html(self,connfd,getRequest): 70 if getRequest =='/': 71 filename = self.static_dir + '/manager.html' 72 else: 73 filename =self.static_dir + getRequest 74 try: 75 f = open(filename) 76 except IOError: 77 #没有找到网页 78 responseHeaders = "HTTP/1.1 404 Not Found\r\n" 79 responseHeaders += '\r\n' 80 responseBody = "Sorry,Not found the page" 81 else: 82 #返回网页内容 83 responseHeaders = "HTTP/1.1 200 OK\r\n" 84 responseHeaders +="\r\n" 85 responseBody = f.read() 86 finally: 87 response = responseHeaders + responseBody 88 connfd.send(response.encode())#发给客户端 89 90 def get_data(self,connfd,getRequest): 91 responseHeaders = "HTTP/1.1 200 OK\r\n" 92 responseHeaders += '\r\n' 93 responseBody ="<p>waiting httpserver v3.0</p>" 94 response = responseHeaders + responseBody 95 connfd.send(response.encode())#发给客户端 96 97 98 if __name__=="__main__": 99 #使用者自己设定ress 100 server_addr = ('0.0.0.0',8000) 101 #用户提供存放网页的目录 102 static_dir ="./static" 103 #创富强武器对象 104 httpd = HTTPServer(server_addr,static_dir) 105 #启动服务 106 httpd.serve_forever() 107http_server.py
四. 协程技术
1.定义:纤程。微线程。是为非抢占多任务产生子程序的计算机组件。
协程允许不同入口点在不同位置暂停或开始,
简单来说,
协程就是可以暂停的执行的函数
* yield可以实现上述函数暂停执行功能,
即yield是python内部实现协程的基础关键字
*协程的本质其实是一个单线程程序,不会使用计算机多核资源
2.协程原理:记录一个函数的上下文栈帧,协程调度切换时会记录的上下文保存,
在切换回来时进行调取,恢复原有的执行内容,
以便从上一次执行位置继续执行
3.协程优缺点
优点:【1】协程完成多任务占用计算资源很少
【2】由于协程的多任务切换在应用层完成,因此切换开销少
【3】协程为单线程程序,无需进程共享资源同步互斥处理
缺点:【1】无法利用计算机的多核资源
4.利用协程模块完成协程
【1】greenlet模块
1.安装 sudo pip3 install greenlet
2.函数
greenlet.greenlet(func)
功能:创建协程对象
参数:协程函数
g.switch()
功能:选择要执行的协程函数
1 from greenlet import greenlet 2 3 def test1(): 4 print("执行test1") 5 gr2.switch() 6 print("结束test2") 7 gr2.switch() 8 9 def test2(): 10 gr1.switch() 11 print("执行test1") 12 print("结束test2") 13 14 #将函数变为协程 15 gr1 = greenlet(test1) 16 gr2 = greenlet(test2) 17 18 19 #启动协程 20 gr1.switch() #执行协程1greelet0.py
【2】gevent
1.安装:sudo pip3 install gevent
2.函数:
gevent.spawn(func,argv)
功能:生成协程对象
参数:func 协程函数
argv 给协程函数传参(不定参)
返回值:协程对象
gevent.joinall(list,[timeout])
功能:阻塞等待协程执行完毕
参数:list 协程对象列表
timeout 超时时间
gevent.sleep(sec)
功能:gevent睡眠阻塞
参数:睡眠时间
* gevent协程 只有在遇到gevent指定的阻塞行为时才会自动在协程之间进行跳转
如:gevent.joinall(),gevent.sleep()带来阻塞
1 import gevent 2 from gevent import spawn 3 4 def foo(): 5 print("Running foo") 6 gevent.sleep(3) 7 print("Foo again") 8 9 def bar(): 10 print("Running bar") 11 gevent.sleep(2) 12 print("Bar again") 13 14 f = gevent.spawn(foo) 15 b = gevent.spawn(bar) 16 gevent.joinall([f,b]) 17 18 # from gevent import spawn,sleep,joinall 19 20 # def foo(): 21 # print("Running foo") 22 # sleep(3) 23 # print("Foo again") 24 25 # def bar(): 26 # print("Running bar") 27 # sleep(2) 28 # print("Bar again") 29 # f = spawn(foo) 30 # b = spawn(bar) 31 # joinall([f,b]) 32gevrnt_1.py
作业:1.梳理之前的项目代码思路
2.复习mysql数据库用法
1 ''' 2 HTTP Server v2.0 3 *多线程并发 4 *基本的request解析 5 *能够反馈基本数据 6 *使用类封装 7 ''' 8 9 from socket import * 10 from threading import Thread 11 import sys 12 13 14 #封装具体的类作为THHP Server功能模块 15 class HTTPServer(object): 16 def __init__(self,server_addr,static_dir): 17 #添加对象属性 18 self.server_address = server_addr#属性 19 self.static_dir = static_dir 20 self.create_socket() 21 self.bind() 22 23 def create_socket(self): 24 self.sockfd = socket() 25 self.sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) 26 27 def bind(self): 28 self.sockfd.bind(self.server_address) 29 self.ip = self.server_address[0] 30 self.port =self.server_address[1] 31 #启动服务 32 def serve_forever(self): 33 self.sockfd.listen(5) 34 print('Listen the port %d'%self.port) 35 while True: 36 try: 37 connfd,addr = self.sockfd.accept() 38 except KeyboardInterrupt: 39 self.sockfd.close() 40 sys.exit("退出服务器") 41 except Exception as e: 42 print("Error:",e) 43 continue 44 #创建多线程处理请求 45 clientThread = Thread(target = self.handle,args=(connfd,)) 46 clientThread.setDaemon(True) 47 clientThread.start() 48 49 #具体处理thhp请求 50 def handle(self,connfd): 51 #接受HTTP请求 52 request = connfd.recv(4096) 53 #防止浏览器异常断开 54 if not request: 55 connfd.close() 56 return 57 #请求解析 58 requestHeaders = request.splitlines() 59 print(connfd.getpeername(),":",requestHeaders[0]) 60 #获取请求内容 61 getRequest = str(requestHeaders[0]).split(' ')[1] 62 63 if getRequest =='/' or getRequest[-5:]=='.html': 64 self.get_html(connfd,getRequest) 65 else: 66 print("想获取其他内容") 67 connfd.close() 68 69 def get_html(self,connfd,getRequest): 70 if getRequest =='/': 71 filename = self.static_dir + '/manager.html' 72 else: 73 filename =self.static_dir + getRequest 74 try: 75 f = open(filename) 76 except IOError: 77 #没有找到网页 78 responseHeaders = "HTTP/1.1 404 Not Found\r\n" 79 responseHeaders += '\r\n' 80 responseBody = "Sorry,Not found the page" 81 else: 82 #返回网页内容 83 responseHeaders = "HTTP/1.1 200 OK\r\n" 84 responseHeaders +="\r\n" 85 responseBody = f.read() 86 finally: 87 response = responseHeaders + responseBody 88 connfd.send(response.encode())#发给客户端 89 90 def get_data(self,connfd,getRequest): 91 responseHeaders = "HTTP/1.1 200 OK\r\n" 92 responseHeaders += '\r\n' 93 responseBody ="<p>waiting httpserver v3.0</p>" 94 response = responseHeaders + responseBody 95 connfd.send(response.encode())#发给客户端 96 97 98 if __name__=="__main__": 99 #使用者自己设定ress 100 server_addr = ('0.0.0.0',8000) 101 #用户提供存放网页的目录 102 static_dir ="./static" 103 #创富强武器对象 104 httpd = HTTPServer(server_addr,static_dir) 105 #启动服务 106 httpd.serve_forever() 107http_server.py