前情回顾
本地套接字 : 本地进程间实现通信
socket(AF_UNIX,SOCK_STREAM)
进程 :一次执行的过程
进程特征和概念
PCB 虚拟内存 PID 父子进程 孤儿进程 僵尸进程
ps -aux pa -ajx top nice renice
进程的状态
三态 五态
fork()
多程序 : 无法根据情况动态创建进程
通过接口创建进程:便于控制,可以在程序运行中随时根据需要创建
getpid getppid sys.exit os._exit
处理僵尸进程
1.让父进程先结束
2.父进程处理子进程的退出
wait waitpid
处理信号
3. 创建二级子进程
********************************************
os.waitpid(pid,option)
功能: 处理子进程的退出
参数: pid : -1 表示等待任意的子进程退出
>0 表示等待相应PID号的子进程
option: 0 表示阻塞等待
WNOHANG :表示非阻塞等待
返回值: 同 wait
os.waitpid(-1,0) ==== os.wait()
创建二级子进程
父进程创建子进程后等待子进程退出
子进程创建二级子进程后马上退出,二级子进程成为孤儿
让父进程和二级子进程处理具体事件
群聊聊天室
*选择使用什么样的套接字
udp
转发 客户端 ---》 服务器 ---》 其他客户端
用print简单打印命令操作提示
存储用户 列表 字典
使用函数或者类来包装功能
没完成一个功能检测一个功能
*功能描述
#类似于qq群聊 ,用户在加入聊天室时有一个简单的登录
输入用户名即可
实现 : 客户端输入用户名,发送给服务器,服务器存储
#需要个数据结构保存用户
收到发过来的用户名 放到列表或者字典中
#当一个人发送消息 其他人可以接受消息
张三 : xxxxxx
实现 : 客户将消息发送给服务器,服务器遍历列表,进行转发
#当一个人登录 退出时给其他人一些提示
xxx login
xxx logout
实现:给服务器发送登录退出消息,服务器转发
# 管理员发送消息 全部在线成员均可收到
实现 : 服务端可控制消息发送,给所有人
server:
def login:
def chat:
def main()
multiprocessing 模块创建进程 标准库
1. 需要将事件封装为函数
2. 使用multiprocessing提供的类创建新进程
3. 新的进程和对应的函数相关联,进程启动会自动执行函数,完成事件
4. 进程回收
创建子进程类
multiprocessing.Process()
功能 : 创建子进程
参数 : name : 给创建的进程起一个名字
默认 process-1
target : 目标函数
args :元组 要给函数传递的参数 位置
kwargs : 字典 要给函数传递的参数 键值
进程对象属性函数
p.start()
功能 : 启动子进程 此时进程真正创建
p.join([timeout])
功能 : 阻塞等待回收相应的子进程
参数 : 默认为阻塞,timeout为超时时间
p的其他属性
p.name 进程名称
p.pid 创建的进程的PID号
p.is_alive() 进程状态
p.daemon
默认值为False 表示主进程结束后 不影响子进程的执行
如果设置为True 则主进程执行完毕所有的子进程一同退出
* 设置必须在 start()前
* 一般使用daemon = True时不用加join
* 该属性并不是 linux/unix系统中所说的守护进程设置
守护进程 : 生命周期长,随系统创建随系统销毁。
不受前端控制,后台运行
操作系统进程,或者是自动化运行进程居多
作业 : 编写一个程序,使用multiprocessing
要求创建两个进程来复制一个文件,各复制一半(以字节来分)
下面是python程序
**********************************************************************
#创建二级子进程处理僵尸
import os
#创建一级子进程
pid1 = os.fork()
if pid1 < 0:
print("创建一级子进程失败")
elif pid1 == 0:
#创建二级子进程
pid2 = os.fork()
if pid2 < 0:
print("创建二级子进程失败")
elif pid2 == 0:
print("做另一件任务")
else:
#一级子进程退出,使二级子进程成为孤儿
os._exit(0)
else:
#等待一级子进程退出
os.wait()
print("做父进程该做的")
**********************************************************************
import multiprocessing as mp
import os
import time
a = 1
def th1():
global a
a = 1000
print("th1 a",a)
print(os.getppid(),"----",os.getpid())
print("吃饭早饭")
time.sleep(1)
print("吃饭午饭")
time.sleep(2)
print("吃饭晚饭")
time.sleep(3)
def th2():
print(os.getppid(),"----",os.getpid())
print("睡觉午觉")
time.sleep(2)
print("睡觉")
time.sleep(3)
print("th2 a:",a)
def th3():
print(os.getppid(),"----",os.getpid())
print("打豆豆")
time.sleep(2)
print("打豆豆")
time.sleep(2)
#创建三个新的进程,关联上面三个事件
#生产进程对象分别表示这三个进程
p1 = mp.Process(target = th1)
p2 = mp.Process(target = th2)
p3 = mp.Process(target = th3)
#通过生成的进程对象启动子进程
#子进程有父进程的代码段 只不过只执行对应的函数
p1.start()
p2.start()
p3.start()
print("Parent PID",os.getpid())
#阻塞等待回收进程
p1.join()
p2.join()
p3.join()
print("++++++++++++++++++++++++")
# th1()
# th2()
# th3()
*****************************************************************
from multiprocessing import *
from time import sleep
a = 1
def worker(sec,msg):
print("a = ",a)
for i in range(3):
sleep(sec)
print("worker message:",msg)
# 位置传参
# p = Process(target = worker,args = (2,"hello")
# 字典传参
p = Process(name="worker",target = worker,
args = (2,),kwargs = {'msg':"hello"})
p.start()
print("p.name :",p.name)
#p所代表的子进程的PID号
print("p.pid:",p.pid)
print("p.alive",p.is_alive())
p.join()
*******************************************************************
import multiprocessing as mp
import os
import time
def th1():
print(os.getppid(),"----",os.getpid())
print("吃饭早饭")
time.sleep(1)
print("吃饭午饭")
time.sleep(2)
print("吃饭晚饭")
time.sleep(3)
def th2():
print(os.getppid(),"----",os.getpid())
print("睡觉午觉")
time.sleep(2)
print("睡觉")
time.sleep(3)
def th3():
print(os.getppid(),"----",os.getpid())
print("打豆豆")
time.sleep(2)
print("打豆豆")
time.sleep(2)
things = [th1,th2,th3]
process = []
for th in things:
p = mp.Process(target = th)
p.daemon = True
process.append(p)
p.start()
print("+++++++父进程++++++++")
# for i in process:
# i.join()
****************************************************************
import os,sys
from time import sleep
pid = os.fork()
if pid < 0:
print("Create process failed")
elif pid == 0:
print("Child process...")
sleep(2)
sys.exit(2)
else:
#设置为非阻塞状态,循环处理查看子进程状态
while True:
p,status = os.waitpid(-1,os.WNOHANG)
sleep(0.5)
print("parent process")
print(p,status)
while True:
pass
********************************************************************
这是聊天室程序
server.py
'''
name : Levi
chatroom server
'''
from socket import *
import sys,os
#实现登录
def do_login(s,user,name,addr):
if (name in user) or name == "管理员":
s.sendto("该用户已存在,请重新输入".encode(),addr)
return
s.sendto(b'OK',addr)
msg = "
欢迎 %s 进入聊天室"%name
#通知所有人
for i in user:
s.sendto(msg.encode(),user[i])
#将用户插入字典
user[name] = addr
return
def do_chat(s,user,cmd):
#cmd = ['C','zhang','I','love','China']
msg = "
%-4s: %s"%(cmd[1],' '.join(cmd[2:]))
#发送给所有人,除了自己
for i in user:
if i != cmd[1]:
s.sendto(msg.encode(),user[i])
return
def do_quit(s,user,name):
del user[name]
msg = "
" + name + "离开了聊天室"
for i in user:
s.sendto(msg.encode(),user[i])
return
#子进程处理客户端请求
def do_child(s):
#字典用来存储用户信息 {name:(ip,port)}
user = {}
#循环接受请求
while True:
msg,addr = s.recvfrom(1024)
msg = msg.decode()
cmd = msg.split(' ')
#根据不同请求做不同事情
if cmd[0] == 'L':
do_login(s,user,cmd[1],addr)
elif cmd[0] == 'C':
do_chat(s,user,cmd)
elif cmd[0] == 'Q':
do_quit(s,user,cmd[1])
else:
s.sendto("请求错误".encode(),addr)
#发送管理员消息
def do_parent(s,addr):
while True:
msg = input("管理员消息:")
msg = "C 管理员 "+ msg
s.sendto(msg.encode(),addr)
s.close()
sys.exit(0)
def main():
if len(sys.argv) < 3:
print("argv is error")
return
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST,PORT)
#使用数据报套接字
s = socket(AF_INET,SOCK_DGRAM)
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(ADDR)
#创建子进程
pid1 = os.fork()
if pid1 < 0:
print("创建一级子进程失败")
elif pid1 == 0:
#创建二级子进程
pid2 = os.fork()
if pid2 < 0:
print("创建二级子进程失败")
elif pid2 == 0:
do_child(s)
else:
#一级子进程退出,使二级子进程成为孤儿
os._exit(0)
else:
#等待一级子进程退出
os.wait()
do_parent(s,ADDR)
if __name__ == "__main__":
main()
*******************************************************************
client.py
'''
name:Levi
chatroom client
'''
from socket import *
import sys,os
import signal
#子进程发送消息
def do_child(s,name,addr):
while True:
text = input("发言(输入quit退出):")
#用户退出
if text == "quit":
msg = "Q " + name
s.sendto(msg.encode(),addr)
#从子进程中杀掉父进程
os.kill(os.getppid(),signal.SIGKILL)
sys.exit("退出聊天室")
#正常聊天
else:
msg = "C %s %s"%(name,text)
s.sendto(msg.encode(),addr)
#父进程接收消息
def do_parent(s):
while True:
msg,addr = s.recvfrom(1024)
print(msg.decode() + "
发言(输入quit退出):",
end="")
def main():
if len(sys.argv) < 3:
print("argv is error")
return
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST,PORT)
s = socket(AF_INET,SOCK_DGRAM)
while True:
name = input("请输入姓名:")
msg = 'L ' + name
s.sendto(msg.encode(),ADDR)
data,addr = s.recvfrom(1024)
if data.decode() == 'OK':
print("@进入聊天室@")
break
else:
print(data.decode())
pid = os.fork()
if pid < 0:
print("创建子进程失败")
elif pid == 0:
do_child(s,name,ADDR)
else:
do_parent(s)
if __name__ == "__main__":
main()
******************************************************************