网络编程+并发编程
架构:B/S 和 C/S
B/S:充分发挥PC机的性能
C/S:统一了应用的接口,隶属于CS架构
OSI模型 七层
我们用五层
应用层http协议 https协议 ftp协议
传输层tcp udp 协议(四层交换机)
网络层IP协议路由器(?)(三次交换机)
数据链路层arp协议,交换机 (二层交换机)
物理层网卡,双绞线 (传输电信号)
Arp协议:通过目标ip地址获取目标mac地址
物理地址:mac地址全球唯一,每个电脑的网卡上
Ip地址:四位点分十进制三十二位点分二进制
交换机的通信方式:
单播:点对点
组播:点对多
广播:向多个pc端发送数据包
交换机和路由器的区别?
交换机是组织局域网的,经过内部处理解析数据,将数据已点对点,点对多的方式发送给目标
路由器是跨网段的数据传输,路由出网络传输的最佳路径
socket 介于应用层和传输层的socket抽象层
Tcp:面向连接的,双全工的 面向字节流的,安全可靠,会发生黏包,只可以一个客户端访问。 三次握手,四次挥手
Udp:无连接的,面向数据报的,不安全,不可靠。可以同时和多个客户端通信
三次握手:(必须是客户点先发起)
1.客户端发起请求链接服务端
2.服务端收到请求,向客户端发送可以连接的请求
3.客服端收到连接,连接成功
四次挥手:(客户端和服务端都可以发起)
1.客户端发起断开连接的请求
2.服务端收到请求,然后准备断开连接的一些事物
3.服务端发送请求,我已经准备完毕,可以断开了
4.客户端收到请求,断开连接。
为什么会发生黏包:因为有缓存机制,连续发或者连续收。(在数据传输过程中,接收数据端接收数据时不知道该如何接收,造成的数据混乱现象)
合包机制:nagle算法 — 发数据的时候一点一点发,但是接收的时候会一次收到。
拆包机制:发送的数据太大,分开发送,接收的时候,最后不能刚刚接完,就会发生黏包。
都是发生在发送端。
如何解决黏包?
自定义表头:用struct模块,事先将要发送文件的大小存下来,发送 过去,然后按着指定数据开始接收。
Struct 模块 可以将一个整数,封装为一个指定(一般为4)字节数的数字,这样接收端就可以指定大小接收这个数字。
操作系统
Dos系统#单用户单任务
Windows系统#单用户多任务(早起的Windows)
Unix系统#多用户多任务
操作系统的作用:1)封装接口,让用户方便使用 2)对系统资源的分配与调度
计算机的五大组成部分:运算器。控制器。存储器。输入设备。输出设备。
编程语言发展史:机器语言,汇编语言,高级语言
并行:(两件事或者多件事)同一时间点,同时执行 (多个CPU)
并发:(两件事或者多件事)同一时间间隔,交替执行
阻塞:程序因为类似IO等待、等待时间等导致无法继续执行
非阻塞:程序遇到类似于IO操作时,不再阻塞等待,如果没有及时的处理IO,就会报错或者跳过等待其他操作,
同步:某一个任务的执行必须依赖另一个任务的返回结果
异步:一个任务的执行,不需要依赖另一个任务的返回,只需要告诉另一个任务一声
进程:cpu资源分配的最小单位 进程由三部分组成:代码段,数据段,PCB(进程控制块)
线程:cpu资源调度的最小单位线程由三部分组成:代码段,数据段,TCB(线程控制块)
进程的三大基本状态:
就绪状态:已经获得运行所需的所有资源,除CPU
执行状态:已经获得所有资源包括CPU,处于正在运行
阻塞状态:因为各种原因,进程放弃了CPU,导致进程无法继续执行,此时进程处于内存中,继续等待获取CPU的一种状态。ß
进程学的东西: multiprocessing
1)Process模块
线程的创建
1)直接创建
p = Process(target = func, argest = (元组形式, 为func所传的参数)) #实例化进程对象
2)继承 (Process)
多线程的开启1)for循环2)多个对象实例化
方法:
start()#开启进程
join()#感知进程的结束,异步变同步
is_alive()#判断进程是否存活
terminate()#杀死一个进程
属性:
name#获取进程名
pid#获取进程号
daemon = True #守护进程
守护进程的特点:
#当主进程代码结束后,守护进程随主进程结束
#守护进程不能再创建子进程
#守护进程必须在start之前
2)锁 Lock模块(互斥锁/同步锁)
lock = Lock()#实例化一个锁对象
lock.acquire()#上锁
lock.release()#解锁
RLock模块(递归锁)
递归锁可以同时acquire多次,但是必须acquire几次就必须release几次。都在就会陷入死锁状态
死锁
典型的例子:科学家吃面 (一个人拿着面,一个人拿着叉子,到最后谁也吃不上面)
信号量Semaphore模块
sem = Semaphore(int数据类型)#可以指定有多少线程可以同时拿到锁
sem.acquire()#需要上锁将这些数据锁住
sem.release()
事件Event模块
e = Event()
e.wait()#根据is_set()的状态来决定,自身的阻塞状态 如果is_set()为False则为阻塞,如果is_set()为True则为非阻塞
e.is_set()#默认为False,
e.set()#将is_set()的状态变为True
e.clear()#将is_set()的状态变为False
典型例子:红绿灯事件
3)进程间通信(IPC)
Queue模块#队列 先进先出 First in first out
q = Queue()#创建队列对象(可以指定大小)
q.put() #向队列中添加元素(如果队列以满处于阻塞状态,只有当队列不满才可以继续添加)
q.get()#取出队列中元素(如果队列中元素为空处于阻塞状态,只有对列中有元素才可以继续取出)
q.full()#判断一个对列是否 已满
q.empty()#判断一个对列是否为空
q.put_nowait() #不阻塞,如果可以继续往队列中放数据就继续放,不能放就报错
q.get_nowait() #不阻塞,如果有数据就直接获取,没有数据就报错
JoinableQueue()模块
q = JoinableQueue()
#继承了Queue模块,但是新增了两个方法
q.task_done() #统计对列q有多少个元素被拿走(拿走一个数据就给join返回一个结果),通常与q.get()在一起用 用于生产者
q.join()#感知一个对列的数据被全部执行完毕 与q.put()在一起用 用于消费着
队列 = 管道 + 锁
重点:生产者消费着模型
Pipe模块#管道 (本身是不安全的) (双全工)
p = Pipe()
conn1, conn2 = Pipe()
管道是不安全的
管道是用于多进程之间通信的一种方式
如果在单进程中使用管道,那么就是conn1收数据,conn2发数据
如果是conn1发数据,那么conn2收数据
如果在多进程中使用管道,那么就必须是父进程中用con1收,子进程中使用conn2发
父进程使用conn1发,子进程中使用conn2收
父进程使用conn2收,子进程中使用conn1发
父进程使用conn2发,子进程中使用conn1收
在管道中有一个著名的错误叫做EOFERrror。
是指:父进程中如果关闭了发送端,子进程还继续接受数据,那么就会引发EOFError
4)数据共享Manager模块 Value模块
men = Manager()
(1)
m.list(列表数据)
m.dict(字典数据)
(2)
with Manager() as m:
……
5)进程池Pool模块
p = Pool(os.cup_count() +1)#开启多进程之后,每次处理数据只能指定个数个处理
p.close()
p.join()#close在join之前
方法:
map(func, itreable)#异步处理 itreable ,有返回值,返回值是,每一个func的返回值组成的列表, 自带close和join
apply(func, argest)#同步处理有返回值,返回值为func的返回值 不需要加close和join
apply_async(func, argest, callback)#异步处理,有返回值,返回一个对象,这个对象有get方法,可以获取func的返回值
#这个get只能一个一个获取,以我们一般处理完所有线程后再获取数据
#func的返回值可以作为参数传给callback这个回调函数。回调函数在主进程中执行
apply函数中的所有进程都为普通进程
apply_async函数中的所有进程都为守护进程
线程学的东西:threading
GIL:全局解释器锁(只有CPython才有)
锁的是线程:同一时间只允许一个线程访问CPU #(没有真正的并行)
1)Thread模块
线程的创建
1)t = Thresd(target= func. argest = (元组,为func所传的参数)) 实例化线程对象
2)继承
多线程的创建
1)for 循环
2)直接实例化多个对象
2)锁
Lock#互斥锁(同步锁)
RLock #递归锁
死锁#死锁
信号量Semaphore模块
sem = Semaphore(int数据类型)#可以指定有多少线程可以同时拿到锁
sem.acquire()#需要上锁将这些数据锁住
sem.release()
事件Event模块
e = Event()
e.wait()#根据is_set()的状态来决定,自身的阻塞状态 如果is_set()为False则为阻塞,如果is_set()为True则为非阻塞
e.is_set()#默认为False,
e.set()#将is_set()的状态变为True
e.clear()#将is_set()的状态变为False
3)条件Condition模块
条件是让程序员自行去调度线程的一个机制
方法:
acquire()
release()
wait() #让线程阻塞住
notify(int数据类型)#是指给wait发一个信号,让wait变成不阻塞#int数据类型,是指你要给多少wai发信号
4)定时器Timer模块
创建:Timer(time, func)
#time:睡眠时间,以秒为单位
#func:睡眠之后,需要执行的任务
5)线程池
进程与线程的区别:
进程资源分配的基本单位,线程是cpu调度的基本单位。
线程不可以自己独立拥有资源。线程的执行,必须依赖于所属进程中的资源。
进程中必须至少应该有一个线程。
线程和进程的比较:
1)cpu切换进程比切换线程慢很多,在python中如果IO操作过多的话,使用线程最好
2)在同一个进程内,所有线程共享这个进程pid,也就是说所有线程共享所属进程的所有资源和内存地址
3)在同一个进程内,所有线程共享该进程中的全局变量
4)因为GIL锁的存在,在CPython中,没有真正的线程并行。但是有真正的多进程并行
当你的任务是计算密集的情况下,使用多进程好。
总结:在CPython中,IO密集用多线程,计算密集用多线程。
5)关于守护线程和守护进程的事情:(注意:代码执行结束,并不代表程序结束)
守护进程:要么自己正常结束,要么根据父进程的代码执行结束而结束
守护线程:要么自己正常结束,要么根据父线程的执行结束而结束(会等其余子线程运行结束)
![网络编程+并发编程—总结](http://p2.ttnews.xyz/loading.gif)
閱讀更多 程序猿Monster 的文章