w8

本周内容总结

软件开发架构

规定了程序的请求逻辑、功能分块

1.C/S架构
	Client:客户端
  	Server:服务端
        '''
        我们使用计算机下载下来一个app的本质就是各大互联网公司的客户端软件
        通过这些客户端软件我们就可以体验到各个互联网公司给我们提供的服务
       	eg:
       		下载淘宝客户端 打开 体验淘宝服务端提供的购物服务
       	ps:
       		一般情况下客户端与服务端交互需要互联网 但是如果服务端和客户端在一台计算机上就不需要
       		
       	客户端:即将要去消费的客人
       	服务端:给客人提供服务的店
       	
       	作为服务端必备的多个条件
       		1.24小时不间断提供服务
       		2.固定的地址
       		3.能够服务多个客人(高并发)
        '''
2.B/S架构
	Browser:浏览器
  	Server:服务器/端
        '''
        浏览器可以充当所有服务端的客户端
        
        ps:B/S架构本质还是C/S架构
        '''
        
B/S与C/S架构的区别
'''
C/S:
	优势:不同公司的客户端由不同公司独立开发 可以高度定制化客户端功能	
	劣势:需要下载才能使用

B/S:
	优势:不用下载就能使用
	劣势:无法完成高度定制 并且需要遵守很多规则
'''

架构总结

ATM:三层架构
选课系统:三层架构
本质也属于软件开发架构的范畴

软件设计的大方向>>>:统一接口
    微信小程序
    支付宝小程序

网络编程前戏

1.什么是网络编程
	基于网络编写代码 能够实现数据的远程交互
2.学习网络编程的目的
	能够开发CS架构的软件
3.网络编程的起源
	'''
	最早起源美国军事领域
		想实现计算机之间数据的交互
			最早的时候只能硬盘拷贝
			之后发明了网络编程
	'''
4.网路编程必备的条件
	数据的远程交互
    	1.早期的电话
        	电话线
       	2.早期的大台式电脑
        	网线
        3.笔记本电脑、移动电话
        	网卡
    ps:实现数据的远程交互必备的基础条件是物理连接介质

OSI七层架构协议简介

'''
OSI七层协议:规定了所有的计算机在远程数据交互的时候必须经过相同的处理流程、在制作的过程中必须拥有相同的功能硬件
'''
引用层
表示层
会话层
传输层
网络层
数据链路层
物理连接层
ps:应 表 会 传 网 数 物
    
'''常见的是整合之后五层或者四层'''
应用层
传输层
网络层
数据链路层
物理连接层

应用层
传输层
网络层
网络接口层

'''
接收网络消息 数据由下往下传递
发送网络消息 数据由上往下传递
'''

OSI七层协议之物理连接层

主要用于确保计算机之间的物理连接介质 接收数据(bytes类型、二进制)

OSI七层协议之数据链路层

1.规定了电信号的分组方式
2.以太网协议
	规定了计算机在出厂的时候必须有一块网卡 网卡上有一串数字
    该数字相当于计算机的身份号码是独一无二的
    该数字的特征:12为的16进制
        前6位厂商编号 后6位流水线号
    该数字也称为:以太网地址/MAC地址

网络相关专业名词

计算机之间要想实现数据交互必须要'连接'到一起

1.交换机	
	能够将所有接入交换机的计算机彼此联系起来
2.广播
	首次查找接入同一个交互机的其他计算机 需要朝交换机里面吼一嗓子
3.单播
	首次被查找的计算回应查找它的计算机 并附带自己的mac地址
4.广播风暴
	接入同一台交换机的多台计算机同时发广播
5.局域网
	可以简单的理解为有单个交换机组成的网络
    在局域网内可以直接使用mac地址通信
6.广域网
	可以简单的理解为范围更大的局域网
7.互联网
	由所有的局域网、广域网连接到一起形成的网络
8.路由器
	不同的局域网计算机之间是无法直接实现数据的交互的 需要路由器连接

OSI七层协议之网络层

IP协议:
	规定了所有接入互联网的计算机都必须有一个IP地址 类似于身份证号
    mac地址是物理地址可以看成永远无法修改
    IP地址是动态分布的 不同的产所IP是不同的
IP地址特性:
    IPV4:点分十进制
        0.0.0.0
        255.255.255.255
        共容纳的总量为(4**255)
    IPV6:能够给地球上每一粒沙子都分一个IP地址(凸显它的厉害)
        IP地址可以跨局域网传输
