PythonNet_05_bj

前请回顾
本地套接字 : AF_UNIX 做本地的进程间通信

多任务编程中的进程

进程 : 程序在计算机中的一次执行过程

进程状态 : 等待态 运行态 就绪态

os.fork()
功能 创建新的进程

os.getpid() 获取当前进程的PID
os.getppid() 获取父进程的PID

退出进程
os._exit()
sys.exit()


import os
from time import sleep

pid = os.fork()

if pid < 0:

print(“Create process failed”)

elif pid == 0:

print(“Child Process”)

# 子进程打印父进程的PID

print(“Parent pid:”,os.getppid())

sleep(2) #等父进程退出

print(“Parent pid again:”,os.getppid())

else:

sleep(1) # 等待子进程打印自己的PID

print(“Parent Process”)

# Child Process

# Parent pid: 5267

# Parent Process

if pid < 0:
print(“Create process failed”)
elif pid == 0:
print(“Child Process :”,os.getpid())
print(“Child Process over”)
# 子进程打印父进程的PID
# print(“Parent pid:”,os.getppid())
# sleep(2) #等父进程退出
# print(“Parent pid again:”,os.getppid())
else:
sleep(2)
print(“Parent Process”)
while True:
pass
# sleep(1) # 等待子进程打印自己的PID

孤儿进程:父进程先于子进程退出,此时子进程就会成为
孤儿进程。

  • 孤儿进程会被系统指定的进程收养,即系统进程会成为
    孤儿进程新的父进程。当孤儿进程退出时“继父”,会处
    理孤儿进程退出状态,使其不会成为僵尸。

僵尸进程:子进程先于父进程退出,父进程没有处理子进
程的退出状态,此时子进程就会成为僵尸进程

  • 僵尸进程会滞留部分PCB信息在内存中,大量的僵尸进
    程会消耗系统资源,应该尽量避免僵尸进程的产生

如何避免僵尸进程
* 父进程先退出 (不佳,因为不好控制)
* 父进程处理子进程的退出状态

pid,status = os.wait()
功能: 在父进程中阻塞等待子进程的退出
返回值 : 一个两个元素的元组
pid : 退出的子进程的PID号
status : 退出的子进程的退出状态

import os
from time import sleep

pid = os.fork()

if pid < 0:
print(“create process failed”)
elif pid == 0:
sleep(3)
print(“Child process over”)
os._exit(2)
else:
# 等子进程执行完毕
pid,status = os.wait()
print("++++++++++++++++++++")
print(pid,status)
print(os.WEXITSTATUS(status)) #获取退出状态
while True:
pass

#Child process over
#++++++++++++++++++++
#6818 768

#查看命令:ps -aux

pid,status = os.waitpid(pid,option)
功能 : 处理子进程的退出状态
参数 : pid -1 表示等待任意子进程退出
>0 整数 表示等待对应PID号的子进程退出
option : 0 表示阻塞等待
WNOHONG 表示非阻塞
返回值 : 同wait()

waitpid(-1,0) ==== wait()

watipid.py

import os
from time import sleep

pid = os.fork()

if pid < 0:
print(“create process failed”)
elif pid == 0:
sleep(3)
print(“Child process over”)
os._exit(2)
else:
while True:
sleep(1)
# 设置非阻塞状态
pid,status = os.waitpid(-1,os.WNOHANG)
print("++++++++++++++++++++")
print(pid,status)
print(os.WEXITSTATUS(status)) #获取退出状态
while True:
pass

tarena@tedu:~$ python3 03_waitpid.py

++++++++++++++++++++

0 0

0

++++++++++++++++++++

0 0

0

Child process over

++++++++++++++++++++

6530 512

2

Traceback (most recent call last):

File “03_waitpid.py”, line 17, in

pid,status = os.waitpid(-1,os.WNOHANG)

ChildProcessError: [Errno 10] No child processes

创建二级子进程
* 父进程创建子进程等待子进程的退出
* 子进程创建二级子进程后满上退出
* 二级子进程成为孤儿,处理具体事件

#创建二级子进程处理僵尸

import os
from time import sleep

def fun1():
sleep(3)
print(“第一件事情”)

def fun2():
sleep(4)
print(“第二件事情”)

pid = os.fork()

if pid < 0:
print(“create process error”)
elif pid == 0:
#创建二级子进程
pid0 = os.fork()
if pid0 < 0:
print(“create pid0 failed”)
elif pid0 == 0:
fun2() #做另一件事情
else:
os._exit(0)
else:
os.wait()
fun1() #做第一件事情

聊天室项目

功能 : 类似QQ群聊

  1. 进入聊天室前需要输入用户名
  2. 有人进入聊天室会向其他用户发起通知
    xxx 进入了聊天室
  3. 一个人发消息,其他人都能收到
    xxx 说:xxxxxxxx
  4. 某个人退出聊天室 其他人也会收到通知
    xxx 退出了聊天室
  5. 管理员喊话功能 :管理员发言所有客户端都能收到
    管理员 说:xxxxxxx

需要什么技术:

socket 通信

存储用户 : 字典或列表
姓名 和 地址

用什么类型套接字 : udp套接字

怎么发消息:

  • 转发 即客户端发给服务器然后服务器在发送给其他人

*在客户端让发送和接收需要相互独立,各使用一个进 程
*服务端,管理员喊话和请求的接收需要独立,各使用一个进程

