网络基本概念:
1、主机:
2、端口:
3、ip:
4、缓冲区功能:协调读写速度,减少和磁盘交互.
5、文件描述符:每一个IO操作系统都会为其分配一个不同的正整数,该正整数即为此IO操作的文件描述符。通常从3开始往后排.
6、高内聚:单个模块功能尽量单一
7、低耦合:模块之间尽量减少关联和影响
8、协议(网络协议):在网络通信中,各方必须遵守的规定。包括建立什么样的连接,消息结构等。
9、https:HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。
10、IO密集型程序:程序的执行过程中进行大量的IO操作,而只有较少的cpu运算。消耗计算机资源较少,运行时间长。
11、CPU密集型程序(计算密集型):程序运行中需要大量CPU运算,IO操作较少。消耗CPU资源多,运行速度快。
12、五元组:源IP地址、源端口、目的IP地址、目的端口、传输层协议这五个量组成的集合。
osi七层模型:
应用层:提供用户服务,具体内容由特定程序规定
表示层:数据的压缩优化
会话层:建立应用连接,选择传输层服务
传输层:提供不同的传输服务,流量控制
网络层:路由选择,网络互连
链路层:提供链路交换,具体消息以帧发送
物理层:物理硬件,接口网卡线路
协议都有哪些:
应用层:TFTP HTTP DNS SMTP
传输层:TCP UDP
网络层:IP
物理层:IEEE
三次握手和四次挥手:
三次握手:建立数据传输两端的持续连接:
1、客户端向服务器发起连接请求
2、服务器收到连接请求进行确认,返回报文
3、客户端收到服务器确认进行连接创建
四次挥手:断开连接的两端,保证数据的传输完整
1、主动方发送报文,告知被动方要断开连接
2、被动方返回报文,告知收到请求,准备断开
3、被动方再次发送报文,告知准备完毕可以断开
4、主动方发送报文完成断开
tcp流式套接字 和 udp数据报套接字 的区别:
协议的层面上的区别:
1、tcp提供可靠的传输服务,可靠性表现在:数据在传输过程中,无失序、无差错、无重复、无丢失;udp不保证传输的可靠性
2、tcp传输过程中有建立和断开连接的过程:三次握手和四次挥手;udp无需建立三次握手和四次挥手的连接断开过程
3、tcp适合文件的上传下载,网络情况良好;udp网络情况较差,对可靠性要求不高,收发消息的两端不适合建立固定连接
编程的层面上的区别:
1、流式套接字采用字节流的方式传输数据,而数据报套接字以数据报形式传输
2、tcp会产生粘包现象,udp消息是有边界的,不会粘包
3、tcp传输是建立在连接的基础上,保证传输的可靠性,而udp一次接收一个数据报,不保证完整性
4、tcp需要依赖listen、accept建立连接,udp不用
5、tcp收发消息使用recv、send,udp用recvfrom、sendto
套接字:
tcp流式套接字:
服务端流程:
from socket import *
创建套接字:sockfd=socket(AF_INET,SOCK_STREAM)
绑定服务端地址:sockfd.bind(('127.0.0.1',8888))
监听套接字:sockfd.listen(2)
创建连接:connfd,addr=sockfd.accept()
接收消息:data=connfd.recv(1024)
发送消息:n=connfd.send(b'Receive your message\n')
print('Send %d bytes data'%n)
关闭连接套接字:connfd.close()
关闭服务端套接字:sockfd.close()
客户端流程:
创建套接字:sockfd=socket()
发起连接请求:sockfd.connect(('172.0.0.1',8888))
发送信息:sockfd.send(data.encode())
接收信息:data=sockfd.recv(1024).decode()
关闭套接字:sockfd.close()
补充:
sendall():
功能:同send() 作为tcp消息发送
参数:同send()
返回值:发送成功返回None,发送失败返回异常
recv()特性:
1、如果连接断开,recv会立即结束阻塞返回空字符串。
2、当接收缓冲区为空时会阻塞
3、如果recv一次接收不完缓冲区内容,下次会继续接收,确保数据不丢失
send()特性:
1、如果另一端不存在,仍使用send进行发送,则会产生BrokePipeError异常。
2、当发送缓冲区满时会阻塞
tcp粘包:
产生原因:tcp传输采用字节流的方式,消息之间没有边界,如果发送和接收速度不匹配,会造成多次发送的内容被一次接收,形成意义上的误解即粘包。
产生条件:当使用send快速的连续发送极有可能产生粘包。
影响:如果每次发送的内容代表一个独立的意思,此时产生粘包需要处理。但是如果多次发送的内容本身就是一个连续的整体,此时就不需要处理。
如何处理:
1、每次发送后加一个结尾标志,接收端通过标志进行判断。
2、发送一个数据结构
3、每次发送中间有一个短暂的延迟
udp数据报套接字:
服务端流程:
1、创建套接字:sockfd=socket(AF_INET,SOCK_DGRAM)
2、绑定服务端地址:sockfd.bind()
3、消息的收发:
接收:data,addr=sockfd.recvfrom(buffersize)
发送:n=sockfd.sendto(data,addr)
4、关闭套接字:sockfd.close()
客户端流程:
1、创建套接字:sockfd=socket(AF_INET,SOCK_DGRAM)
2、消息收发:
发送:sockfd.sendto('你好'.encode(),('127.0.0.1',8888))
接收:data,addr=sockfd.recvfrom(buffersize)
socket模块 和套接字属性
注:s表示一个套接字对象
属性:
s.type:获取套接字类型
s.family:获取地址族类型
函数:
s.fileno():获取套接字的文件描述符
s.getsockname():获取绑定地址
s.getpeername():获取tcp连接套接字另一端的地址
s.setsockopt(level,optname,value):设置套接字选项,丰富原有套接字功能
参数:
level:获取选项的类型SOL、IPP开头都是选项类型
optname:每个选项类型中的子选项
value:为选项设置值
s.getsockopt(level,optname):获取套接字选项的值
udp套接字应用之广播
一点发送多点接收
tcp套接字应用之HTTP传输
http协议---》超文本传输协议 应用层协议
用途:网页的获取,给予网站的数据传输,给予http协议的数据传输
特点:
1、应用层协议,传输层使用tcp传输
2、简单灵活,和多种语言对接方便
3、无状态协议,不记录用户的通信内容
4、成熟稳定 http1.1
工作模式:
1、使用http双方均遵循http协议规定发送接收消息体
2、请求方,根据协议组织请求内容发送给对方
3、服务方,收到内容按照协议解析
4、服务方,将回复内容按照协议组织发送给请求方
5、请求方,收到回复根据协议解析
http请求:Request
请求格式:
1、请求行
GET / HTTP/1.1
请求种类 请求内容 协议版本
请求种类:
GET:获取网络资源
POST:提交一定的附加数据,得到返回结果
HEAD:获取响应头
PUT:更新服务器资源
DELETE:删除服务器资源
CONNECT:预留
TRACE:测试
OPTIONS:获取服务器性能
2、请求头:对请求内容的具体描述
3、空行
4、请求体:提交具体的请求参数
http响应:Response
响应格式:
1、响应行:反馈具体的响应情况
HTTP/1.1 200 ok
版本信息 响应码 附加信息
响应码:
1**:提示信息 表示请求已经接受
2**:响应成功
3**:响应需要重新定向
4**:客户端错误
5**:服务器错误
常见响应码:
200:成功
404:请求页面不存在
401:没有访问权限
500:服务器发生未知错误
503:服务器暂时无法执行
2、响应头:对响应信息的具体描述
3、空行
4、响应体:将客户想要的内容进行返回
HTTPS和HTTP的区别主要如下:
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用;
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议;
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443;
4、http的链接很简单,是无状态的;https协议是由ssl+http协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
IO input output
凡是在内存中存在数据交换的操作都可以认为是IO操作
比如:
内存和磁盘交互 读写 read write
内存和终端交互 print input
内存和网络交互 send recv
IO分类:
1、阻塞IO
特点:默认形态 效率很低的一种IO
阻塞情况:
1)因为某种条件没有达到造成的阻塞:input accept recv
2)处理IO事件的时间消耗较长带来阻塞:文件的读写过程、网络数据发送过程
2、非阻塞IO
特点:通过修改IO时间的属性,使其变为非阻塞状态,即避免条件阻塞的情况
非阻塞情况:
1)往往和循环搭配使用,这样可以不断执行部分需要执行的代码,也不影响对阻塞条件的判断。
设置套接字为非阻塞:
s.setblocking() 异常:BlockingIOError
功能:设置套接字的阻塞状态
参数:设置为False
e.g.: s.setblocking(False)
while True:
print('waiting to connect ...')
try:
confd,addr=s.accept()
except BlockingIOError:
sleep(2)
print(ctime())
continue
2)超时检测:将原本阻塞的IO设置一个最长阻塞等待时间,在规定时间内如果达到条件则正常执行,如果时间到仍未达到条件则结束阻塞。
s.settimeout(sec) 异常:timeout
功能:设置套接字超时时间
参数:设置的时间
3、IO多路复用
特点:同时监控多个IO时间,当哪个IO时间准备就绪就执行哪个IO事件。此时形成多个IO时间都可以操作的现象,不必逐个等待执行。
准备就绪:IO事件即将发生的临界状态
import select:
select:支持Windows、Linux、Unix
函数原型:r,w,x=select(rlist,wlist,xlist[,timeout])
功能:监控IO事件,阻塞等待IO事件发生
参数:
rlist:列表 存放监控被动等待处理的IO事件
wlist:列表 存放需要主动处理的IO
xlist:列表 存入如果发生异常需要处理的IO
timeout:超时时间
返回值:
r:列表 rlist中准备就绪的IO
w:列表 wlist中准备就绪的IO
x:列表 xlist中准备就绪的IO
注意事项:
1、处理IO的过程中不应该有死循环出现,使一个客户端长期占有服务端。
2、IO多路复用是一种并发行为,但是是单进程程序,效率较高
poll:支持Linux、Unix
位运算:按照二进制位来进行运算操作
使用:
1、在底层做硬件寄存器的操作,最小单位就是位
2、做标志位的过滤选择
运算符:
&:按位与
|:按位或
^:按位异或
<<:左移
>>:右移
1 & 1 = 1, 1 | 1 = 1, 1 ^ 1 = 0
1 & 0 = 0, 1 | 0 = 1, 1 ^ 0 = 1
0 & 1 = 0, 0 | 1 = 1, 0 ^ 1 = 1
0 & 0 = 0, 0 | 0 = 0, 0 ^ 0 = 0
二进制:
1:0001
2:0010
3:0011
4:0100
5:0101
6:0110
7:0111
8:1000
9:1001
10:1010
代码:
from select import poll
1、创建poll对象
p=poll()
2、添加关注的IO
poll IO 事件分类:
POLLIN:rlist被动处理的事件
POLLOUT:wlist主动处理的事件
POLLERR:xlist错误处理事件
POLLHUP:断开连接
POLLPRI:紧急处理
POLLVAL:无效
p.register(s,POLLIN)
p.register(s,POLLIN|POLLERR)
3、去掉对IO的关注
p.unregister(s)
4、进行监控
events=p.poll()
功能:监控关注的IO,阻塞等待IO发生
返回值:events是一个列表,列表中每个元素为一个元组,代表准备就绪需要处理的IO
events=[(fileno:文件描述符,event:事件),(),()]
实施方法:建立比照字典{s.fileno():s}
5、
epoll:支持Linux、Unix
使用方法:与poll基本相同
区别:
1、生成对象使用epoll() 而不是poll()
2、register注册IO事件 事件类型改为epoll事件类型
select、poll、epoll区别:
1、select可以很好支持Windows
2、epoll比select和poll效率高,select和poll差不多
3、epoll提供了更多的触发方式,EPOLLET
4、事件IO
5、异步IO
本地套接字
linux 下文件类型:
b:块设备文件
c:字符设备文件
d:目录
-:普通文件
l:链接
s:套接字
p:管道
作用:用于本地不同程序间进行通信
本地套接字创建流程:与tcp相似
1、创建套接字对象
sockfd=socket(AF_UNIX,SOCK_STREAM)
2、绑定本地套接字文件
sockfd.bind(path)
path:一个文件(字符串)
3、监听
4、连接套接字文件
5、接收发送信息
多任务编程
意义:充分的利用计算机资源提高程序的运行效率
定义:通过应用程序利用计算机的多个核心达到同时执行多个任务的目的,以此来提升程序的执行效率。
实施方案:多进程 多线程
并行:多个计算机核心在同时处理多个任务,多个任务之间是并行关系。
并发:计算机同时处理多个任务,内核在多个任务间不断切换,达到好像在同时处理的运行效果。此时多个任务实际为并发关系。
进程:process
1、程序在计算机中运行一次的过程
2、进程是一个动态的过程描述,占有cpu内存等计算机资源的,有一定的生命周期
程序:是一个可执行文件,是静态的,占有磁盘,不占有计算机运行资源
注:同一个程序的不同执行过程是不同的进程,因为分配的计算机资源等均不同
进程创建流程:
1、用户空间运行一个程序,发起进程创建
2、操作系统接受用户请求,开启进程创建
3、操作系统分配系统资源,确认进程状态
4、将创建好的进程提供给应用层使用
cpu时间片:
如果一个进程占有计算机核心,我们称为该进程在cpu时间片上。多个任务实际对cpu会进行争夺,一般由操作系统分配cpu时间
PCB(进程控制块):
在操作系统中,进程创建后会自动产生一个空间存放进程信息,称为进程控制块。
进程信息:
进程PID,进程占有的内存位置,创建时间,用户。。。
进程PID:
进程在操作系统中的唯一编号,大于0的整数,由系统自动分配
进程信息查看命令:ps -aux
进程特征:
1、进程是操作系统分配计算机资源的最小单位
2、每个进程都有自己单独的虚拟内存空间
3、进程间的执行相互独立,互不影响。
进程状态:
三态:
1、就绪态:进程具备执行条件,等待系统分配cpu
2、运行态:进程占有CPU处理器,处于运行状态
3、等待态:进程暂时不具备运行条件,需要阻塞等待,让出CPU
五态:
1、新建态:创建一个新的进程,获取资源的过程
2、就绪态:进程具备执行条件,等待系统分配cpu
3、运行态:进程占有CPU处理器,处于运行状态
4、等待态:进程暂时不具备运行条件,需要阻塞等待,让出CPU
5、终止态:进程结束释放资源的过程
ps -aux ----->STAT查看进程状态
D:等待态 (不可中断等待)
S:等待态 (可中断等待)
T:等待态 (暂停状态)
R:运行态 (就绪态、运行态)
Z:僵尸态 ()
+:前台进程
<:高优先级
N:低优先级
l:有进程链接
s:会话组组长
进程优先级:
优先级决定了一个进程的执行权限和占有资源的优先程度。
查看进程优先级:
top:动态查看进程优先级 ctrl+左右翻页
取值范围:-20~19 -20优先级最高
nice:指定优先级运行程序
e.g. nice -9 ./while.py
sudo nice --9 ./while.py -9优先级
父子进程:
在系统中除了初始化进程,每个进程都有一个父进程,可能有0个或者多个子进程。由此形成父子进程关系。我们认为每个进程都是父进程发起请求创建的。
查看进程树:pstree
查看父进程PID:ps -ajx PPID进程ID号
要求:
1、什么是进程,进程和程序的区别
2、了解进程的特征
3、清楚进程的状态及状态间的转化关系
4、并行和并发的区别,操作系统功能
创建新进程
import os
pid = os.fork()
功能:创建一个新的进程
参数:无
返回值:
失败返回一个负数:-1
成功:
1、在原有进程中返回新的进程的PID
2、在新的进程中返回0
1、子进程会复制父进程全部代码段,包括fork前的代码
2、子进程从fork的下一句开始执行
3、父子进程通常会根据fork返回值的差异选择执行不同的代码(使用if结构)
4、父子进程在执行上互不干扰,执行顺序不确定
5、子进程虽然复制父进程内存空间,但是有自己的特性,如PID号、PCB等
6、父子进程空间独立,各自修改各自的内容,互不影响
进程的相关函数:
os.getpid():
功能:获取当前进程的PID号
返回值:返回PID号
os.getppid():
功能:获取当前进程的父进程PID号
返回值:返回PID号
os._exit(status):
功能:退出进程
参数:进程的退出状态 整数
sys.exit([status]):
功能:退出进程
参数:默认为0 如果是整数则表示退出状态,如果是字符串,则表示退出时打印字符串。可以通过捕获SystemExit异常阻止退出。
孤儿进程:父进程先于子进程退出,此时子进程就会成为孤儿进程。
1、孤儿进程会被系统指定的进程收养,即系统进程会成为该孤儿进程新的父进程。
2、孤儿进程退出时,该父进程会处理退出状态。
僵尸进程:子进程先于父进程退出,父进程没有处理子进程退出状态,此时子进程成为僵尸状态。
1、僵尸进程已经结束,但是会直流部分PCB信息在内存,大量的僵尸会消耗系统资源,应该尽量避免
父进程处理子进程退出状态
pid,status=os.wait()
功能:在父进程中阻塞等待处理子进程的退出
返回值:
pid:退出状态的子进程PID号
status:子进程退出状态
os.WEXITSTATUS(status):
功能:获取进程退出状态码
pid,status=os.waitpid(pid,option)
功能:同wait
参数:
pid
-1:表示任意子进程退出
>0整数:指定PID号的子进程退出
option
0:表示阻塞等待
WNOHANG:表示非阻塞
返回值:同wait
父进程先退出
创建二级子进程
1、父进程创建子进程等待子进程退出
2、子进程创建二级子进程,然后马上退出
3、二级子进程成为孤儿,处理具体事件
def fun1():
sleep(3)
print('第一件事')
def fun2():
sleep(4)
print('第二件事')
pid = os.fork()
if pid <0:
print("进程创建失败")
elif pid ==0:
pid0=os.fork()
if pid0<0:
print("创建二级进程失败")
elif pid0==0:
fun2()
else:
os._exit(0)
else:
os.wait()
fun1()
multiprocessing 模块创建进程
1、需要将要做的事件封装为函数
2、使用multiprocessing中提供的Process类创建进程对象
3、通过进程对象和Process初始化函数对进程进行设置,并且绑定要执行的事件
4、启动进程,会自动执行相关联函数
5、事件完成后回收进程
最基本使用:
Process()
功能:创建进程对象
参数:
[name:给创建的进程对象起一个名字]
target:绑定的函数
args:元组(给target函数按照位置传参)
kwargs:字典(给target函数按照键值传参
p.start()
功能:启动进程,此时进程被创建。自动运行进程函数
p.join([timeout])
功能:阻塞等待回收响应的进程
参数:超时时间
e.g.import multiprocessing as mp
from time import sleep
def fun():
sleep(3)
print("son")
p=mp.Process(target=fun)
p.start()
p.join()
特性:
1、multiprocessing创建进程是原来进程的子进程,创建后父子进程格子执行互不影响
2、子进程同样是复制父进程的空间,子进程对内容的修改不会影响父进程的空间
3、join回收子进程,会有效的阻止僵尸进程产生
4、通常使用multiprocessing创建进程,父进程只用作进程的创建和回收,不做其他工作
multiprocessing进程对象属性:
p.is_alive()
功能:判断进程生命周期状态
返回值:布尔值
p.name
功能:进程名称 默认为process-1 如果起名字则为自定义名称
p.pid
功能:返回创建子进程的pid
p.daemon
功能:
1、默认值为False,父进程退出不会影响子进程运行
2、改为True,父进程退出子进程也会退出
特性:
1、daemon 的设置必须在start前
2、如果设置daemon为True 则不再使用join
创建自己的进程类
1、继承Process类
2、重写__init__并且调用父类的__init__
3、重写run方法,此时声称对象后,调用start就会自动运行run
多进程:
优点:
1、能并行执行多个任务,提高效率
2、创建方便,运行独立,不受其他进程影响
3、数据安全
缺点:
进程的创建和删除都需要消耗计算机的资源
进程池技术:
产生原因:如果有大量任务需要多进程完成,且可能需要频繁的创建和删除进程,给计算机带来大量的资源消耗。
原理:在进程池内运行一定数量进程,通过这些进程完成进程池队列中的事件,直到事件执行完毕,减少进程不断的创建删除过程。
实施操作方法:
1、创建进程池,在进程池中放入适当进程
2、将事件加入到进程池队列
3、事件不断运行,直到所有事件运行完毕
4、关闭进程池,回收进程
from multiprocessing import Pool
pool=Poll(processes)
功能:创建进程池对象
参数:表示进程池中有多少进程
pool.apply_async(func,args,kwds)
功能:将事件放入进程池列队
参数:
func 要执行的事件
args 给func用元组传参
kwds 给func用字典传参
返回值:返回事件对象r
通过r.get()方法获取事件函数返回值
pool.apply(func,args,kwds)
功能:将事件放入进程池列队
参数:
func 要执行的事件
args 给func用元组传参
kwds 给func用字典传参
pool.close()
功能:关闭进程池,不能再添加新的事件
pool.join()
功能:阻塞等待回收进程池
pool.map(func,iter)
功能:将要完成的事件放入进程池
参数:
func 要完成的事件函数
iter 可迭代对象给func传参
返回值:事件函数的返回值列表
进程间通信
进程间由于空间独立,资源无法互相直接获取,因此在不同的进程间进行数据传递就需要专门的通信方法。
进程间通信方法(IPC):
1、管道Pipe
在内存中开辟一段空间,形成管道结构,管道对多个进程可见,进程可以对管道进行读写操作
multiprocessing中提供Pipe
fd1,fd2=Pipe(duplex=True)
功能:创建一个管道
参数:默认为双向管道,如果设置为False,则为单向管道
返回值:
双向:fd1、fd2类似于open创建的对象,可进行读写操作
单向:fd1只能读,fd2只能写
fd.recv()
功能:从管道内读取内容
返回值:读到的内容,如果管道无内容则阻塞
fd.send(data)
功能:向管道写入内容
参数:要发送的内容,几乎可以发送python支持的所有数据类型
2、消息队列
队列:先进先出
在进程中开辟队列结构空间,多个进程可以向队列投放消息,在取出的时候按照存入顺序取出
multiprocessing -->Queue
q=Queue(maxsize=0)
功能:创建队列
参数:maxsize 默认表示根据系统分配空间存储消息,如果传入一个正整数则表示最多存放多少条消息
返回:队列对象
q.put(data,[block,timeout])
功能:存放消息
参数:
data 存入的消息(python数据类型)
block:
默认True表示当队列满时阻塞
设置为False则表示非阻塞
timeout当block为True表示超时时间
data=q.get([block,timeout])
功能:取出消息
参数:
block:
默认为True 当列队空时阻塞
设置为False 表示非阻塞
timeout:当block为True时,表示是超时时间
返回值:返回获取的消息
q.full() 判断队列是否为满
q.empty() 判断队列是否为空
q.qsize() 判断当前队列有多少消息
q.close() 关闭队列
3、共享内存
在内存中开辟一段空间,存储数据,对多个进程可见。
每次写入共享内存中的数据会覆盖之前的内容。
from multiprocessing import Value
obj=Value(ctype,obj)
功能:开辟共享内存空间
参数:
ctype:字符串 要转变的c的数据类型 对比类型对照表
obj:共享内存的初始化数据
返回:共享内存对象
obj.value:表示共享内存中的值。对其修改或者使用即可。
obj=Array(ctype,obj)
功能:开辟共享内存
参数:
ctype:要转化的c的类型
obj:要存入共享内存的数据
列表:将列表存入共享内存,数据类型一直
正整数:表示开辟几个数据空间
返回:数据列表
读取修改文件:返回对象[index]=newNo.
区别:
类型 管道 消息队列 共享内存
开辟空间 内存 内存 内存
读写方式 两端读写(双向或单项) 先进先出 操作覆盖内存
效率 一般 一般 较快
应用 多用于两端通信 使用广泛 复杂,需要同步互斥机制
4、信号
一个进程向另一个进程通过信号传递某种讯息,接收方在接收到信号后进行相应的处理
查看信号:kill -1
kill -signum PID给PID的进程发送一个信号,kill在这里的意思是发送
关于信号
信号名称:信号的名字或者数字
信号含义:信号的作用
默认行为:当一个进程接收到信时采取的行为
终止行为
暂停行为
忽略产生
e.g import os
import signal
os.kill(os.getppid(),signal.SIGKILL)
通过python进行信号处理
os.kill(pid,sig)
功能:发送信号给某个进程
参数:
pid 给哪个进程发送信号
sig 要发送什么信号
signal.alarm(sec)(异步处理函数)
功能:一定时间后给吱声发送一个SIGALRM信号
参数:指定时间
注意:在一个进程中只能有一个时钟信号,设置后一个时钟会把第一个时钟覆盖掉,sleep会影响信号钟
异步处理信号:
当alarm将请求发给内核,内核会记录请求,应用程序会继续执行,不会停止,当条件达成,内核会给应用程序发送信号,应用程序会对信号进行反应,以完成信号传达的信息。条件达成后,进程已结束,内核忽略此信号.
程序执行的同步和异步
同步:按照步骤一步一步顺序执行
异步:在程序执行中利用内核,不影响应用程序持续执行
信号时唯一的异步通信方式
signal.pause()
功能:等待信号(阻塞)
signal.signal(signum,handler)(异步处理函数)
功能:处理信号
参数:
signum:要处理的信号
handler:信号的处理方法
SIG_DFL 表示使用默认的方法处理
SIG_IGN 表示忽略这个信号
def func(sig,frame) 自定义函数处理信号
sig:表示要处理的信号
frame:信号的结构对象
signal函数不能处理SIGKILL SIGSTOP信号
在父进程中使用signal(SIGCHLD,SIG_IGN),这样子进程退出时会有系统自动处理
5、信号量
给定一定的数量,对多个进程可见,并且多个进程根据信号量的多少确定不同的行为
multiprocessing---》Semaphore()
sem=Semaphore()
功能:生成信号量对象
参数:信号量的初始值
返回值:信号量对象
sem.acquire()
功能:信号量数量减1,信号量为0时会阻塞
sem.release()
功能:信号量数量加1
sem.get_value()
功能:获取当前信号量的值
e.g. from time import sleep
import os
from multiprocessing import Semaphore,Process
sem=Semaphore(3)
def fun():
print('process %d wait for semaphore'%os.getpid())
sem.acquire()
print('process %d expend semaphore'%os.getpid())
sleep(3)
print('process %d add semaphore'%os.getpid())
sem.release()
jobs=[]
for i in range(4):
p=Process(target=fun)
jobs.append(p)
p.start()
for i in jobs:
i.join()
同步互斥机制
目的:解决对共有资源操作产生的争夺
临界资源:多个进程或者线程都能操作的资源
临界区:操作临界资源的代码段
同步:是一种合作关系,为完成某个任务,多进程或者多线程之间形成一种协调。按照约定依次执行对临界资源的操作,相互告知相互促进。
互斥:互斥是一种制约关系,当一个进程占有临界资源就会进行加锁的操作,此时其他进程就无法操作该临界资源。直到使用的进程进行解锁操作后才能使用。
Event 事件
multiprocessing--》Event
创建事件对象
e.Event()
事件阻塞
e.wait([timeout])
事件设置
e.set()
功能:当e被set()后,e.wait()不再阻塞
事件清除
e.clear()
功能:e被clear()后,e.wait()又会阻塞
事件判断
e.is_set()
功能:判断当前事件对象是否被设置
锁 Lock
multiprocessing--》Lock
创建对象
lock=Lock()
上锁
lock.acquire()
上锁状态:执行acquire()操作会阻塞
解锁
lock.release()
解锁状态:执行release()不阻塞
with lock:---》上锁
……
---》with代码块执行结束即解锁
6、套接字
线程
定义:线程也是一种多任务编程的方式,可以使用计算机多核资源。线程又被称为轻量级的进程。
特征:
1、线程是计算机核心分配的最小单位
2、一个进程可以包含多个线程
3、线程也是一个运行过程,也要消耗计算机资源。多个线程共享其进程的资源和空间。
4、线程也拥有自己特有的资源属性,比如指令集,TID等。
5、线程无论是创建还是删除还是运行,资源消耗都小于进程
6、多个线程之间并行执行,互补干扰。
创建线程
threading模块
threading.Thread()
功能:创建线程对象
参数:
name:线程名称
target:线程函数
args:元组 给线程函数传参
kwargs:字典 给线程函数传参
t.start()
功能:启动线程
t.join([timeout])
功能:回收线程
线程属性
t.is_alive()查看线程状态
t.name()线程名称
t.setName()设置线程名称
threading.currentThread()获取当前县城对象
t.daemon 默认情况下,主线程的结束不会影响分支线程,如果设置为True 则主线程退出分支线程也会退出
设置方法:
t.daemon=True
t.setDaemon(True)
判断daemon属性:
t.isDaemon()
注:线程daemon属性的设置在start前
一般设置daemon后不会再使用join
创建自己的线程类
1、继承Thread类
2、运行Thread类中的__init__方法以获取父类属性
3、重写run方法
threadpool(线程池,第三方模块)
线程通信
通信方法
多个线程共用进程空间,所以进程的全局变量对进程内的线程均可见。因此使用全局变量通信是线程主要通信方法。
注意事项
线程间通信更容易产生资源争夺,往往需要同步互斥机制保证通信安全。
线程的同步互斥
threading--》Event()
操作
from threading import Thread,Event
e=Event()
e.wait([timeout])如果e为设置状态则不阻塞,未设置则阻塞
e.set()将e变为设置状态
e.clear()将e设置去除
线程锁
lock=threading.Lock()创建锁
lock.acquire()上锁
lock.release()解锁
操作原理:重复上锁acquire会阻塞
Python线程GIL问题
GIL:全局解释器锁
后果:一个解释器,同一时刻只能解释一个线程。并行变并发。大大降低了python多线程的执行效率。
Python 的GIL问题 解决方案
1、尽量使用进程
2、不使用c作为解释器
3、Python线程适用于高延迟的IO操作,网络操作,不适合cpu密集型或者传输速度很快的IO操作
注意:线程遇到阻塞会让出解释器
进程线程区别联系:
1、两者都是多任务编程方式,都能使用计算机多核资源
2、进程的创建和删除要比线程消耗更多的计算机资源
3、进程空间独立,数据安全性好,有专门的通信方法
4、线程使用全局变量通信,更加简单,但往往需要同步互斥
5、一个进程可以包含多个线程,线程共享进程的资源
6、进程线程都有自己的特有属性资源,如命令,属性,id等
使用场景:
1、如果需要创建较多的并发,任务比较简单,线程比较合适
2、如果数据和功能比较独立,此时使用进程比较合适
3、使用线程时要考虑到同步互斥的复杂程度
4、python线程需要考虑到GIL问题
服务器模型
硬件服务器:主机 集群
厂商:IBM HP 联想 浪潮
软件服务器:
编写的服务端程序,依托于硬件服务器运行,提供给用户一定的软件服务。
分类:
webserver:网络后端程序提供网站请求的后端处理和响应
httpserver:处理http请求,回复http响应
邮箱服务器:处理邮件
文件服务器:处理文件传输
功能:
网络连接
逻辑处理
数据的交互
数据的传输
协议的实现
模型结构:
c/s:客户端服务器模型
b/s:浏览器服务器模型
服务器目标:
处理速度快
数据更安全
并发量大
硬件方面:
更高的配置
集成分布基础
更好的网络速度
更多主机
更好的网络安全性
软件方面:
程序占有更少的资源
更稳定的运行效果
更流畅的运行速度
采用更安全更合适的技术
基础服务器模型
循环服务器
单进程程序,循环接收客户端请求,处理请求,每处理完一个请求再去接收下一个请求。
优点:
实现简单,占用资源少
缺点:
无法同时连接多个客户端,当一个客户端长期占有服务器时,形成其他客户端无法操作的情况
使用情况:
任务比较短暂,udp套接字更合适
并发服务器
同时处理多个客户端的任务请求
io并发:io多路复用 协程
优点:
资源消耗少,效率较高,适用于IO类型服务器
缺点:
不能监控cpu密集型程序,本质是单进程所以不能长期阻塞消息的收发
多进程、多线程并发
为每一个客户端单独提供一个进程或者线程处理请求。由于进程线程执行独立所以对其他进程不会有影响
优点:
客户端可以长期占有服务器,操作不会对其他进程现场产生影响
缺点:
消耗资源较多
多进程并发
使用 fork 完成并发
1、创建套接字,绑定,监听
2、等待接收客户端请求 accept
3、创建子进程处理客户端请求
父进程继续等待其他客户端连接
4、客户端退出则子进程退出
多线程并发
每有一个用户客户端就创建一个新的线程处理客户端请求
对比多进程:
优点:资源消耗少
缺点:需要处理共享资源,注意GIL问题
实现步骤
1、创建套接字,绑定,监听
2、接收客户端请求,创建新的线程
3、主线程继续等待其他客户端连接,分支线程执行客户端请求
4、处理完客户端请求后,分支线程退出,关闭客户端套接字
多进程并发的HTTPsever
接收浏览器的http请求
对请求进行解析
根据解析判断请求内容
将要返回的内容组织成http响应格式发送给客户端
升级:
使用多线程并发
增加具体请求解析
增加数据获取功能
封装用类
技术实现:
threading 并发 tcp套接字
tcp socket传输
HTTP协议响应和请求的格式
socket 中的服务器的继承模块
python2 SocketServer
python3 socketserver
功能:
通过模块的接口完成基于多进程/多线程的tcp/udp的socket并发程序
多进程tcp服务器
from socketserver import *
class Server(ForkingMixIn,TCPServer):
pass
class Handler(StreamRequestHandler):
def handle(self):
print(self.request.getpeername())
while True:
data=self.request.recv(1024).decode()#接收消息
if not data:
break
print(data)
self.request.send(b'1111111')#发送消息
server=Server(('0.0.0.0',8888),Handler)
server.serve_forever()
多进程udp服务
from socketserver import*
class Server(FokingUDPServer):
pass
class Handler(DatagramRequestHandler):
def handle(self):
while True:
data=self.rfile.readline().decode()#接收消息
if not data:
break
print(data)
self.wfile.write(b'11111111')#发送消息
server=Server(('0.0.0.0',8888),Handler)
server.serve_forever()
库的方法:
sys.argv:
功能:获取来自命令行的参数,形成一个列表,以空格作为每一项分隔,如果一项中有空格则用引号表示一个整体,命令行内容均作为字符串传入。
format():合成字符串
sys.stdin:输入
sys.stdout:输出
select.EPOLLET:边缘触发
os.path.exists(path):
功能:判断一个文件夹下是否有某个文件
os.unlink(path) 或 os.remove(path):
功能:删除一个文件
获取文件大小
os.path.getsize(path)
功能:获取一个文件的大小
参数:文件
os.listdir(PATH):获取文件夹下的所有列表
os.path.isfile(file):判断一个文件的类型是否为普通文件
os.path.isdir(file):判断一个文件的类型是否为目录