ps:IP地址可以用来标识全世界独一无二的一台计算机

OSI七层协议之传输层

PORT协议(端口协议)
	用来标识一台计算机上面的某一个应用程序
  	范围:0~65535
   	特征:动态分布
    建议:
        0-1024 		系统默认需要使用
        1024-8000    常见软件的端口号
        8000之后     我们可以自定义使用
      
UPL:统一资源定位符(网址)
    网址的本质是由IP和PORT组成的
    
IP + PORT:能够定位全世界独一无二的一台计算机上面的某一个应用程序
    
域名解析:将网址解析成IP+PORT
    
我们之所以不直接使用IP+PORT的原因是太难记了 所以发明了域名(网址)

IP:PORT 实际用冒号连接
#eg:
	114.55.205.139:80
    baidu.com
    两者都是百度 第一个是IP:PORT 第二个是域名你能记住哪一个呢?

传输层之TCP与UDP协议

TCP与UDP都是用来规定通信方式的
	通信的收可以随心所欲的聊 也可以遵循一些协议符合要求的聊
	同理 我们也可以不遵循这些协议 但是遵循了更加合理合规
    
1.TCP协议
	#三握四挥
    三次握手建立联系
    1.TCP协议又称可靠协议(数据不易丢失)
    	造成数据不易丢失的原因不是有双向通道 而是有反馈机制
        给对方发消息之后会保留一个副本 直到对方回应了消息才会删除
        否则在一定时间内反复发送
    2.洪水攻击
    	同一时间有大量的客服端请求建立链接 会导致服务器一直处于
 	SYN_RCVD状态
    3.服务端如何区分客户端建立链接的请求
    	可以对请求做唯一的标识
    四次挥手断开联系
    1.四次不能合并成三次
    	因为中间需要确认消息是否发完(TIME_WAIT)

2.UDP协议
	也称为不可靠协议、数据报协议
    早期QQ使用的就是纯生的(没有加任何额外功能)UPD协议
    

应用层

应用层相当于是程序员自己写的应用程序 里面的协议特别多
常见的有:HTTP HTTPS FTP

socket模块

如果我们需要编写基于网络的数据交互的程序 意味着我们需要自己通过代码来控制我们之前所学习的OSI七层(十分麻烦而且复杂)
所以就有了socket 它类似于操作系统 封装了丑陋复杂的接口提供简单快捷的接口

socket也叫套接字
	基于文件类型的套接字家族(单机)
  	AF_UNET
    基于网络类型的套接字家族(联网)
    AF_INET

socket代码简介

'''服务端'''
import socket

#1.产生一个socket对象 并指定采用的通信版本与协议(TCP)
server = socket.socket() # 括号内不写参数 默认就是TCP协议
#family = AF_INET基于网络的套接字 type=SOCK_STREAM流式协议即TCP
#2.绑定一个固定的地址(服务端必备的条件之一)
server.bind(('127.0.0.1',8000)) # 127.0.0.1是本机的回环地址
#3.设立半连接池
server.listen(5)
#4.等待接客
sock,addr = server.accpet() # return sock addr 三次握手
# sock是双向通道 addr就是客户端地址
#5.接待客人
data = sock.recv(1024) #接收客户端的消息 1024个字节
print(data.decode('utf8'))
sock.send('给客服端回复的消息').encode('utf8')
#发送的消息要是bytes类型
#6.关闭双向通道
sock.close() # 四次挥手
#7.关闭服务器
server.close()


'''客户端'''
import socket

#1.生成socket对象指定类型和协议
client = socket.socket()
#2.通过服务器的地址链接服务端
client.connect(('127.0.0.1',8080))
#3.向服务端发送消息
client.send('给服务端接收的消息'.encode('utf8'))
#4.接收服务端发送的消息
data = client.recv(1024)
print(data.decode('utf8'))
#5.断开与服务端的链接
client.close()

代码优化

1.聊天的内容自定义
	使用 input来获取动态输入
2.让聊天可循环 不要聊一句就直接断开
	将聊天的消息打包到while循环中
3.对用户输入做一个判定
	用户输入的消息不可为空 两边不能都是recv或者send 
    一定是一方收或者一方发
