目录python
C/S: Client: 客户端 Server: 服务端 优势: 占用网络资源少,软件的使用稳定 缺点: 服务端更新后,客户端也得跟着跟新. 须要使用多个软件,须要下载多个客户端 B/S: Browser: 浏览器(客户端) Server: 服务端 服务端与客户端做用: 服务端: 24小时不间断提供服务 客户端: 须要体验服务端时,再去链接服务端,并享受服务
一 网络编程:
1.互联网协议OSI七层协议
1)应用层
2)表示层
3)会话层
4)传输层
5)网络层
6)数据链路层
7)物理链接层程序员
- 物理链接层 基于电信号发送二进制数据. - 数据链路层 1) 规定好电信号的分组方式 2) 必需要有一块网卡: - mac地址: 12位惟一的16进制字符串 - 前6位: 厂商号 - 后6位: 流水号 - 以太网协议: 在同一个局域网内通讯. - 单播 1对1吼 - 广播 多对多吼 - 广播风暴: - 不能跨局域网通讯 - 网络层 - ip: 定位局域网的位置 - port: 惟一标识一台计算机上一个应用程序. - arp协议: 将mac地址获取,并解析成ip和port. - 传输层 - TCP 特色: TCP协议称之为流式协议. 若想要通讯,必须创建链接,并创建双向通道. - 三次握手,四次挥手 - 三次握手建链接 - 客户端往服务端发送请求创建通道 - 服务端要确认客户端的请求,并往客户端也发送请求创建通道 - 客户端接收到服务端创建链接的请求,并返回确认 - 创建双向通道 - 双向通道: - 反馈机制 客户端往服务端发送请求获取数据,服务端务必返回数据,客户端确认收到. 反则会反复发送,一直到某个时间段内,会中止发送 - 四次挥手断链接 - C往S发送断开链接请求,S返回确认收到 - S须要再次发送断开链接请求 - C返回确认收到 - 最终确认断开链接 - UDP 1)数据不安全 2)不须要创建双向通道 3)传输速度快 4)不会有粘包问题 5)客户端发送数据,不须要服务端确认收到,爱收不收 TCP与UPD的区别: TCP: 比喻成在打电话 UDP: 比喻成发送短信 - 应用层 - ftp - http: 能够携带一堆数据 - http + ssl 2.socket socket用来写套接字客户端与服务端的模块,内部帮咱们封装好了7层协议须要作的事情. 3.手撸socket套接字模板 - 服务端: import socket server = socket.socket() server.bind( (ip, port) ) # 绑定手机号 server.listen(6) # 半链接池: 能够接待7个客户端 # 监听链接 conn, addr =server.accept() # 接收消息 data = conn.recv(1024) # 发送消息 conn.send('消息内容'.encode('utf-8')) - 客户端: import socket client = socket.socket() client.connect( (ip, port) ) # 发送消息 client.send() # 接收消息 client.recv(1024) 4.subprocess(了解) 用来经过代码往cmd建立一个管道,而且发送命令和接收cmd返回的结果. import subprocess obj = subprocess.Popen( 'cmd命令', shell=True, # 接收正确结果 stdout=subprocess.PIPE, # 接收错误结果 stderr=subprocess.PIPE ) success = obj.stdout.read() error = obj.stderr.read() msg = success + error 5.黏包问题 1.不能肯定对方发送数据的大小 2.在短期内,间隔时间短,而且数据量小的状况, 默认将这些数据打包成一个 屡次发送的数据 ---> 一次性发送 6.struct解决黏包问题 初级版: i: 4 能够将一个数据的长度打包成一个固定长度的报头. struct.pack('模式i', '源数据长度') data = 'gagawagwaga' # 打包成报头 headers = struct.pack('i', len(data)) # 解包获取数据真实长度 data = struct.unpack('i', headers)[0] 注意: 以什么方式打包,必须以什么方式解包. 升级版: 先将数据存放到字典中,将字典打包发送过去 - 字典的好处: - 真实数据长度 - 文件的描述信息 - 发送的数据,更小 dic = { 'data_len': 1000000000000000000000046546544444444444444444444444444444444444444, 文件的描述信息 } 7.上传大文件数据 # 客户端 dic = { 文件大小, 文件名 } with open(文件名, 'rb') as f: for line in f: client.send(line) # 服务端 dic = { 文件大小, 文件名 } init_recv = 0 with open(文件名, 'wb') as f: while init_recv < 文件大小: data = conn.recv(1024) f.write(data) init_recv += len(data) 10.socketserver(现阶段,了解) - 能够支持并发 import socketserver # 定义类 # TCP: 必须继承BaseRequestHandler类 class MyTcpServer(socketserver.BaseRequestHandler): - handle # 内部实现了 server = socket.socket() server.bind( ('127.0.0.1', 9527) ) server.listen(5) --- while True: conn, addr = server.accept() print(addr) # 必须重写父类的handle, 当客户端链接时会调用该方法 def handle(self): print(self.client_address) while True: try: # 1.接收消息 # request.recv(1024) == conn.recv(1024) data = self.request.recv(1024).decode('utf-8') send_msg = data.upper() self.request.send(send_msg.encode('utf-8')) except Exception as e: print(e) break TCP: SOCK_STREAM conn.recv() UDP模板: SOCK_DGRAM server.recvfrom() - 服务端 import socket server = socket.socket( type=socket.SOCK_DGRAM ) server.bind( (ip, port) ) data, addr = server.recvfrom(1024) server.sendto(data, addr) - 客户端 import socket client = socket.socket( type=socket.SOCK_DGRAM ) ip_port = (ip, port) client.sendto(data, ip_port) data, _ = client.recvfrom(1024) print(data)
二 并发编程
12.多道技术
- 单道shell
- 多道: 切换 + 保存状态 - 空间上的复用 支持多个程序使用 - 时间上的复用 - 遇到IO操做就会切换程序 - 程序占用CPU时间过长切换 13.并发与并行 并发: 看起来像同时运行: 多道技术 并行: 真正意义上的同时运行: 多核下 14.进程 进程是资源单位,没建立一个进程都会生成一个名称空间,占用内存资源. - 程序与进程 程序就是一堆代码 进程就是一堆代码运行的过程 - 进程调度 - 时间片轮转法 10个进程, 将固定时间,等分红10份时间片,分配给每个进程. - 分级反馈队列 1级别: 2级别: 3级别: - 进程的三个状态 - 就绪态: 建立多个进程, 必需要排队准备运行 - 运行态: 进程开始运行, 1.结束 2.阻塞 - 阻塞态: 当运行态遇到IO操做,就会进阻塞态. - 同步与异步 提交任务的方式 - 同步: 同步提交, 串行,一个任务结束后,另外一个任务才能提交并执行. - 异步: 异步提交, 多个任务能够并发运行 - 阻塞与非阻塞 - 阻塞: 阻塞态 - 非阻塞: 就绪态 运行态 - 同步和异步、阻塞和非阻塞的区别。 二者是不一样的概念,不能混为一谈. - 建立进程的两种方式 一: p = Process(target=任务, args=(任务的参数, )) p.daemon = True # 必须放在start()前,不然报错 p.start() # 向操做系统提交建立进程的任务 p.join() # 向操做系统发送请求, 等全部子进程结束,父进程再结束 二: class MyProcess(Process): def run(self): # self == p 任务的过程 p = MyProcess() p.daemon = True # 必须放在start()前,不然报错 p.start() # 向操做系统提交建立进程的任务 p.join() # 向操做系统发送请求, 等全部子进程结束,父进程再结束 - 回收进程资源的两种条件 - 调用join让子结束后,主进程才能结束. - 主进程正常结束 15.僵尸进程与孤儿进程(了解) 僵尸进程: 凡是子进程结束后,PID号还在, 主进程意外死亡,无法给子进程回收资源. - 每一个子进程结束后,都会变成,僵尸进程 (PID) 孤儿进程: 凡是子进程没有结束,可是主进程意外死亡.操做系统优化机制(孤儿院), 会将没有主,而且存活的进程,在该进程结束后回收资源. 16.守护进程 只要父进程结束,全部的子进程都必须结束. 17.互斥锁 将并发变成串行,牺牲执行效率,保证数据安全. from multiprocessing import Lock mutex = Lock() # 加锁 mutex.acquire() 修改数据 mutex.release() 18.队列 - FIFO队列: 先进先出 from multiprocessing import Queue q = Queue(5) # 添加数据,若队列添加数据满了,则等待 q.put() # 添加数据,若队列添加数据满了,直接报错 q.put_nowait() # 获取队列中的数据 q.get() # 若队列中没数据,会卡住等待 q.get_nowait() # 若队列中没数据,会直接报错 19.堆栈 LIFO 20.IPC进程间通讯 - 进程间的数据是隔离的 - 队列可让进程间通讯 - 把一个程序放入队列中,另外一个程序从队列中获取,实现进程间数据交互 21.生产者与消费者 模型 生产者: 生产数据 消费者: 使用数据 为了保证 供需平衡. 经过队列实现, 生产者将数据扔进队列中,消费者从队列中获取数据. 能够保证一边生产一边消费. 22.线程 - 什么是线程 - 进程: 资源单位 - 线程: 执行单位 - 建立进程时,会自带一个线程 一个进程下能够建立多个线程. - 使用线程的好处 节省资源的开销 - 进程与线程优缺点: - 进程: 优势: - 多核下能够并行执行 - 计算密集型下提升效率 缺点: - 开销资源远高于线程 - 线程: 优势: - 占用资源远比进程小 - IO密集型下提升效率 缺点: - 没法利用多核优点 23.线程间数据是共享的 - 画图 24.GIL全局解释器锁 - 只有Cpython才有自带一个GIL全局解释器锁 1.GIL本质上是一个互斥锁. 2.GIL的为了阻止同一个进程内多个线程同时执行(并行) - 单个进程下的多个线程没法实现并行,但能实现并发 3.这把锁主要是由于CPython的内存管理不是 "线程安全" 的. - 内存管理 - 垃圾回收机制 注意: 多个线程过来执行,一旦遇到IO操做,就会立马释放GIL解释器锁,交给下一个先进来的线程. 总结: GIL的存在就是为了保证线程安全的,保证数据安全 25.多线程使用的好处 - 多线程: IO密集型,提升效率 - 多进程 计算密集型,提升效率 26.死锁现象(了解) 27.递归锁(了解,之后不用) 解决死锁现象 mutex = Lock() # 只能引用1次 mutex1, mutex2 = RLock() # 能够引用屡次 +1, 只要这把锁计数为0释放该锁, 让下一我的使用, 就不会出现死锁现象. 28.信号量(绝对了解) 信号量也是一把锁, 可让多个任务一块儿使用. 互斥锁: 只能让一个任务使用 信号量: 可让多个任务一块儿使用. sm = Semaphore(5) 可让5个任务使用 29.线程队列 使用场景: 若线程间数据不安全状况下使用线程队列, 为了保证线程间数据的安全. import queue - FIFO: 先进先出队列 queue.Queue() - LIFO: 后进先出队列 queue.LifoQueue() - 优先级队列: - 根据数字大小判断,判断出队优先级. - 进队数据是无序的 queue.PriorityQueue() 30.event事件 能够控制线程的执行,让一些线程控制另外一些线程的执行. e = Event() - 线程1 e.set() # 给线程2发送信号,让他执行 - 线程2 e.wait() # 等待线程1的信号 31.进程池与线程池 为了控制进程/线程建立的数量,保证了硬件能正常运行. from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor pool1 = ProcessPoolExecutor() # 默认CPU个数 pool2 = ThreadPoolExecutor() # CPU个数 * 5 pool3 = ProcessPoolExecutor(100) # 100个 pool4 = ThreadPoolExecutor(200) # 200个 # 将函数地址的执行结果,给回调函数 pool4.submit(函数地址, 参数).add_done_callback(回调函数地址) - 回调函数(必须接收一个参数res): # 获取值 res2 = res.result() 32.协程 - 进程: 资源单位 - 线程: 执行单位 - 协程: 单线程下实现并发, 不是任何的单位,是程序员YY出来的名字. - 单线程下实现并发 好处是节省资源, 单线程 < 多线程 < 多进程 - IO密集型下: 协程有优点 - 计算密集型下: 进程有优点 - 高并发: - 多进程 + 多线程 + 协程 (Nginx) 协程的建立: 手动实现切换 + 保存状态: - yield - 函数一直在调用next() 会不停地切换 yield不能监听IO操做的任务 - gevent来实现监听IO操做 33.gevent pip3 install gevent from gevent import monkey monkey.patch_all() # 设置监听全部IO from gevent import spawn, joinall # 实现 切换 + 保存状态 - 实现了单线程下实现并发 s1 = spawn(任务1) s2 = spawn(任务2) joinall([s1, s2]) 34.IO模型(了解) - 阻塞IO - 非阻塞IO - 多路复用IO - 异步IO