网络编程+并发编程—总结

网络编程+并发编程

架构: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)关于守护线程和守护进程的事情:(注意:代码执行结束,并不代表程序结束)

守护进程:要么自己正常结束,要么根据父进程的代码执行结束而结束

守护线程:要么自己正常结束,要么根据父线程的执行结束而结束(会等其余子线程运行结束)

网络编程+并发编程—总结


分享到:


相關文章: