网络编程遇到相关问题

为什么出现粘包问题?

TCP协议就类似于打电话
只有在TCP协议中才会出现粘包现象,因为TCP协议是流式协议
它的特点是将数据量小并且时间间隔比较短的数据一次性打包发送出去
本质其实还是因为我们不知道需要接收的数据的长短

如何解决粘包问题?

1 发送数据直接先告诉对方数据量的大小
2 利用struct模块定制我们自己的消息传输协议

TCP的大文件上传

客户端:
        1.制作字典的报头(固定4个长度)
        2.发送报头
        3.发送字典
        4.最后再发真实数据
服务端:
        1.先接收4个长度的报头
        2.解析报头获取字典的长度
        3.接收字典数据  从字典中获取真实数据的详细信息
        4.接收真实数据

udp协议

UDP协议就类似于发短信
1.udp协议客户端允许发空
2.udp协议不会粘包
3.udp协议服务端不存在的情况下,客户端照样不会报错
4.udp协议支持并发

UDP叫数据报协议,意味着发消息都带有数据报头
udp的server不需要就行监听也不需要建立连接
在启动服务之后只能被动的等待客户端发送消息过来,客户端发送消息的时候,要带上服务端的地址
服务端在回复消息的时候,也需要带上客户端的地址

多道技术

解决cpu在执行程序,遇到io时,不干活的情况
时间上的复用(单个cpu的电脑上,起多个应用程序。cpu快速切换,给人的感觉是同时运行)
空间上的复用(多个程序共一套硬件设备,它是多道技术实现时间上的复用的基础,不然还要去硬盘读数据)
一个任务占用cpu时间过长或被操作系统强行剥夺走cpu的执行权限(比起串行效率反而降低)
一个任务执行过程中遇到io操作,也会被操作系统强行剥夺走cpu的执行权限(比起串行效率提高)

串行|并发

串行:一个程序完完整整的运行完毕,才能运行下一个程序
并发:看上去像同时运行

进程理论

程序:一堆代码
进程:正在运行的程序
进程是一个实体,每一个进程都有它自己独立的内存空间

同步和异步:针对任务的提交方式

同步:提交任务之后原地等待任务的返回结果,期间不做任何事!
异步:提交任务之后,不等待任务的返回结果,执行运行下一行代码!

阻塞与非阻塞:针对程序运行的状态

阻塞:遇到io操作   >>> 阻塞态
非阻塞:就绪或者运行态  >>> 就绪态,运行态

互斥锁:锁千万不要随意去用

会将并发变成串行,牺牲了效率但是保证了数据的安全
锁一定要在主进程中创建,给子进程去用
解决多个进程操作同一份数据,造成数据不安全的情况
加锁会将并发变成串行
锁通常用在对数据操作的部分,并不是对进程全程加锁
一把锁不能同时被多个人使用,没有抢到的人,就一直等待锁释放

生产者消费者模型

生产者:生产数据(做包子的)
消费者:处理数据(吃包子的)
两者之间的通信介质:队列/管道
供需不平衡:
    队列: 
        生产者生产的数据放到队列里面
        消费者去队列里面获取数据

IPC机制

进程间通信
    进程与进程之间是数据隔离的
    管道/队列(管道+锁)
    队列:先进先出
    堆栈:先进后出
    q.put()  放入值
    q.get()  获取队列里面的值(同一时刻只能有一个任务来队列中获取数据)
    两者在存放值和取值的时候都会出现阻塞的情况(队列满了,队列空了)

线程理论

把操作系统比喻成工厂
进程:资源单位(工厂里面的车间)
线程:执行单位(车间里面的流水线)
任何一个进程都自带一个"主"线程
进程中的线程数据是共享的,
开起进程的开销要远远大于开启线程的开销
开启进程:申请空间,拷贝代码都需要耗时
开启线程:开销极小,几乎在代码执行的同时线程就已经创建

线程之间数据共享

线程之间数据共享
多个线程操作同一份数据???出现数据不安全的情况
涉及到多个线程或进程操作同一份数据的时候,通常都需要将并行并发变成串行
虽然牺牲了效率但是提高了数据的安全性
针对不同的数据,需要加不同的锁
锁(独立卫生间)

GIL全局解释器锁

只在Cpython解释器中
由于Cpython内存管理不是线程安全的!
同一进程下的多个线程在同一时刻只能有一个线程被执行
必须先抢解释器才能被cpu执行
GIL是加在Cpython解释器上的一把锁,并不能保证数据的安全,想保证数据的安全,就必须加不同的锁

python内存管理

内存管理>>>垃圾回收机制
1.引用计数
2.标记清除
3.分代回收

死锁与递归锁

即便你记住了每acquire一次就release一次的操作,也会产生死锁现象
递归锁:可以连续的acquire(),每acquire()一次计数加一

信号量

如果把互斥锁比喻成独立卫生间,那么信号量就相当于多个卫生间,一个可以指定多个线程访问

event事件

event = Event()
        
event.set()  # 告诉另外一个子线程 你可以运行了
        
event.wait()  # 等待别人给我发set()信号

socket服务端实现并发

固定的ip和port
24小时提供服务
能够实现并发

进程池线程池

线程不可能无限制的开下去,总要消耗和占用资源

进程池线程池概念:硬件有极限,为了减轻硬件压力,所以有了池的概念
池:
    为了减缓计算机硬件的压力,避免计算机硬件设备崩溃
    虽然减轻了计算机硬件的压力,但是一定程度上降低了持续的效率
进程池线程池:
    为了限制开设的进程数和线程数,从而保证计算机硬件的安全

- concurrent.futures模块导入
- 线程池创建(线程数=cpu核数*5左右)
- submit提交任务(提交任务的两种方式)
- 异步提交的submit返回值对象
- shutdown关闭池并等待所有任务运行结束
- 对象获取任务返回值
- 进程池的使用,验证进程池在创建的时候里面固定有指定的进程数
- 异步提交回调函数的使用

协程,io密集型会提高效率

- 进程:资源单位
- 线程:执行单位
- 协程:单线程下实现并发(能够在多个任务之间切换和保存状态来节省IO),这里注意区分操作系统的切换+保存状态是针对多个线程而言,而我们现在是想在单个线程下自己手动实现操作系统的切换+保存状态的功能

协程这个概念完全是程序员自己想出来的东西,它对于操作系统来说根本不存在。操作系统只知道进程和线程。
注意:
    并不是单个线程下实现切换+保存状态就能提升效率,因为你可能是没有遇到io也切,那反而会降低效率

实现高并发的原理

将单个线程的效率提升到最高,多进程下开多线程,多线程下用协程>>> 实现高并发!!!

协程实现服务端客户端通信

链接和通信都是io密集型操作,我们只需要在这两者之间来回切换其实就能实现并发的效果
服务端监测链接和通信任务,客户端起多线程同时链接服务端
相关文章
相关标签/搜索