4.服务端多次重启可能会报错
	Address already in use 主要是mac电脑会报
  	方式1:改端口号
   	方式2:输入代码(查询之前的博客有)
5.当客户端异常断开的情况下 如何让服务端去服务其他人
	windows服务端会直接报错
  mac服务端会有一段时间反复接收空消息延迟报错	
  	异常处理、空消息判断

半连接池的概念

上述代码中有一段
server.listen(5) # 半连接池

当多个客户端来链接的情况下 我们可以设置等待数量(不考虑并发问题)
假设服务端只有一个人的前提下

粘包现象

1.当服务端存在多个recv
2.客服端连续执行多次send
预想效果 >>>: 让每一次send输入的消息和服务端recv接收的消息一一对应
实际效果 >>>: recv接收为空或者recv接收到其他recv对应的消息
这就是所谓的粘包现象

产生原因:
    1.不知道每次的数据到底有多大
    2.TCP也称为流式协议:数据像流水一样没有间隔(TCP会针对数据较小且发送时间间隔短的多条数据一次性结合并打包发送)
        
避免黏包现象的关键点/核心思路
	如何获取即将收到的数据大小

struct模块

针对解决黏包问题
	粘包问题出现的关键就是无法动态获取发送的长度
    使用struct模块可以将长度打包成一个固定长度(4)
    
import struct

info = b'hello'
print(len(info)) # 获取数据的长度(bytes)
res = struct.pack('i',len(immkjnfo)) # 讲数据打包成固定的长度 i是固定的打包模式
print(len(res)) # 4

real_len = struct.unpack('i',res)
print(real_len)   # 将打包好的数据解析成真实的长度 结果为一个元组

"""
解决黏包问题初次版本
    客户端
        1.将真实数据转成bytes类型并计算长度
        2.利用struct模块将真实长度制作一个固定长度的报头
        3.将固定长度的报头先发送给服务端 服务端只需要在recv括号内填写固定长度的报头数字即可
        4.然后再发送真实数据
    
    服务端
        1.服务端先接收固定长度的报头
        2.利用struct模块反向解析出真实数据长度
        3.recv接收真实数据长度即可
"""
'''问题1:struct模块无法打包数据量较大的数据 就算换更大的模式也不行'''
# res = struct.pack('i', 12313213123)
# print(res)
'''问题2:报头能否传递更多的信息  比如电影大小 电影名称 电影评价 电影简介'''

"""
黏包问题终极方案
    客户端 
        1.制作真实数据的信息字典(数据长度、数据简介、数据名称)
        2.利用struct模块制作字典的报头
        3.发送固定长度的报头(解析出来是字典的长度)
        4.发送字典数据
        5.发送真实数据     
    服务端
        1.接收固定长度的字典报头
        2.解析出字典的长度并接收
        3.通过字典获取到真实数据的各项信息
        4.接收真实数据长度
"""

UPD协议(了解)

1.UDP服务器和客户端'各玩各的'
2.UDP不会出现多个消息发送合并(黏包)
UPD协议一般都用在聊天软件上

并发编程理论

研究网络编程其实就是在研究计算机的底层原理及发展史

"""
计算机中真正干活的是CPU 
"""
操作系统发展史
	1.穿孔卡片阶段
  	计算机很庞大 使用很麻烦 一次只能给一个人使用 期间很多时候计算机都不工作
    	好处:程序员独占计算机 为所欲为
  		坏处:计算机利用率太低 浪费资源
 	2.联机批处理系统
  	提前使用磁带一次性录入多个程序员编写的程序 然后交给计算机执行
    	CPU工作效率有所提升 不用反复等待程序录入
	3.脱机批处理系统
  	极大地提升了CPU的利用率
	总结:CPU提升利用率的过程

多道技术

'''
在学习并发编程的过程中 不做刻意提醒的情况下 默认一台计算机就一个CPU(只有一个干活的人)
'''
单道技术
	所有的程序排队进行 过程不能重合
多道技术
	利用空闲时间提前准备数据 最大化提升CPU利用率
    
多道技术详细
	1.切换
  	计算机的CPU在两种情况下会切换(不让你用 给别人用)
    	1.程序有IO操作
      	输入\输出操作
        	input、time.sleep、read、write
  		2.程序长时间占用CPU	
      	我们得雨露均沾 让多个程序都能被CPU运行一下 

  2.保存状态
  	CPU每次切换走之前都需要保存当前操作的状态 下次切换回来基于上次的进度继续执行

