网络编程02--并发理论
昨日复习
- socket基本使用
内置的模块
import socket
s = socket.socket() # 创建网络传输,默认TCP协议
s.bind((IP+port)) # 绑定IP+端口
s.listen(5) # 半连接池
sock, addr = s.accept # 监听,三次握手的lisent态
sock.recv(1024) # 接收内容
sock.send(发送的内容) # 发送内容
c = socket.socket()
c.connect((IP+port))
- 通信循环
将recv和send用while循环 - 连接循环
监听代码使用while循环起来 - 代码健壮性校验
- 异常捕获
- 端口冲突
- 系统问题
在客户端判断用户是否输入为空
在服务端判断接受是否为空
- TCP粘包特性
- 双向同道中数据量较大接收有残余
- TCP会将数据量较小并且时间较短的数据一次性打包发送(流式协议)
- 如何解决黏包问题
-
报头:固定长度,内部包含诸多信息
能够固定打包的模块struct
客户端- 打包固定长度的字典的报头并发送
- 发送字典数据
- 发送真实数据
服务端
- 先接收固定长度的字典的报头
- 解析出字典的长度
- 接收字典数据,并解析出真实数据相关的内容
- 接收真实的数据
-
- 大文件如何传输
- 如何校验文件数据的一致性
使用hashlib模块对文件内容做加密处理,之后发送成功之后取出随机字符串做对比
切片解密对比
读取文件部分内容加密(划分区域) - 数据储存
for循环一行行发送,一行行储存
- 如何校验文件数据的一致性
昨日代码务必掌握
昨日需求剖析
- 将客户端与服务端全部使用软件开发目录规范编写
- 将各个功能写成函数
1、UDP代码编写
# 服务端
import socket
amg = socket.socket(type = socket.SOCK_DGRAM) # UDP协议
amg.bind(('127.0.0.1', 9000)) # 绑定IP地址
msg, addr = amg.rescvfrom(1024)
amg.sendto(发送的内容,addr发送的地址)
amg.close()
# 客户端
import socket
ip_port = ('127.0.0.1', 9000)
udp_sk = socket.socket(type=socket.SOCK_DGRAM)
udp_sk.sendto(内容,ip_port)
back, addr = udp_sk.recvfrom(1024)
print(back.decode('utf-8'),addr)
# 建议QQ程序练习
2、操作系统的发展史
学习并发编程其实就是现在学习操作系统的发展史(底层逻辑)
- 穿孔卡片时代:
- CPU的利用率极低(所有的输入只能通过穿孔卡片操作,每个计算每次只能一个人操作专属的代码,没办法执行其他代码)
- 联机批处理系统
- 将多个程序员的程序一次性录入磁带中,之后交由输入机输入并交由CPU执行
- 脱机批处理系统
- 现代计算机的雏形(远程输入,高速磁带,主机)
3、多道程序系统(多道技术)
前提:针对单核CPU(同一时间计算机只能高一件事)
单道技术(串行)
多道技术(单核)
- 切换+保存状态
CPU的工作机制(单核)
- 当某个程序进入IO状态,才做系统会自动剥夺改程序的CPU执行权限
- 当某个程序长时间占用CPU时,那么操作系统也会剥夺改程序的CPU的执行权限
并行与并发
- 并行:多个程序同时执行(需多个CPU)
- 并发:多个程序看起来像同时运行即可
简单小问题:
- 单核CPU能都实现并行
不能,但可以实现并发 - 12306可以同时支持上亿的用户买票,问是并发还是并行
并发(高并发)
星轨:微博可以同时支持多个星轨
4、进程理论(重要重点关注)
-
进程与程序的区别
-
程序:及代码,在类似py文件内的代码(死的)
-
进程:运行起来的程序(代码)(活的)
-
看成内存中独立的空间(运行的程序)
-
-
-
单核情况下的进程调度
- 进程调度算法演变
- FCFS:先来先服务
缺点:对短作业不友好 - 短作业优先调度算法
缺点:对长作业不友好 - 时间片轮转发+多级反馈列队(现在计算机正在使用的算法)
先分配给担心的多个进程相同的时间片
之后根据进程消耗的时间片分类别
- FCFS:先来先服务
- 进程调度算法演变
-
进程三状态图
- 就绪态
- 运行态
- 阻塞态
- 程序要想进入运行态,必须先经过就绪态
- 同步&异步(用于面熟任务的提交方式)
- 同步:
- 提交任务之后原地等待任务的返回结构,期间不做任何事
- 异步:
- 体检任务有之后不原地等待任务的返回结果,直接去做其他事情,结构由反馈机制自动提醒
- 阻塞&非阻塞(描述任务的执行状态)
- 阻塞:阻塞态
- 非阻塞:就绪态,运行态
5、创建进程
# 代码层面创建进程
# 高端模块
from mulirocessing import Process
import time
def test(name):
print('%s正在运行'%name)
time.sleep(3)
print('%s已经结束'%name)
if __name__ = '__main__':
p = Process(target=test, args=('kk',)) # s生成一个进程对象
p.start() # 告诉操作系统开设一个新进程,并运行。异步提交
'''
在win系统中开设进程类似于导入模块
从上往下再次执行代码
一定要在__main__判断语句内执行开设进程的代码块
if __name__ = '__main__':
print(123)
在linux系统中直接将代码完整的复制一份执行
不需要__main__判断语句内执行
'''
# 类创建进程
class MyProcess(Process):
def __init__(self, name):
super().__init__()
self.name = name
def run(self):
print('%s正在运行'%name)
time.sleep(3)
print('%s已经结束'%name)
if __name__ == '__main__':
p = MyProcess('kk')
p.start()
6、进程的join方法
from multiprocessing import Process
import time
def test(name, n):
print('%s is running' % name)
time.sleep(n)
print('%s is over' % name)
if __name__ == '__main__':
p_list = []
start_time = time.time()
for i in range(1, 4):
p = Process(target=test, args=(i, i))
p.start()
p_list.append(p)
# p.join() # 串行 9s+
for p in p_list:
p.join()
print(time.time() - start_time)
"""
p = Process(target=test, args=('jason',))
p1 = Process(target=test, args=('kevin',))
p2 = Process(target=test, args=('oscar',))
p.start()
p1.start()
p2.start()
"""
print('主进程')
7、进程间默认无法交互
# 进程间数据是相互隔离的
from multiprocessing import Process
money = 100
def test():
global money
money = 999
if __name__ == '__main__':
p = Process(target=test)
p.start()
# 先确保子进程运行完毕了 再打印
p.join()
print(money)
8、对象方法
from mulirocessing import Process
import time
import os
def test(name):
print('%s正在运行'%name)
time.sleep(3)
print('%s已经结束'%name)
if __name__ = '__main__':
p = Process(target=test, args=('kk',)) # s生成一个进程对象
p.start() # 告诉操作系统开设一个新进程,并运行。异步提交
p.join() # 等待子进程运行结束在运行主进程
p.terminate() # 立刻结束子进程
print(p.is_alive()) # 查看进程是否存在,返回布尔值
print(current_process().pid) # 查看当前进程号
print(os.getpid()) # 查看当前进程号
print(os.getppid()) # 查看父进程号
"""
1.current_process查看进程号
2.os.getpid() 查看进程号 os.getppid() 查看父进程进程号
3.进程的名字,p.name直接默认就有,也可以在实例化进程对象的时候通过关键字形式传入name=''
3.p.terminate() 杀死子进程
4.p.is_alive() 判断进程是否存活 3,4结合看不出结果,因为操作系统需要反应时间。主进程睡0.1即可看出效果
"""
扩展
时间服务器的实现原理
- 1、内部电容小电池
- 专门为时间模块供电
- 2、远程时间同步
- 联网之后会自动更新时间
linux多台服务器定时任务
- 随机抽取一台服务器的时间为标准,到一定时间所有的机器执行定时脚本