注意点

  1. 功能封装 将每个功能模块化
  2. 测试,每个功能进行测试

代码编写流程

搭建网络连接----》多进程的创建—》每个进程功能的编写----》
项目功能的诸个编写

客户端可能发送的请求

进入聊天室: “L name”
服务端 : 识别请求 判定是否可以进入
回复客户端 保留用户
告知其他人谁进入

聊天请求 : “C name message”
服务端 : 识别请求 转发给其他人

退出聊天室: “Q name”
服务端 : 识别请求 告知其他人谁退出
将其从用户中删除

server.py

from socket import *
import os,sys

def do_login(s,user,name,addr):
if (name in user) or name == “管理员”:
s.sendto(“该用户已存在”.encode(),addr)
return
s.sendto(b’OK’,addr)
#通知所有人
msg = “\n欢迎 %s 进入聊天室”%name
for i in user:
s.sendto(msg.encode(),user[i])
#将用户插入字典
user[name] = addr

def do_chat(s,user,name,text):
msg = “\n%-4s 说:%s”%(name,text)
#发送给除了自己的所有人
for i in user:
if i != name:
s.sendto(msg.encode(),user[i])

def do_quit(s,user,name):
del user[name]
msg = “\n” + name + “离开了聊天室”
for i in user:
s.sendto(msg.encode(),user[i])

接收客户端请求并处理

def do_child(s):
#用于存储用户 {‘zhangsan’?‘172.60.50.51’,9687)}
user = {}
#循环接收各个客户端请求并处理
while True:
msg,addr = s.recvfrom(1024)
msgList = msg.decode().split(’ ')
#判断请求类型进行处理
if msgList[0] == ‘L’:
do_login(s,user,msgList[1],addr)
elif msgList[0] == ‘C’:
do_chat(s,user,msgList[1],
’ '.join(msgList[2:]))
elif msgList[0] == ‘Q’:
do_quit(s,user,msgList[1])

发送管理员消息

def do_parent(s,addr):
while True:
msg = input(“管理员消息:”)
msg = "C 管理员 " + msg
s.sendto(msg.encode(),addr)

创建套接字,创建链接 ,创建父子进程

def main():
#server address
ADDR = (‘0.0.0.0’,8888)
#创建套接字
s = socket(AF_INET,SOCK_DGRAM)
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(ADDR)

#创建父子进程 ,并且防止僵尸进程
pid = os.fork()

if pid < 0:
    sys.exit("创建进程失败")
elif pid == 0:
    #创建二级子进程
    pid0 = os.fork()
    if pid0 < 0:
        sys.exit("创建进程失败")
    elif pid0 == 0:
        #执行子进程功能
        do_child(s)
    else:
        os._exit(0)
else:
    os.wait()
    #执行父进程工能
    do_parent(s,ADDR)

if name == “main”:
main()


client.py

‘’’
Project : Chatroom
name : Levi
chatroom server
‘’’
from socket import *
import sys,os
import signal

#发送消息
def do_child(s,name,addr):
while True:
text = input(“发言(quit退出):”)
#退出
if text.strip() == “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()+"\n发言(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:
    sys.exit("创建子进程失败")
elif pid == 0:
    do_child(s,name,ADDR)
else:
    do_parent(s)

if name == “main”:
main()


multiprocessing 模块创建进程

  1. 需要将要做的事件进行封装成函数
  2. 使用multiprocessing提供的类Process创建进程对象
  3. 通过对象和Process的初始化函数对进程进行设置以
    及绑定要执行的事件
  4. 启动进程,会自动的执行函数代表的事件
  5. 完成进程的回收

创建进程对象
Process()
功能:创建进程对象
参数:name : 给创建的进程对象起一个名字
默认为Process-1
target : 绑定的函数
args :元组 用来给 target函数传参按位置传参
kwargs : 字典 按照键值传参

p.start()
功能:启动进程 进程被创建,自动运行对应函数

p.join([timeout])
功能 : 阻塞等待对应子进程的退出,回收子进程
参数 : 超时时间

  • 如果不使用join 则子进程会成为僵尸进程
  • 在使用multiprocessing创建进程中,一般父进程功能
    就是创建子进程等待回收,不做过多其他事情
  • 使用multiprocessing创建子进程,同样子进程复制父
    进程空间,之后有自己独立的执行空间,互不干扰

import multiprocessing as mp
from time import sleep

a = 1

def fun():
global a
a = 1000
sleep(3)
print(“子进程事件”)

#创建进程对象
p = mp.Process(target = fun)

#启动进程
p.start()

sleep(2)

print(“这是父进程”)

#回收进程
p.join()
print("a = ",a)


from multiprocessing import Process
from time import sleep
import os

def th1():
sleep(3)
print(“吃饭”)
print(os.getppid(),"----",os.getpid())
def th2():
sleep(2)
print(“睡觉”)
print(os.getppid(),"----",os.getpid())
def th3():
sleep(4)
print(“打豆豆”)
print(os.getppid(),"----",os.getpid())

thing = [th1,th2,th3]
process = []

for th in thing:
p = Process(target = th)
process.append§ #将进程对象保存
p.start()

#回收进程
for i in process:
i.join()

作业: 1. 将聊天室代码进行梳理
2. 复习fork创建进程的内容进行整理
3. multiprocessing 函数巩固

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值