11月18学习总结
一、软件开发目录
1.软件开发框架
软件开发框架:在编写项目之前需要遵循的代码层面上面的规范(运行流程,环节,步骤)
2.软件开发框架的分类
1.c/s框架
client/server 客户端/服务端
eg:客户端就是各种APP软件,用户可以体验对应服务器的服务
2.b/s框架
broswer/server 浏览器/服务端
eg:用户通过浏览器来体验对应服务器的服务功能,不需要下载APP
# 服务器具备的特征:
24小时不间断的提供服务
固定网址,不经常改变
可以同时服务多个人
3.两种框架的优劣势
cs架构:
优:通过下载客户端APP可以在APP软件中高度定制相关服务
劣:需要下载客户端的APP,占内存也比较繁琐
bs架构:
优:不需要下载客户端,直接通过浏览器就可以快速体验服务
劣:定制一些功能的话较为繁琐
4.框架的发展趋势
发展趋势必然是统一接口原则,如微信,支付宝的小程序,可以直接体验其他的服务,避免了各自的优劣
二、网络编程简介
1.网络编程
基于互联网编写的代码,能够实现数据的远程交互
2.网络编程的本质
本质就是解决计算机之间数据远程交互,最早起源于美国军方
3.网络编程的要求
计算机之间实现数据远程传输的必要条件就是得通过物理连接介质
三、OSI七层协议详细简介
应用层,表示层,会话层,传输层,网络层,数据链路层,物理连接层
# 记忆技巧:应表会传网数物
整合为五层:
应用层、传输层、网络层、数据链路层、物理连接层
继续整合为四层:
应用层、传输层、网络层、网络接口层
四、网络相关名词
1.交换机:
能够让接入交换机的计算机实现彼此互联
2.以太网:
就是现实世界中最普遍的一种计算机网络,它规定了包括物理层的连线、电子信号和介质访问层协议的内容。
3.广播:
接入同一台交换机的多台计算机同时发广播
4.单播:
首次被查找的计算机回应找他的计算机,并附带自己的mac地址
mac地址:(在命令提示符下输入命令“ipconfig /all”回车之后就会显示当前计算机的一些网络信息,其中“Physical Address”字样的这一项就是当前计算机中网卡的 MAC地址)
5.广播风暴:
接入同一台的交换机的多台计算机同时发广播
6.局域网:
由固定区域组成的网络,局域网内可以直接使用mac地址通信(局域网可以理解为有单个交换机组成的网络)
7.广域网:
可以理解为范围更大的局域网
8.互联网:
由所有的局域网,广域网理解到一起形成的网络
9.路由器:
不同的局域网计算机之间是无法直接实现交互的,交互需要路由器连接
五、OSI七层协议之物理连接层
主要用于确保计算机之间的物理连接介质,接收数据(bytes类型,二进制)
六、OSI七层协议之数据链路层
1.规定了电信号的分组方式
2.规定了每台计算机必须有一块网卡
由12到16位组成,前六位是生产商编号,后六位是生产流水线号
该数字也称:以太网地址/mac地址
七、OSI七层协议之网络层
IP协议:规定了所有接入互联网的计算机必须有一个IP地址,类似于我们的身份证
mac地址是物理地址可以看成永远无法修改
IP地址是动态分配的 不同的场所IP是不同的
IP地址特征:
IPV4:点分十进制
最小: 0.0.0.0
最大: 255.255.255.255
IPV6:能够给地球上每一粒沙分一个IP地址
# IP地址可以用来标识全世界独一无二的一台计算机
八、OSI七层协议之传输层
1.PORT协议(协议):规定了一台计算机上的每一个正在运行的应用程序都必须有一个端口号,端口号用来管理多个应用程序的标记
端口号特征:
1.端口号的范围:0-65535
2.端口号是动态分配的
3.同一时间同一台计算机端口号不能冲突
4.端口号范围使用:
0-1024:一般是操作系统内部需要使用的
1024-8000:一般是常见的软件已经使用了
8000+:我们平时写代码可以使用8000之后的端口号
2.URL:统一资源定位符(网址)
URL的本质就是IP + PORT
3.IP+PORT:能够定位全世界独一无二的一台计算机上面的某一个应用程序
IP+PORT应用时加冒号连接
eg: 114.55.205.139:80
九、传输层之TCP与UDP协议
TCP与UDP协议都是用来规定通信方式的,数据传输过程中能够遵循的协议有很多其中TCP协议和UDP协议是较为常见的两个。
1.TCP协议
可靠传输,只要得不到认可,就重新发送数据报,直到得到对方的确认为止
1.三次握手建连接:
建立双向通道
问题:洪水攻击
解决的办法:同时让大量的客户端朝服务端发送建立TCP连接的请求
2.四次挥手
断开双向通道(中间的两步不能合并,需要有检查的时间)
注意:基于TCP协议传输的数据非常安全,因为有双向通道,基于TCP传输数据,数据不容易丢失,原因在于二次确认机制,每次发送数据都需要返回确认消息,否则在一定时间会反复发送。达到一定次数的发送,若得不到确认则删除数据。
三次握手和四次挥手也可以看成是小情侣谈恋爱的过程
三次握手:表白在一起
四次挥手:决裂要分手
# 基于TCP传输数据因为有双向通道所以很安全
TCP传数据不容易丢失因为有二次确认机制,每次发送数据都需要返回确认消息,否则在一定时间会反复发送
2.UDP协议
UDP协议发送数据没有任何的通道也没有任何的限制,但是没有TCP协议传输数据来的安全(没有二次确认机制)
eg:发了消息,重要的是发了,不管别人看了没有,回没有回复
十、应用层
应用层提供各种各样的应用层协议,这些协议嵌入我们使用的各种应用程序中,主要是程序员自己采用什么样的策略和协议
常见的协议有:HTTP,HTTPS,FTP....
十二、socket套节字编程
1.套节字的作用
可以看成两个网络应用程序进行通信时,各自通信连接中的端点
2.套节字家族
基于文件类型的套节字家族
套节字家族的名字:AF_UNIX
基于网络类型的套节字家族
套节字家族的名字:AF_INET
3.socket代码简介
'''客户端'''
import socket
# 1.生成socket对象指定类型和协议
client = socket.socket()
# 2.通过地址链接服务端
client.connect(('127.0.0.1',8080))
# 3.直接给服务端发送消息
client.send('你好,我是客户端,你是谁'.encode('utf8'))
# 4.接收服务端发送过来的消息 1024是字节数
data = client.recv(1024)
print(data.decode('utf8'))
# 5.断开与服务端的链接
client.close()
'''服务端'''
import socket
# 1.产生一个socket对象并指定采用的通信版本和协议(TCP)
server = socket.socket()
# 2.绑定一个固定的地址(服务端必备的条件)
server.bind(('127.0.0.1',8080))
# 3.设立半连接池
server.listen(5)
# 4.等待连接
sock,addr = server.accept()
print(sock,addr)
# 5.服务
data = sock.recv(1024)
print(data.decode('utf8'))
sock.send('我是服务端,专门为您服务的'.encode('utf8'))
# 6.关闭双向通道
sock.close()
# 7.关闭服务端
server.close()
4.代码优化
'''优化客户端'''
import socket
# 1.生成socket对象指定类型和协议
client = socket.socket()
# 2.通过地址链接服务端
client.connect(('127.0.0.1',8081))
while True:
msg = input('请输入您想要发给服务端的消息>>>').strip()
if len(msg) == 0:
print('不能发送空消息哦')
continue
# 3.直接给服务端发送消息
client.send(msg.encode('utf8'))
# 4.接收服务端发送过来的消息 1024是字节数
data = client.recv(1024)
print('来自服务端的消息>>>>',data.decode('utf8'))
# # 5.断开与服务端的链接
# client.close()
'''优化服务端'''
import socket
# 1.产生一个socket对象并指定采用的通信版本和协议(TCP)
server = socket.socket()
# 2.绑定一个固定的地址(服务端必备的条件)
server.bind(('127.0.0.1',8081))
# 3.设立半连接池
server.listen(5)
while True:
# 4.等待连接
sock,addr = server.accept()
while True:
try:
# 5.服务
data = sock.recv(1024)
if len(data) == 0:
break
print(f'来自于客户端{addr}的消息>>>>',data.decode('utf8'))
msg = input('请输入发送给客户端的消息(不能发空消息)>>>:').strip()
sock.send(msg.encode('utf8'))
except BaseException:
break
十三、半连接池
当服务器在响应了客户端的第一次请求后会进入多待状态,半连接池其实就是一个容器,系统会自动将半连接放入这个容器中,可以避免连接过多
eg:server.listen(5)
十四、黏包现象
1.黏包现象
情况一:发送方的缓存机制
发送端需要等缓冲区满才发送出去,造成粘包,发送数据时间间隔很短,数据很小,回合到一起,产生粘包。
情况二:接收方的缓存机制
接收方不及时接收缓冲区的包,造成多个包接收,客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包。
黏包现象通俗的讲解:
1.服务器连续执行了三次recv
2.客户端连续执行了三次send
出现黏包现象的原因:
1.不清楚数据真实多大
2.TCP协议会针对数据量较小且发送间隔较短的多条数据一次性合并打包发送
解决黏包现象的关键点:
主要是明白数据具体有多大
'''服务端'''
import socket
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
sock,address = server.accept()
print(sock.recv(1024))
print(sock.recv(1024))
print(sock.recv(1024))
'''客户端'''
import socket
client = socket.socket()
client.connect(('127.0.0.1',8080))
client.send(b'jason')
client.send(b'kevin')
client.send(b'jia')
2.struct模块
import struct
info = b'hello baby'
print(len(info)) # 数据真实的长度(bytes) 10
res = struct.pack('i', len(info)) # 将数据打包成固定的长度 i是固定的打包模式
print(len(res)) # 报头
real_res = struct.unpack('i', res)
print(real_res)
黏包问题的解决方案:
字典作为报头打包,效果好
客户端:
1.制作真实的数据信息字典
2.利用struct模块制作字典的报头
3.发送固定长度的报头(解析出来是字典的长度)
4.发送字典数据
5.发送真实数据
服务端
1.接收固定长度的字典报头
2.解析出字典的长度并接收
3.通过字典获取到真实数据的各项信息
4.接收真实数据长度
3.黏包代码实战
'''客户端'''
import socket
import struct
import json
import os
client = socket.socket()
client.connect(('127.0.0.1',8080))
# 1.获取真实数据的大小
file_size = os.path.getsize(r'D:\pythonProject\demo9\终极实战\1.txt')
# 2.制作真实数据的字典数据
data_dict = {
'file_name' : '2.txt',
'file_size':file_size,
'file_desc':'随机乱写的',
'file_info':'嘉嘉'
}
# 3.制作字典报头
data_dict_bytes = json.dumps(data_dict).encode('utf8')
data_dict_len = struct.pack('i',len(data_dict_bytes))
# 4.发送字典报头
client.send(data_dict_len)
# 5.发送字典
client.send(data_dict_bytes)
# 6.最后发送真实的数据
with open(r'D:\pythonProject\demo9\终极实战\1.txt','rb') as f:
for line in f:
client.send(line)
'''服务端'''
import socket
import struct
import json
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
sock,addr = server.accept()
# 1.接收固定长度的字典报头
data_dict_head = sock.recv(4)
# 2.根据报头解析吃字典的长度
data_dict_len = struct.unpack('i',data_dict_head)[0]
# 3.接收字典数据
data_dict_bytes = sock.recv(data_dict_len)
data_dict = json.loads(data_dict_bytes) # 自动解码再反序列化
# 4.获取真实数据的各项信息
total_size = data_dict.get('file_size')
with open(data_dict.get('file_name'), 'wb') as f:
f.write(sock.recv(total_size))
十五、UDP协议
'''服务端'''
import socket
server = socket.socket(type=socket.SOCK_DGRAM) # UDP协议
server.bind(('127.0.0.1', 8080))
while True:
data, addr = server.recvfrom(1024)
print('客户端地址>>>:', addr)
print('上述地址发送的消息>>>:', data.decode('utf8'))
msg = input('>>>:').strip()
server.sendto(msg.encode('utf8'), addr)
'''客户端'''
import socket
client = socket.socket(type=socket.SOCK_DGRAM)
server_addr = ('127.0.0.1', 8080)
while True:
msg = input('>>>:').strip()
client.sendto(msg.encode('utf8'), server_addr)
data, addr = client.recvfrom(1024)
print(data.decode('utf8'), addr)
十六、并发编程理论
1.穿孔卡片
CPU的利用率非常低,好处就是可以让程序员独占计算机
2.联机批处理系统
提前使用磁带一次性录入多个程序员编写的程序,然后交给计算机执行
缩短录入数据的时间,让CPU连续工作的时间边长,为了提升CPU 的利用率
3.脱机批处理系统
极大地提升了CPU的利用率
# 总结:操作系统的发展史是CPU利用率提升的发展史
十七、多道技术
1.单道技术
所有程序排队执行,过程不能重合,总耗时是所有程序之和
2.多道技术
计算机利用空闲时间提前准备好的一些数据,提高效率,总耗时时较短。
多道技术:切换和保存
1.切换
计算机在以下两种情况下会切换:
1.程序进入IO操作时(input,time,sleep,read,write)
2.程序长时间占用CPU(得切换一下)
2.保存状态
CPU每次切换走之前都得保存当前操作的状态,下次切换回来基于上次的进度继续执行
一个列子明白单道和多道
eg:
电饭煲煮饭:40分钟
洗衣:35分钟
烧水:10分钟
单道技术:85分钟
多道技术:40分钟
十八、进程理论
进程与程序的区别:
程序:一堆四代码(没有运行起来)
进程:正在运行的程序(被运行起来了)
进程的调度算法:
1.FCFS(先来先服务的算法):
对短作业不友好(第一个程序耗时2小时,之后的程序耗时1秒)
2.短作业优先调度
对长作业不友好
3.时间片轮转法+多级反馈队列
将时间均分 然后根据进程时间长短再分多个等级
十九、进程的并行与并发
并行:
多个进程同时执行,必须有多个CPU参与,单个CPU无法实现并行
并发:
多个进程看上去像同时执行,单个CPU可以实现,多个CPU肯定也可以
二十、进程的三状态
就绪态:所有进程在被CPU执行之前都必须进入就绪态等待
运行态:CPU正在执行
阻塞态:进程运行过程中出现了IO操作 阻塞态无法直接进入运行态 需要先进入就绪态
二十一、同步与异步
1.提交完成任务之后原地等待任务的返回结果,期间不做任何事
2.提交完任务之后不愿原地等待任务的返回结果,直接去做其他事情,有结果自动通知
二十二、阻塞与非阻塞
阻塞:
阻塞态:指结果返回之前,当前线程会被挂起,调用线程只有得到结果之后才会返回
非阻塞:
指在不能立刻得到结果之前,该调用不会阻塞当前线程。即就是就绪态,运行态
同步异步:用来描述任务的提交方式
阻塞和非阻塞:用来描述任务执行的状态
1. 同步阻塞:效率最低
在银行排队,并且在队伍中什么事情都不做。
2. 同步非阻塞:实际上是效率低下的,这个程序需要在这几种不同的行为之间来回的切换。
在银行排队,并且在队伍中做点其他事。
3. 异步阻塞:采用的是异步的方式去等待消息被触发(通知),异步操作是可以被阻塞住的,只不过它不是在处理消息时阻塞,而是在等待消息通知时被阻塞。
取号,在座位上等着叫号,期间不做事。
4.异步非阻塞:效率更高,程序不用在不同的操作中来回切换。
取号,在旁边座位上等着叫号,期间做任何自己想要做的事。
二十三、创建进程的多种方式
1.鼠标双击软件图标
2.Python代码创建进程
from multiprocessing import Process
import time
def task(name):
print('running',name)
time.sleep(3)
print('over',name)
if __name__ == '__main__':
p1 = Process(target=task,args=('jia',))
p1.start()
# task()
from multiprocessing import Process
import time
# def task(name):
# print('running',name)
# time.sleep(3)
# print('over',name)
class MyProcess(Process):
def __init__(self,name,age):
super().__init__()
self.name = name
self.age = age
def run(self):
print('running', self.name, self.age)
time.sleep(3)
print('over', self.name, self.age)
if __name__ == '__main__':
obj = MyProcess('jia',12)
obj.start()
print('main')
二十四、进程join方法
from multiprocessing import Process
import time
def task(name,n):
print('%s is running' % name)
time.sleep(n)
print('%s is over' % name)
if __name__ == '__main__':
p1 = Process(target=task,args=('jason1',1))
p2 = Process(target=task,args=('jason2',2))
p3 = Process(target=task,args=('jason3',3))
start_time = time.time()
p1.start()
p1.join()
# 注进程代码等待子进程代码运行结束后再执行
p2.start()
p2.join()
p3.start()
p3.join()
print(time.time() - start_time)
二十五、进程间数据隔离
# 同一台计算机上的多个进程数据是严格意义上的物理隔离
from multiprocessing import Process
import time
money = 1000
def task():
global money
money = 99
print('子进程的task函数查看money',money)
if __name__ == '__main__':
p1 = Process(target=task)
p1.start() # 创建子进程
time.sleep(2)
print(money)
二十六、进程间通信IPC机制
IPC:进程间的通信
消息队列:存储数据的地方,所有人都可以存,也可以取
from multiprocessing import Queue
q= Queue(4) # 括号内可以指定存储数的个数
q.put(111) # 往消息队列中存放数据
q.put(777) # 往消息队列中存放数据
q.put(999) # 往消息队列中存放数据
print(q.get()) # 取出数据
print(q.get()) # 取出数据
# print(q.get()) # 取出数据
print(q.get_nowait())
from multiprocessing import Process, Queue
def product(q):
q.put('子进程p添加的数据')
def consumer(q):
print('子进程获取队列中的数据', q.get())
if __name__ == '__main__':
q = Queue()
# 主进程往队列中添加数据
p1 = Process(target=consumer, args=(q,))
p2 = Process(target=product, args=(q,))
p1.start()
p2.start()
print('main')
二十七、进程对象诸多方法
1.如何查看进程号
from multiprocessing import Process,current_process
current_process()
current_process().pid
import os
os.getpid()
os.getppid()
2.终止进程
p1.terminate()
ps:计算机操作系统都有对应的命令可以直接杀死进程
3.判断进程是否存活
p1.is_alive()
二十八、生产者消费者模型
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
简单的来说就是我们去买棒冰,生产者肯定先制作好棒冰(数据),我们去买的时候生产者会卖给我们,再次期间这些棒冰会存储在冰柜内(消息队列/数据库)。
'''
完整的生产者消费者模型至少有是三个部分:
生产者
消息队列/数据库
消费者
'''
二十九、守护进程
# 守护进程会随着守护的进程结束而立刻结束
from multiprocessing import Process
import time
def task(name):
print('仙女姐姐:%s' % name)
time.sleep(3)
print('仙女姐姐:%s' % name)
if __name__ == '__main__':
p1 = Process(target=task,args=('feifei',))
p1.daemon = True
p1.start()
time.sleep(1)
print('仙女姐姐走了')
三十、僵尸进程与孤儿进程
僵死进程:子进程退出后,会将该进程的重型资源释放掉(cpu,内存,打开的文件),子进程的进程描述符仍然保存在系统中,比如pid。
所有的子进程在运行结束之后都会变成僵尸进程(死了没死透)
程序正常结束才会产生僵尸进程,如果强制关闭父进程,操作系统会把父进程已经运行结束的子进程全部删除,也就不会产生僵尸进程了。
僵尸进程的危害:
系统的pid号是有限的,僵尸进程保留的信息如果一直不被释放,一直累计会导致没有可用的pid号而导致系统不能产生新的进程。
'''进程已经运行结束,但是相关的资源并没有完全清空,需要父进程参与回收'''
孤儿进程(无害):一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
'''父进程意外死亡,子进程正常运行,该子进程就称之为孤儿进程,孤儿进程也不是没有人管,操作系统会自动分配福利院接收'''
三十一、多进程数据错乱问题
from multiprocessing import Process
import time
import json
import random
# 查票
def search(name):
with open(r'data.json', 'r', encoding='utf8') as f:
data = json.load(f)
print('%s在查票 当前余票为:%s' % (name, data.get('ticket_num')))
# 买票
def buy(name):
# 再次确认票
with open(r'data.json', 'r', encoding='utf8') as f:
data = json.load(f)
# 模拟网络延迟
time.sleep(random.randint(1, 3))
# 判断是否有票 有就买
if data.get('ticket_num') > 0:
data['ticket_num'] -= 1
with open(r'data.json', 'w', encoding='utf8') as f:
json.dump(data, f)
print('%s买票成功' % name)
else:
print('%s很倒霉 没有抢到票' % name)
def run(name):
search(name)
buy(name)
if __name__ == '__main__':
for i in range(10):
p = Process(target=run, args=('用户%s'%i, ))
p.start()
# 用户1在查票 当前余票为:1
# 用户0在查票 当前余票为:1
# 用户2在查票 当前余票为:1
# 用户3在查票 当前余票为:1
# 用户4在查票 当前余票为:1
# 用户5在查票 当前余票为:1
# 用户6在查票 当前余票为:1
# 用户7在查票 当前余票为:1
# 用户8在查票 当前余票为:1
# 用户9在查票 当前余票为:1
# 用户2买票成功
# 用户5买票成功
# 用户4买票成功
# 用户3买票成功
# 用户0买票成功
# 用户7买票成功
# 用户9买票成功
# 用户6买票成功
# 用户1买票成功
# 用户8买票成功
标签:11,总结,socket,18,进程,print,import,data,name
From: https://www.cnblogs.com/zx0524/p/16909074.html