多任务编程之OS父子进程实现udp聊天室

功能需求

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

服务端

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=name+'\n离开了聊天室'
	for i in user:
		s.sendto(msg.encode(), user[i])

# 接收客户端请求并处理
def do_child(s):
	# 用于存储用户{'张三':('0.0.0.0',8888)}
	user = {}
	# 循环接收各个客户端请求并处理
	while True:
		msg, addr = s.recvfrom(1024)
		msgList = msg.decode().split(' ')
		# 根据msg第一项判断请求类型
		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()

客户端

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())
			continue	
		pid = os.fork()
		if pid < 0:
			sys.exit("创建进程失败")
		elif pid == 0:
			do_child(s, name, ADDR)
		else:
			do_parent(s)
	

if __name__=="__main__":
	main()

服务端
在这里插入图片描述
第一个客户端登陆
在这里插入图片描述
第二个客户端登陆
在这里插入图片描述
第三个客户端登陆
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值