赞
踩
目录
- 1、CS架构与BS架构
- CS即Client/Server(客户机/服务器)结构
- BS即Browser/Server(浏览器/服务器)结构
- 开发维护成本:cs开发维护成本高于bs
- 安全性:cs安全性高于bs
- 客户端负载:cs客户端负载大于bs
- 响应速度:cs相应速度高于bs
-
- 2、网络通信
- 网络=物理链接介质+互联网通信协议
- 网络存在的意义就是跨地域数据传输===>称之为通信
-
- 3、OSI七层协议
- 五层协议
- 应用层
- 传输层
- 网络层
- 数据链路层
- 物理层
- 协议:规定数据的组织格式(头部+数据部分)
-
- 3.1物理层
- 一组数据称为:位(电信号010101)
- 单纯的电信号毫无意义,必须对其进行分组
-
- 3.2数据链路层:ethernet以太网协议
- 一组数据称为:帧=头(源mac地址与目标mac地址)+数据(网络层发过来的整体内容)
- mac地址:但凡接入互联网的主机必须有一块网卡,每块网卡在出厂时都烧制好全世界独一无二的地址
- 计算机通信基本靠吼,即以太网协议的工作方式是广播
-
- 3.3网络层:IP协议
- 一组数据称为:包=头(源IP地址与目标IP地址)+数据(传输层发过来的整体内容)
- 要达到的目的:
- 划分广播域
- 每一个广播域但凡要接通外部,一定要有一个网关帮内部的计算机转发包到网上
- 网关与外界通信走的是路由协议
- 一个合法的ipv4地址=ip地址/子网掩码地址
-
- 3.4传输层:tcp\udp协议
- 一组数据称为:段=头(源port与目标port)+数据(应用层发过来的整体内容)
- 基于端口,端口范围0-65535,0-1023为系统占用端口
- ip+port ===> 标识全世界范围内独一无二的一个基于网络通信的应用程序
- 基于tcp协议通信之前:必须建立一个双向通信的链接
- 三次握手,四次挥手
- tcp是可靠传输的,发送数据必须等到对方确认后才算完成,才会将自己内存中的数据清除
- ps:当服务端大量处于TIME_WAIT状态时意味着服务端正在经历高并发
-
- 3.5应用层
- 可以自定义协议=》头部(对数据的描述信息发给谁数据的类型长度等)+数据部分
- http https ftp
-
-
-
- 总结:
- mac => 标识局域网内独一无二的一台计算机
- ip + mac => 标识全世界范围内独一无二的一台计算机
- ARP协议通过ip地址解析mac地址:
- 两台计算机在同一局域网内(源ip与目标ip网络地址一样),目标mac地址就是计算机2的mac地址
- 两台计算机不在同一局域网内(源ip与目标ip网络地址不一样),目标mac地址就是网关的mac地址
- ip => 标识全世界范围内独一无二的一台计算机
- ip + port => 标识全世界范围内独一无二的一台计算机上的一个基于网络通信的应用程序
-
- 应用层 数据
- 传输层 tcp
- 网络层 ip
- 数据链路层 ethernet
- 物理层
- (原mac地址,目标mac地址) (源ip地址,目标ip地址) (源port,目标port) 数据
- 在经由物理层转换为电信号
- import socket
-
- server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- server.bind(("127.0.0.1",8080))
- server.listen(5)
-
- # 链接循环
- while True:
- conn,addr=server.accept()
- # 通信循环
- while True:
- try:
- data=conn.recv(1024)
- conn.send(data.upper())
- except Exception:
- break
- conn.close()
- import socket
-
- client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
-
- client.connect(("127.0.0.1",8080))
- while True:
- msg=input("请输入信息:").strip()
- if msg=="":continue
- client.send(msg.encode("utf-8"))
- data=client.recv(1024)
- print(data.decode("utf-8"))
- client.close()
- import socket
-
- server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
- server.bind(("127.0.0.1",8080))
-
- while True:
- data,addr=server.recvfrom(1024)
- server.sendto(data.upper(),addr)
- import socket
-
- server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
-
- while True:
- msg=input("请输入:").strip()
- server.sendto(msg.encode("utf-8"),("127.0.0.1",8080))
- res=server.recvfrom(1024)
- print(res)
- import socket
- import os
- import json
- import struct
-
- server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- server.bind(("127.0.0.1",8080))
- server.listen(5)
-
- conn,addr=server.accept()
- while True:
- try:
- path=conn.recv(1024)
- path=path.decode("utf-8")
- filename=os.path.basename(path)
- size=os.path.getsize(filename)
-
- # 制作头:包含数据的一些信息
- header={
- "filename":filename,
- "size":size
- }
- header_str=json.dumps(header)
- header_bytes=header_str.encode("utf-8")
- # 先发送头的长度:4个字节
- x=struct.pack("i", len(header_bytes))
- conn.send(x)
- # 再发送头
- conn.send(header_bytes)
- # 再发送真实数据
- with open(path,"rb") as f:
- while True:
- msg = f.read(1024)
- if len(msg)==0:
- break
- conn.send(msg)
-
- except Exception:
- break
- conn.close()
- '''
- 粘包问题出现的原因
- 1、tcp是流式协议,数据像水流一样粘在一起没有边界区分
- 2、收数据没有收干净,残留部分会和下一次结果混在一起
- ps:
- 1、udp协议是报式协议,数据一报一报的一个recv对应一个send
- 2、收不干净就丢掉,所以没有粘包问题
- 解决粘包问题的思路:每次都收干净就行
- 1、拿到数据的总大小total_size
- 2、recv_size+=循环接收的数据,直至recv_size=total_size
- '''
- import socket
- import struct
- import json
-
- client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
-
- client.connect(("127.0.0.1",8080))
- while True:
- msg=input("请输入文件路径:").strip()
- if msg=="":continue
- client.send(msg.encode("utf-8"))
- # 先接收4个字节,获取头的长度
- x=client.recv(4)
- header_len=struct.unpack("i",x)[0]
- # 根据头的长度,再接收头
- header_bytes=client.recv(header_len)
- header_str=header_bytes.decode("utf-8")
- header=json.loads(header_str)
- # 根据头的内容,再接收真实数据
- total_size=header["size"]
- recv_size=0
- while recv_size<total_size:
- msg=client.recv(1024)
- try:
- print(msg.decode("utf-8"),end="")
- except Exception:
- pass
- recv_size+=len(msg)
- else:
- print()
- client.close()
- import socketserver
-
- class MyRequestHandler(socketserver.BaseRequestHandler):
- # 通信循环:启动一个线程进行通信循环
- def handle(self):
- # self.request => 链接对象
- # self.client_address => 客户端ip、port
- while True:
- try:
- data = self.request.recv(1024)
- self.request.send(data.upper())
- except Exception:
- break
- self.request.close()
-
- # 链接循环:从半链接池中取出链接请求,与其建立双向链接
- s=socketserver.ThreadingTCPServer(("127.0.0.1",8080),MyRequestHandler)
- s.serve_forever()
- import socket
-
- client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
-
- client.connect(("127.0.0.1",8080))
- while True:
- msg=input("请输入信息:").strip()
- if msg=="":continue
- client.send(msg.encode("utf-8"))
- data=client.recv(1024)
- print(data.decode("utf-8"))
- client.close()
- import socketserver
-
- class MyRequestHandler(socketserver.BaseRequestHandler):
- def handle(self):
- # self.request => (b'hello', <socket.socket fd=360, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>)
- # self.client_address => ('127.0.0.1', 52491)
- client_data=self.request[0]
- server=self.request[1]
- client_addr=self.client_address
- server.sendto(client_data.upper(),client_addr)
-
- s=socketserver.ThreadingUDPServer(("127.0.0.1",8080),MyRequestHandler)
- s.serve_forever()
- import socket
-
- server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
-
- while True:
- msg=input("请输入:").strip()
- server.sendto(msg.encode("utf-8"),("127.0.0.1",8080))
- res=server.recvfrom(1024)
- print(res)
- cd /home
- wget https://www.python.org/ftp/python/3.7.6/Python-3.7.6.tgz
- tar -xvf Python-3.7.6.tgz
- cd Python-3.7.6
- ./configure --prefix=/usr/local/python3
- make && make install
- vim /etc/profile
参考博客:操作系统的发展史 - JasonJi - 博客园 (cnblogs.com)
并发与并行
- 并发:看起来像同时运行的
- 并行:真正意义上的同时执行
如何实现
- 空间上的复用:多个程序共用一套计算机硬件
- 时间上的复用:切换(一个程序遇到IO操作、长时间占用cpu)+保存状态
多道技术图解
程序与进程
- 程序:躺在硬盘的一堆代码,是静态的。(程序想要被计算机运行,它的代码必须要先由硬盘读到内存,之后CPU取指令再执行)
- 进程:程序的执行过程,是动态的。(创建进程就是在内存中申请一块空间,将需要运行的代码丢进去,一个进程对应一块独立的内存空间)
进程的调度
- 先来先服务调度算法:对长作业有利,对短作业无利
- 短作业优先调度算法:对短作业有利,对长作业无利
- 时间片轮转法+多级反馈队列:
同步与异步(描述的是任务的提交方式)
- 同步:任务提交后,原地等待任务的返回结果
- 异步:任务提交之后,不原地等待任务的返回结果,任务的返回结果会有一个异步回调机制自动处理
阻塞与非阻塞 (描述的是程序的运行状态)
- 阻塞:阻塞态
- 非阻塞:就绪态、运行态
时间片轮转法+多级反馈队列
进程运行的三状态图
- from multiprocessing import Process
- import time
-
- def task(name):
- print("{} is running".format(name))
- time.sleep(3)
- print("{} is over".format(name))
-
- if __name__ == '__main__':
- # 1、创建一个进程
- p=Process(target=task,args=("Cang",))
- # 2、开启进程
- p.start()
- print("主")
- from multiprocessing import Process
- import time
-
- class MyProcess(Process):
- def run(self):
- print("aaa")
- time.sleep(3)
- print("bbb")
-
- if __name__ == '__main__':
- p=MyProcess()
- p.start()
- print("主")
- from multiprocessing import Process,current_process
- import os
- import time
-
- def func():
- # print("进程:",current_process().pid)
- print("子进程:",os.getpid()) # 查看当前进程的pid
- print("主进程:",os.getppid()) # 查看当前进程的父进程的pid
-
- if __name__ == '__main__':
- p=Process(target=func)
- p.start()
- # p.terminate() # 杀死当前进程,是告诉操作系统帮你杀死进程,但是需要一定的时间
- # print(p.is_alive()) # 判断当前进程是否存活
- p.join() # 等待子进程运行结束之后,再继续运行主进程,不影响其它子进程的运行
- import queue
- q=queue.Queue(3) # 括号内可以传数字,标示生成的队列最大可以同时存放的数据量
- q.put(111)
- q.put(222)
- q.put(333)
- # q.put(444) # 当队列为满时,等待存值
- # print(q.empty()) # 判断队列是否为空
- # print(q.full()) # 判断队列是否为满
- v1=q.get()
- v2=q.get()
- v3=q.get()
- # v4=q.get() # 当队列为空时,等待取值
- # v4=q.get(timeout=3) # 只等3s,若还没有值报错queue.Empty
- # v4=q.get_nowait() # 等都不等,没值直接报错queue.Empty
-
-
- import queue
- q=queue.LifoQueue(3)
- q.put(111)
- q.put(222)
- q.put(333)
- print(q.get())
- print(q.get())
- print(q.get())
-
-
- import queue
- q=queue.PriorityQueue(3)
- q.put((3,111))
- q.put((5,222))
- q.put((-1,333))
- print(q.get())
- print(q.get())
- print(q.get())
- from multiprocessing import Process, Queue
-
- def producer(q):
- q.put(111)
-
- def consumer(q):
- print(q.get())
-
- if __name__ == '__main__':
- q=Queue()
- p1=Process(target=producer,args=(q,))
- p2=Process(target=consumer,args=(q,))
- p1.start()
- p2.start()
- from multiprocessing import Process,JoinableQueue
- import time
- import random
-
- def producer(name,food,q):
- for i in range(3):
- data="{}生产{}{}".format(name,food,i)
- print(data)
- time.sleep(random.random())
- q.put(data)
-
- def consumer(name,q):
- while True:
- data=q.get()
- time.sleep(random.random())
- print("{}吃{}".format(name,data))
- q.task_done()
-
- if __name__ == '__main__':
- q=JoinableQueue()
- p1=Process(target=producer,args=("egon","包子",q))
- p2=Process(target=producer,args=("tank","泔水",q))
- p1.start()
- p2.start()
- p1.join()
- p2.join()
- c1=Process(target=consumer,args=("cang",q))
- c1.daemon=True
- c1.start()
- q.join()
- print("zhu")
- from multiprocessing import Process
- import time
-
- def task(name):
- print("{} is running".format(name))
- time.sleep(3)
- print("{} is over".format(name))
-
- if __name__ == '__main__':
- p=Process(target=task,args=("cang",))
- p.daemon=True # 将进程p设置成守护进程,这一句一定要放在start方法上面才有效否则会报错
- p.start()
- print("主寿终正寝")
进程:资源单位(创建一个进程就是在内存中申请一块空间将需要运行的代码丢进去)
线程:执行单位(线程指得是代码的执行过程,执行过程中需要的资源向线程所在的进程索要)为何要有线程:开设线程的开销要远远小于开设进程的开销(申请内存空间、拷贝代码)
- from threading import Thread
- import time
-
- def task(name):
- print("{} is running".format(name))
- time.sleep(1)
- print("{} is over".format(name))
-
- if __name__ == '__main__':
- t=Thread(target=task,args=("cang",))
- t.start()
- print("zhu")
- from threading import Thread
- import time
-
- class MyThread(Thread):
- def __init__(self,name):
- super().__init__()
- self.name=name
- def run(self):
- print("{} is running".format(self.name))
- time.sleep(1)
- print("{} is over".format(self.name))
-
- if __name__ == '__main__':
- t=MyThread("cang")
- t.start()
- print("zhu")
- from threading import Thread,current_thread,active_count
- import time
- import os
-
- def task(n):
- print(os.getpid())
- print(current_thread().name)
- time.sleep(n)
-
- if __name__ == '__main__':
- t1=Thread(target=task,args=(1,))
- t2=Thread(target=task,args=(2,))
- t1.start()
- t2.start()
- t1.join() # 等待子线程运行结束后再运行主线程,不影响其它子线程的运行
- print(os.getpid()) # 获取进程的pid
- print(current_thread().name) # 获取线程的名字
- print(active_count()) # 统计当前正在活跃的线程数
- from threading import Thread
-
- money=100
-
- def task():
- global money
- money=666
-
- if __name__ == '__main__':
- t=Thread(target=task)
- t.start()
- t.join()
- print(money)
- from threading import Thread
- import time
-
- def task():
- print("123")
- time.sleep(1)
- print("end123")
-
- def foo():
- print("456")
- time.sleep(3)
- print("end456")
-
- if __name__ == '__main__':
- t1=Thread(target=task)
- t2=Thread(target=foo)
- t1.daemon=True
- t1.start()
- t2.start()
- print("zhu")
- '''
- 互斥锁:
- 多个进程/线程操作同一份数据的时候,会出现数据错乱的问题
- 加锁处理,将并发变成串行,牺牲效率但是保证了数据的安全性
- '''
- from multiprocessing import Process,Lock
- import json
- import time
- import random
-
- def search(i):
- with open("a.txt",mode="rt",encoding="utf-8") as f:
- res=f.read()
- dic=json.loads(res)
- print("用户{}查询票数:{}".format(i,dic.get("ticket_num")))
-
- def buy(i):
- with open("a.txt",mode="rt",encoding="utf-8") as f:
- res=f.read()
- dic=json.loads(res)
- time.sleep(random.randint(1,3))
- if dic.get("ticket_num")>0:
- dic["ticket_num"] -= 1
- with open("a.txt",mode="wt",encoding="utf-8") as f:
- res=json.dumps(dic)
- f.write(res)
- print("用户{}买票成功".format(i))
- else:
- print("用户{}买票失败".format(i))
-
- def run(i,mutex):
- search(i)
- # 给买票环节加锁处理
- # 枪锁
- mutex.acquire()
- buy(i)
- # 释放锁
- mutex.release()
-
- if __name__ == '__main__':
- # 在主进程中生成一把锁,让所有的子进程抢,谁先抢到谁买票
- mutex=Lock()
- for i in range(1,10):
- p=Process(target=run,args=(i,mutex))
- p.start()
- '''
- GIL全局解释器锁:
- 是Cpython解释器的特点,而不是python的特点
- 保证的是解释器级别的数据安全,针对不同的数据还是需要加不同的锁来处理
- 会导致同一个进程下的多个线程无法同时执行,也就无法利用多核优势(解释型语言的通病)
- '''
- from threading import Thread, Lock
- import time
-
- money = 100
-
- def task(mutex):
- global money
- mutex.acquire()
- tem = money
- time.sleep(0.01)
- money = tem - 1
- mutex.release()
-
- if __name__ == '__main__':
- mutex = Lock()
- t_list = []
- for i in range(100):
- t = Thread(target=task, args=(mutex,))
- t.start()
- t_list.append(t)
- for t in t_list:
- t.join()
- print(money)
-
- '''
- 100个线程起起来之后,去抢GIL
- 我抢到了GIL,又抢到了互斥锁(无人争抢,其它线程还在等着抢GIL)
- 我进入IO 自动释放GIL,其它线程虽然抢到了GIL但是抢不到互斥锁,最后还是乖乖释放GIL
- 我又抢到了GIL,释放互斥锁,释放GIL
- '''
- '''
- 死锁:
- 我手上有锁A,然后去抢锁B
- 你手上有锁B,然后去抢锁A
- 递归锁:
- 可以被连续的acquire和release
- 每acquire一次计数加一,每release一次计数减一
- 只要计数不为0,那么其他人都无法抢到该锁
- '''
- from threading import Thread, RLock
- import time
-
- mutexB = mutexA = RLock()
-
- class MyThread(Thread):
- def __init__(self, name):
- super().__init__()
- self.name = name
-
- def run(self):
- self.task1()
- self.task2()
-
- def task1(self):
- mutexA.acquire()
- print("线程{}抢到锁A".format(self.name))
- mutexB.acquire()
- print("线程{}抢到锁B".format(self.name))
- mutexB.release()
- print("线程{}释放锁B".format(self.name))
- mutexA.release()
- print("线程{}释放锁A".format(self.name))
-
- def task2(self):
- mutexB.acquire()
- print("线程{}抢到锁B".format(self.name))
- time.sleep(1)
- mutexA.acquire()
- print("线程{}抢到锁A".format(self.name))
- mutexA.release()
- print("线程{}释放锁A".format(self.name))
- mutexB.release()
- print("线程{}释放锁B".format(self.name))
-
- if __name__ == '__main__':
- for i in range(10):
- t = MyThread(i)
- t.start()
- '''
- 信号量:
- 在不同的阶段可能对应不同的技术点,在并发编程中指的是锁
- 如果将互斥锁比成一个坑的话,那么信号量就相当于多个坑
- '''
- from threading import Thread, Semaphore
- import time
- import random
-
- sp = Semaphore(5) # 坑位
-
- def task(name):
- sp.acquire()
- print("线程{}在蹲坑".format(name))
- time.sleep(random.randint(1,3))
- sp.release()
-
- if __name__ == '__main__':
- for i in range(20):
- t=Thread(target=task,args=(i,))
- t.start()
- '''
- Event事件:
- 一些进程/线程需要等待另外一些进程/线程运行完毕之后才能运行,类似发射信号
- '''
- from threading import Thread, Event
- import time
-
- sub=Event()
-
- def light():
- print("红灯亮")
- time.sleep(3)
- print("绿灯亮")
- sub.set()
-
- def car(name):
- print("{}等待绿灯".format(name))
- sub.wait()
- print("{}加油门飙起来".format(name))
-
- if __name__ == '__main__':
- t=Thread(target=light)
- t.start()
- for i in range(20):
- t=Thread(target=car,args=(i,))
- t.start()
- '''
- 同一个进程下的多个线程无法利用多核优势,那么多线程是不是没有用了
- 计算密集型(多核四个任务)
- 多进程:总耗时10+
- 多线程:总耗时40+
- IO密集型(多核四个任务)
- 多进程:相对浪费资源
- 多线程:相对节省资源
- 总结:多进程和多线程都有各自的优势,通常使用多进程下开设多线程,这样既可以利用多核也可以减少资源消耗
- '''
- from multiprocessing import Process
- from threading import Thread
- import time
- import os
-
- def task():
- # m = 1
- # for i in range(1, 100000):
- # m *= i
- time.sleep(0.01)
-
- if __name__ == '__main__':
- start_time=time.time()
- print(os.cpu_count())
- p_list = []
- for i in range(10):
- # p = Process(target=task)
- # p.start()
- # p_list.append(p)
- t=Thread(target=task)
- t.start()
- p_list.append(t)
- for p in p_list:
- p.join()
- print(time.time()-start_time)
- '''
- 进程池与线程池:
- 在保证计算机安全的情况下,最大限度的利用计算机
- 虽然降低了效率,但是它保证了计算机的安全
- '''
- from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
- import time
-
- def task(n):
- print(n)
- time.sleep(2)
- return "===>:{}".format(n ** 2)
-
- def call_back(res):
- print(res.result())
-
- if __name__ == '__main__':
- pool = ThreadPoolExecutor(5)
- for i in range(20):
- res = pool.submit(task, i)
- res.add_done_callback(call_back)
- '''
- 进程:资源单位
- 线程:执行单位
- 协程:单线程实现并发
- 本来cpu遇到IO或者长时间被占用,需要进行切换
- 但是我们程序员自己在代码层面上检测所以的IO操作,一旦遇到IO了我们在代码级别完成切换
- 这样给cpu的感觉就是没有遇到IO,从而提高了程序的运行效率
- '''
- # import time
- # def task1():
- # for i in range(10000000):
- # i+1
- # def task2():
- # for i in range(10000000):
- # i+1
- #
- # start_time=time.time()
- # task1()
- # task2()
- # print(time.time()-start_time) # 1.5311427116394043
-
- # import time
- # def task1():
- # for i in range(10000000):
- # i + 1
- # yield
- # def task2():
- # t = task1()
- # for i in range(10000000):
- # i + 1
- # next(t)
- #
- # start_time = time.time()
- # task2()
- # print(time.time() - start_time) # 2.8123199939727783
- # 总结:计算密集型任务,切换会降低效率
-
- # import time
- #
- # def task1():
- # print("hello")
- # time.sleep(2)
- # def task2():
- # print("world")
- # time.sleep(3)
- # start_time = time.time()
- # task1()
- # task2()
- # print(time.time() - start_time) # 5.0310328006744385
-
- from gevent import monkey;monkey.patch_all()
- from gevent import spawn
- import time
-
- def task1():
- print("hello")
- time.sleep(2)
- def task2():
- print("world")
- time.sleep(3)
- start_time = time.time()
- s1=spawn(task1)
- s2=spawn(task2)
- s1.join()
- s2.join()
- print(time.time() - start_time) # 3.031080722808838
5.1、阻塞模型
- import socket
-
- server=socket.socket()
- server.bind(("127.0.0.1",8080))
- server.listen(5)
-
- while True:
- conn,addr=server.accept()
- while True:
- try:
- data=conn.recv(1024)
- conn.send(data.upper())
- except Exception:
- break
- conn.close()
- import socket
-
- client=socket.socket()
-
- client.connect(("127.0.0.1",8080))
- while True:
- client.send("hello".encode("utf-8"))
- data=client.recv(1024)
- print(data.decode("utf-8"))
5.2、非阻塞模型
- '''
- 虽然非阻塞IO模型给你的感觉很牛逼
- 但是该模型会长时间占用cpu而不干活
- '''
-
- import socket
-
- server=socket.socket()
- server.bind(("127.0.0.1",8080))
- server.listen(5)
- server.setblocking(False)
-
- r_list=[]
- del_list=[]
- while True:
- try:
- conn,addr=server.accept()
- r_list.append(conn)
- except BlockingIOError:
- for conn in r_list:
- try:
- data = conn.recv(1024)
- conn.send(data.upper())
- except BlockingIOError:
- continue
- except ConnectionRefusedError:
- conn.close()
- del_list.append(conn)
- continue
- for conn in del_list:
- r_list.remove(conn)
- del_list.clear()
- import socket
-
- client=socket.socket()
-
- client.connect(("127.0.0.1",8080))
- while True:
- client.send("hello".encode("utf-8"))
- data=client.recv(1024)
- print(data.decode("utf-8"))
5.3、IO多路复用
- '''
- select机制 windows、linux都有
- poll机制 只有linux有
- select和poll都可以监管多个对象,但是poll监管的数量更多
- 上述两个机制对于监管特别多的对象时,会出现相当大的延时响应
-
- epoll机制 只有linux有
- 它给每个对象都绑定了一个回调机制,一旦有响应回调机制立刻发起提醒
- 针对不同的操作系统还要考虑不同的监管机制,书写代码太过繁琐
- 这是有一个人跳出来了(selectors模块)能够根据你跑的平台不同,自动帮你选择对应的监管机制
- '''
- import socket
- import select
-
- server=socket.socket()
- server.bind(("127.0.0.1",8080))
- server.listen(5)
- server.setblocking(False)
-
- read_list = [server] # 将server对象添加到监管列表中
- while True:
- r_list,w_list,x_list=select.select(read_list,[],[]) # 操作系统会监管这些对象,返回可执行的对象
- for i in r_list: # 针对不同的对象作不同的操作
- if i is server: # 针对可执行的server对象,建立链接,并将该链接对象conn添加到监管列表中
- conn,addr=i.accept()
- read_list.append(conn)
- else: # 针对可执行的conn对象,进行接收数据操作
- try:
- data=i.recv(1024)
- conn.send(data.upper())
- except Exception:
- i.close()
- read_list.remove(i)
- import socket
-
- client=socket.socket()
-
- client.connect(("127.0.0.1",8080))
- while True:
- client.send("hello".encode("utf-8"))
- data=client.recv(1024)
- print(data.decode("utf-8"))
5.4、异步IO
异步IO模型是所有模型中效率最高的,也是应用最广泛的
相关的模块与框架
模块:asyncio
框架:sanic tronado twisted
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。