Python网络编程(子进程的创建与处理、简单群聊工具)

前言:
昨天我们已经了解了多进程的原理以及它的实际使用
Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,

但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。

子进程永远返回0,而父进程返回子进程的ID。这样做的理由是,一个父进程可以fork出很多子进程,所以,

父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。

Python的os模块封装了常见的系统调用,其中就包括fork,可以在Python程序中轻松创建子进程

既然是进程那么就会有运行和退出
接下来我们就来了解一下进程的退出以及处理

孤儿进程:
当父进程优先于子进程退出,此时子进程就会成为孤儿进程
特征:
孤儿进程会被系统指定进程收养,即系统进程会成为
这个孤儿进程新的父进程,系统进程会自动处理进程退出状态

僵尸进程:
当子进程优先于父进程退出,父进程没有处理子进程的退出状态
此时子进程就会成为僵尸进程
僵尸进程会滞留部分PCB信息在内存中,大量的僵尸进程会消耗系统给的内存资源,
所以要尽量避免僵尸进程的产生

如何避免僵尸进程的产生:
1.父进程先退出
2.父进程处理子进程状态

PID,status = os.wait
  功能:
     在父进程中阻塞等待处理子进程的退出
  返回值:
       pid :退出的那个子进程的PID号

status :子进程的退出状态
获取原来的退出状态:
wait(status)
pid,status = os.waitpid(pid,option)
功能:在父进程阻塞等待处理子进程的退出
参数 :
pid -1 表示等待任意子进程退出

0 表示等待对应PID号的子进程退出 option
0 表示阻塞等待 WNOHANG 表示非阻塞
返回值:pid
退出的那个子进程的PID号 status 子进程的退出状态

创建二级子进程
父进程创建子进程等待进程退出
子进程创建下一个进程,然后立即退出
二级子进程成为孤儿进程 处理具体工作

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

创建进程对象:
process()
功能:
创建进程对象
参数:
target:函数对象
name 给进程新名称()
args:元组 用来给target函数位置传参
kwargs:字典 用来给target函数键值传参
p.start()
功能:
启动进程,自动运行terget绑定函数,
此时进程被创建
p.join([timeout])
功能:
等待阻塞子进程退出
参数:超时检测
如果不使用join回收可能后产生僵尸进程

使用multiprocessing创建进程子进程同样复制父进程的全部内存空间
之后有自己的独立空间 执行上互不干扰 子进程也有自己的PID特有资源等
使用multiprocessing创建子进程,一般父进程功能就是创建子进程
回收子进程,返回事件交给子进程完成

简单群聊:

功能:
类似QQ群聊
1.进入聊天室需要输入姓名 姓名不能重复
2.有人进入聊天室会向其他人发起通知 xxx进入聊天室
3.如果一个人发消息则其他人都能收到 xxx说:…
4.如果某个人退出聊天室也会收到通知 xxx退出聊天室
5.服务端可以喊话:此时群里所有的都能收到服务端消息 管理员说:…

服务器端:

from socket import *
import os, sys

发送管理员消息

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

用户登录

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
user[name] = addr

def do_chat(s, user, name, data):
msg = “\n{} 说: {}”.format(name, data)
for i in user:
if i != name:
s.sendto(msg.encode(), user[i])

def do_quit(s, user, name):
msg = “\n%s 离开了聊天室” % name
for i in user:
if i == name:
s.sendto(b’EXIT’, user[i])
else:
s.sendto(msg.encode(), user[i])
del user[name] # 删除离开的用户

接收客户端请求并处理

def do_parent(s):
# 用于存储用户 {‘Alex’:(‘127.0.0.1’,8888)}
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’:
# “C Levi [I miss you]”
data = ’ ‘.join(msgList[2:])
do_chat(s, user, msgList[1], data)
elif msgList[0] == ‘Q’:
do_quit(s, user, msgList[1])

创建套接字,网络连接,创建父子进程

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:
    do_child(s, ADDR)
else:
    do_parent(s)

if name == “main“:
main()

客户端:

from socket import *
import sys, os

def login(s, ADDR):
while True:
name = input(“请输入用户名:”)
msg = “L ” + name
s.sendto(msg.encode(), ADDR)
# 接收登录结果
data, addr = s.recvfrom(1024)
if data.decode() == ‘OK’:
print(“@进入聊天室@”)
return name
else:
print(data.decode())

发送消息

def do_child(s, name, addr):
while True:
text = input(“发言(quit退出):”)
# 退出
if text.strip() == “quit”:
msg = “Q ” + name
s.sendto(msg.encode(), addr)
sys.exit(“退出聊天室”)

    msg = "C %s %s" % (name, text)
    s.sendto(msg.encode(), addr)

接收消息

def do_parent(s):
while True:
msg, addr = s.recvfrom(1024)
if msg.decode() == ‘EXIT’:
sys.exit(0)
print(msg.decode() + “\n发言(quit退出):”,end=”“)

main控制套接字的创建

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)

name = login(s, ADDR)
if name:
    pid = os.fork()
    if pid < 0:
        sys.exit("创建子进程失败")
    elif pid == 0:
        do_child(s, name, ADDR)
    else:
        do_parent(s)
else:
    return

if name == “main“:
main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值