进程理论

进程与程序的区别
	程序:一堆死代码(还没有被运行起来)
	进程:正在运行的程序(被运行起来了)
 
进程的调度算法(重要)
	1.FCFS(先来先服务)
  	对短作业不友好
	2.短作业优先调度
  	对长作业不友好
	3.时间片轮转法+多级反馈队列(目前还在用)
  	将时间均分 然后根据进程时间长短再分多个等级
    等级越靠下表示耗时越长 每次分到的时间越多 但是优先级越低

进程的并行与并发

并行
	多个进程同时执行 必须要有多个CPU参与 单个CPU无法实现并行
并发
	多个进程看上去像同时执行 单个CPU可以实现 多个CPU肯定也可以
 
判断下列两句话孰对孰错
	我写的程序很牛逼,运行起来之后可以实现14个亿的并行量
  	并行量必须要有对等的CPU才可以实现
  我写的程序很牛逼,运行起来之后可以实现14个亿的并发量
  	合情合理 完全可以实现	以后我们的项目一般都会追求高并发
ps:目前国内可以说是最牛逼的>>>:12306

进程的三状态

就绪态
	所有的进程在被CPU执行之前都必须先进入就绪态等待
运行态
	CPU正在执行
阻塞态
	进程运行过程中出现了IO操作 阻塞态无法直接进入运行态 需要先进入就绪态

同步与异步

用来表达任务的提交方式

#同步
	提交完任务之后原地等待任务的返回结果 期间不做任何事
#异步
	提交完任务之后不愿地等待任务的返回结果 直接去做其他事 有结果自动通知

阻塞与非阻塞

用来表达任务的执行状态

阻塞
	阻塞态
非阻塞
	就绪态、运行态

综合使用

同步阻塞(效率最低)
同步非阻塞
异步阻塞
异步非阻塞(效率最高)

创建进程的多种方式

'''
1.鼠标双击点开软件图标
2.python代码创建进程
'''

进程间隔数据隔离

同一台计算机的多个进程是严格意义的物理隔离(默认情况)

from multiprocessing import Process
import time

money = 1000


def task():
    global money
    money = 666
    print('子进程的task函数查看money', money)


if __name__ == '__main__':
    p1 = Process(target=task)
    p1.start()  # 创建子进程
    time.sleep(3)  # 主进程代码等待3秒
    print(money)  # 主进程代码打印money
    
'''
此时打印的money的结果是1000>>>说明了数据的隔离
'''

进程的join方法

join方法可以让主进程等待子进程的运行后再运行

IPC机制

IPC:进程间通信
消息队列:存储数据的地方 所有人都可以存 也都可以取
    
from multiprocessing import Queue


q = Queue(3)  # 括号内可以指定存储数据的个数
# 往消息队列中存放数据
q.put(111)
# print(q.full())  # 判断队列是否已满
q.put(222)
q.put(333)
# print(q.full())  # 判断队列是否已满
# 从消息队列中取出数据
print(q.get())
print(q.get())
# print(q.empty())  # 判断队列是否为空
print(q.get())
# print(q.empty())  # 判断队列是否为空
# print(q.get())
print(q.get_nowait())

"""
full() empty() 在多进程中都不能使用!!!
"""

生产者消费者模型

生产者
	负责产生数据的'人'
消费者
	负责处理数据的'人'
    
该模型除了有生产者和消费者之外还必须有消息队列(只要是能够提供数据保存服务和提取服务的理论上都可以)

进程对象的多种方法

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()
4.start()
5.join()
'''上面有哦'''

守护进程

守护进程会随着守护的进程结束而立刻结束

僵尸进程与孤儿进程

僵尸进程
	进程执行完毕后并不会立刻销毁所有的数据 会有一些信息短暂保留下来
 	比如进程号、进程执行时间、进程消耗功率等给父进程查看
 	ps:所有的进程都会变成僵尸进程
孤儿进程
	子进程正常运行 父进程意外死亡 操作系统针对孤儿进程会派遣福利院管理

多进程数据错乱问题

"""
多进程操作数据很可能会造成数据错乱>>>:互斥锁
	互斥锁
		将并发变成串行 牺牲了效率但是保障了数据的安全
"""
posted @ 2022-11-20 16:09  早点早点灬  阅读(263)  评论(0)    收藏  举报