day23作业:
1 from select import select 2 from socket import * 3 import sys 4 from time import ctime 5 6 s = socket() 7 s.bind(('0.0.0.0',8888)) 8 s.listen(3) 9 10 #监控 11 rlist = [s,sys.stdin]#标准输入 12 wlist = [] 13 xlist = [] 14 15 #日志文件 16 f = open('log.txt','a') 17 18 #训话监控 19 while True: 20 rs,ws,xs = select(rlist,wlist,xlist) 21 for r in rs: 22 if r is s: 23 c,addr = r.accept() 24 rlist.append(c) 25 elif r is sys.stdin: 26 f.write("%s %s"%(ctime(),r.readline()))#在终端度一行内容并写入 27 f.flush()#刷新文件缓冲 28 else: 29 data = c.recv(1024) 30 if not data:#如果客户端退出 31 rlist.remove() 32 r.close() 33 continue 34 f.write("%s %s "%(ctime(),data.decode())) #在文件中追加当前时间... 35
1 from socket import * 2 3 #创套接字 4 sockfd = socket() 5 6 #发起连接 7 server_addr = ('172.40.71.149',8888) 8 sockfd.connect(server_addr) 9 10 #收发消息 11 while True: 12 #发 13 data = input(">>") 14 sockfd.send(data.encode()) 15 if not data: 16 break 17 #收 18 # data = sockfd.recv(1024) 19 # print("From server:",data.decode()) 20 21 #关闭套接子 22 sockfd.close() 23
一.基于poll方法的IO多路复用
1.select。poll()
功能:创建poll对象
返回值:poll
2.p.register(fd,event)
功能:注册关注的IO事件
参数:fd 要关注的IO
event 要关注的IO事件类型
* 常用类型:POLLIN 读IO事件 (rlist)
POLLOUT 写IO事件(wlist)
POLLERR 异常IO (xlist)
POLLHUP 断开连接
*e.g. p.register(sockfd,POLLIN)#关注套接字的读事件
p.register(sockfd,POLLIN|POLLERR)#关注套接字的读事件
p.register(sockfd)#关注所有事件(尽量不用)
p.unregister(fd)
功能:取消对IO的关注
参数:IO对象或者对象的frieno
*函数可以返回实例化对象
3. enents = p.poll()#对象的方法
功能:阻塞等待监控的IO事件发生
返回值:返回发生的IO
events格式 [(fileno,event),()...]
每个元组为一个就绪IO,元组第一项是该IO的fileno,
第二项为该IO的就绪的事件类型
* 需要通过fileno寻找对应的IO对象,建立对应字典确保字典中IO和关注的IO时刻保持一致
字典格式:{fileno:io_obj}
4.poll_server 步骤
【1】创建套接字
【2】将套接字register
【3】创建查找字典,并维护
【4】循环建监控IO发生
【5】处理发生的IO
1 from socket import * 2 from select import * 3 4 #创建要关注的IO 5 s = socket() 6 s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) 7 s.bind(('0.0.0.0',8888)) 8 s.listen(5) 9 10 #创建poll对象 11 p = poll() 12 13 #建立查找字典 14 fdmap = {s.fileno():s} 15 16 #注册ID 17 p.register(s,POLLIN|POLLERR) 18 19 20 #循环监控 21 while True: 22 events = p.poll()#阻塞,返回列表 23 #遍历列表,处理IO 24 #元祖:fd文件描述符,event事件 25 for fd,event in events: 26 27 if fd ==s.fileno():#s就绪(监听套接字准备就绪) 28 c,addr = fdmap[fd].accept() 29 print("Connect from",addr) 30 #添加新的注册ID 31 p.register(c,POLLIN|POLLHUP) 32 fdmap[c.fileno()] = c 33 34 elif event & POLLHUP: 35 print("客户端退出") 36 p.unregister(fd)#取消关注 37 fdmap[fd].close() 38 del fdmap[fd] 39 40 elif event & POLLIN:#真->pollin就绪;假-->poll未就绪 41 data = fdmap[fd].recv(1024) 42 print("Receive:",data.decode()) 43 fdmap[fd].send(b'Receive your msg') 44
1 from socket import * 2 3 #创套接字 4 sockfd = socket() 5 6 #发起连接 7 server_addr = ('172.40.71.149',8888) 8 sockfd.connect(server_addr) 9 10 #收发消息 11 while True: 12 #发 13 data = input(">>") 14 sockfd.send(data.encode()) 15 if not data: 16 break 17 #收 18 data = sockfd.recv(1024) 19 print("From server:",data.decode()) 20 21 #关闭套接子 22 sockfd.close() 23
二.基于epoll方法的IO多路复用
* 生成对象改为epoll()
* 生成对象事件类型改为EPOLL类型
epoll特点:
*epoll 效率比select poll 要高
*epoll(一直申请) 监控IO数量比select(1024)多
*epoll的触发方式比poll要多(EPOLLET边缘触发)
1 from socket import * 2 from select import * 3 4 #创建要关注的IO 5 s = socket() 6 s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) 7 s.bind(('0.0.0.0',8888)) 8 s.listen(5) 9 10 #创建poll对象 11 p = epoll() 12 13 #建立查找字典 14 fdmap = {s.fileno():s} 15 16 #注册ID 17 p.register(s,EPOLLIN|EPOLLERR) 18 19 20 #循环监控 21 while True: 22 events = p.poll()#阻塞,返回列表 23 #遍历列表,处理IO 24 #元祖:fd文件描述符,event事件 25 for fd,event in events: 26 27 if fd ==s.fileno():#s就绪(监听套接字准备就绪) 28 c,addr = fdmap[fd].accept() 29 print("Connect from",addr) 30 #添加新的注册ID 31 p.register(c,EPOLLIN|EPOLLHUP) 32 fdmap[c.fileno()] = c 33 34 elif event & EPOLLHUP: 35 print("客户端退出") 36 p.unregister(fd)#取消关注 37 fdmap[fd].close() 38 del fdmap[fd] 39 40 elif event & EPOLLIN:#真->pollin就绪;假-->poll未就绪 41 data = fdmap[fd].recv(1024) 42 print("Receive:",data.decode()) 43 fdmap[fd].send(b'Receive your msg') 44 45 46
1 from socket import * 2 3 #创套接字 4 sockfd = socket() 5 6 #发起连接 7 server_addr = ('172.40.71.149',8888) 8 sockfd.connect(server_addr) 9 10 #收发消息 11 while True: 12 #发 13 data = input(">>") 14 sockfd.send(data.encode()) 15 if not data: 16 break 17 #收 18 data = sockfd.recv(1024) 19 print("From server:",data.decode()) 20 21 #关闭套接子 22 sockfd.close() 23
三.struct模块的使用
1.原理:将一组金丹数据进行打包,转换为bytes格式发送。或者将一组bytes格式数据,进行解析。
2.接口使用
[1] Struct(fmt)
功能:生成结构化对象
参数:fmt 定制了数据结构
e.g. 要发送数据 1 b'zhangsan' 1.75
fmt参数 "i8sf"(8个字串)
[2]st.pack(v1,v2,v3...)
功能:将一组数据按照指定格式打包转换为bytes
参数:要打包的数据
返回值:bytes字节串
[3]st.unpack(bytes)
功能:将bytes字节串按照指定的格式解析
参数:要解析的字符串
返回值:解析后的内容
[4]struct.pack(fmt,v1,v2,v3...)
struct.unpack(fmt,bytes_data)
说明:可以使用struct模块直接调用pack unpack
此时这两个参数传入fmd,其他用发功能相同
1 from socket import * 2 import struct 3 4 s = socket(AF_INET,SOCK_DGRAM) 5 s.bind(('0.0.0.0',8888)) 6 7 #确定数据结构 8 st = struct.Struct('i16sf') 9 10 while True: 11 data,addr = s.recvfrom(1024) 12 #解析 13 data = st.unpack(data) 14 print(data) 15 16 s.close()
1 from socket import * 2 import struct 3 4 ADDR = ('172.40.71.149',8888) 5 s = socket(AF_INET,SOCK_DGRAM) 6 7 while True: 8 my_id = int(input("id:")) 9 name = input("name:") 10 height = float(input("height:")) 11 # len = len(name) 12 13 fmt = "i16sf" 14 data = struct.pack(fmt,my_id,name.encode(),height) 15 s.sendto(data,ADDR) 16 17 s.close()
四.本地套接字
1.功能:用于本地的两个程序之间进行数据的收发
2.套接字文件:用于本地套接字之间通信时,进行数据传输的介质。
3.创建本地套接字的流程
【1】创建本地套接字
socket = sorted(AF_UNIX,SOCK_STREEAM)
【2】绑定本地套接字文件
sockfd.bind(file)
【3】监听,接收客户端连接,消息收发
listen()-->accept()-->recv(),send()
cookie:Linux下文件类型
b(块设备文件)
c(字符设备文件)
d(目录)
-(普通文件)
l(连接文件)
s(套接字文件)
p(管道文件)
1 from socket import * 2 import os 3 4 #确定套接字文件 5 sock_file = './sock' 6 7 #判断文件是否存在,存在就删除 8 if os.path.exists(sock_file): 9 os.remove(sock_file) 10 11 12 #创建本地套接字 13 sockfd = socket(AF_UNIX,SOCK_STREAM) 14 15 #绑定套接字文件 16 sockfd.bind(sock_file) 17 18 #监听,连接 19 sockfd.listen(3) 20 while True: 21 c,addr = sockfd.accept() 22 while True: 23 data = c.recv(1024) 24 if not data: 25 break 26 print(data.decode()) 27 c.close() 28 sockfd.close()
1 from socket import * 2 3 #确保两边使用同一个套接字文件 4 sock_file = './sock' 5 sockfd = socket(AF_UNIX,SOCK_STREAM) 6 sockfd.connect(sock_file) 7 8 while True: 9 msg = input(">>") 10 if not msg: 11 break 12 sockfd.send(msg.encode()) 13 14 sockfd.close()
五.多任务编程
1.意义:充分利用计算机多核咨询,提高程序的运行效率
2.实现方案:多进程 ,多线程
3.并行,并发概念
* 并发:同时处理多个任务,内核咋任务间不断切换达到多个任务被同时执行的效果,
实际每个时刻只有一个任务占有内核
* 并行:多个任务利用计算机多核资源在同时执行,此时多个任务间同时为并行关系。
六.进程(process)
1.定义:程序在计算机中的一次运行
* 程序是一个可执行的文件是静态的占有磁盘
* 进程是一个动态的过程描述,占有计算机运行资源,有一定的生命周期
2. 如何产生一个进程
【1】用户空间通过调用程序接口命令发起请求
【2】操作系统接收用户请求,开始创建进程
【3】操作系统调配计算机资源,确定进程状态等
【4】操作系统将创建的进程提供给用户使用
3.进程概念
* cpu时间片:如果一个进程占有cpu内核则称这个进程在cpu时间片上
*PCB(进程控制块):在内存中开辟的一块空间,用于存放进程的基本信息,
也用于系统查找识别进程
*进程ID(PID):系统为每个进程分配的一个大于0 的整数,作为进程ID,每个ID不会重复。
Linux查看进程ID:ps -aux
* 父子进程:系统中每一个进程(除了系统初始化进程)
都有唯一的父进程,可以有0个或多个子进程。父子进程关系便于进程管理
查看进程树:pstree
*进程状态
三态:
就绪态:进程具备执行条件。等待分配cup资源
运行态:进程占有cpu时间片正在运行
等待态:进程暂停时停止运行。
五态:
新建:创建一个进程,获取资源的过程
终止:进程结束,释放资源的过程
状态查看命令:ps -aux --->STAT列
S 等待态
R 执行态
D 等待态
T 等待态
Z 僵尸
< 有较高优先级
N 优先级较低
+ 前台进程
s 会话组组长
l 有多线程的
面试要求:1.什么是进程,进程和程序有什么区别
2.进程有哪些状态,状态之间如何转化
作业:1.对要求问题总结回答
2.整理网络编程重点程序
能够自己写出 tcp服务器 udp服务端 select服务端 poll服务端