多人网络聊天室实现

16 篇文章 0 订阅
12 篇文章 0 订阅
  • 项目需求:
功能:类似qq群聊、linux环境下
1.进入聊天室需要输入姓名,姓名不能重复
2.有人进入聊天室会向其他人发送通知:xxx进入了聊天室
3.一个人发消息,其他人会收到消息
	xxx 说: xxxxxx
4.某人退出聊天室,其他人也会收到通知
	xxx退出了聊天室
5.管理员喊话 服务端发送消息给所有的客户端都收到
	管理员说:xxxxxx
  • 项目分析:
项目问题:
* 服务端 客户端
* 使用什么技术
* 知识点回顾复习

功能模型: 转发
需要的技术: 套接字通信 udp套接字
用户存储: 字典或列表
消息的收发: 多进程
  • 代码设计:
1.封装(代码量小,将每个功能封装为函数) 
2.接口测试(每实现一步就测试一步)
  • 代码编写流程
1.搭建网络连接
2.创建多进程
3.每个进程功能编写
4.项目功能模块实现 
  • 功能详细解析
1.进入聊天室
客户端:
	输入姓名 
	将信息发送给服务端(注明消息类型)
	等待服务端回复
	根据回复判断是否登录成功
服务端:
	接收请求消息
	判断请求类型
	判断用户名是否存在
		如果存在回复不能
		如果不存在回复可以登录并插入到数据结构
			发送通知给其他用户

2.聊天
客户端: 创建父子进程,分别发消息和收消息
	发送聊天请求
	接收聊天信息
服务端:
	接收请求信息
	将消息转发给其他客户端
3.退出
4.管理员消息
  • 聊天室客户端代码
'''
name: Junx
email: wjfabcd@outlook.com
date: 2019-7
introduce: Chatroom Client
env: python3.6
'''


from socket import *
import sys,os

#创建套接字,登录,创建子进程
def main():
	host,port = (input('请输入聊天室地址:')).split()
	addr = host,int(port)
	if len(addr) < 2:
		return 
	
	#创建套接字
	s = socket(AF_INET,SOCK_DGRAM)

	#循环登录
	while True:
		name = input("请输入姓名:")
		#约定登录请求为L开头+空格,并发送请求,不允许姓名之中有空格
		if ' ' in name: 
			print('不允许输入空格')
			break
		msg = "L " + name
		s.sendto(msg.encode(),addr)

		#等待服务器回复
		data,addr = s.recvfrom(1024)
		
		#约定OK为登录成功
		if data.decode() == 'OK':
			print('您已进入聊天室')
			break # 退出后创建父子进程实现收发消息功能
		else:
			#不成功服务器会回复不允许登录的原因
			print(data.decode())

	#创建父子进程
	pid = os.fork()
	if pid < 0:
		print('创建子进程失败')
	elif pid == 0:
		#子进程用来发送消息
		#指名是谁发的,避免服务端遍历
		send_msg(s,name,addr) 
	else:
		#父进程用来接受所有消息
		recv_msg(s)


def send_msg(s,name,addr):
	while True:
		text = input('发言:')
		
		#输入quit表示退出
		if text.strip() == 'quit':
			msg = 'Q {}'.format(name)
			s.sendto(msg.encode(),addr)
			# 退出聊天室,子进程退出
			sys.exit('退出聊天室')

		msg = 'C {} {}'.format(name,text)
		s.sendto(msg.encode(),addr)

def recv_msg(s):
	#用该函数来接收所有客户端发来的消息
	
	while True:
		data, addr = s.recvfrom(1024)
		#如果子进程退出聊天室,根据服务端发送的响应终止父进程
		if data.decode() == 'EXIT':
			sys.exit(0)
		
		#接收消息并解决linux终端的显示问题
		print(data.decode()+'\n发言:',end ='')

if __name__ == '__main__':
	main()
  • 聊天室服务端代码:
#!/usr/bin/env python3
#coding = utf-8

'''
name: Junx
email: wjfabcd@outlook.com
date: 2019-7
introduce: Chatroom Server
env: python3.6
'''
 
from socket import *
import os,sys

#创建网络连接,创建进程,调用功能函数
def main():
	#server address
	addr = ('0.0.0.0',8888)

	#创建套接字:udp套接字
	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)


def do_parent(s):
	'''接受客户端请求'''
	user = {} # 字典结构 ’name‘ : addr
	print('处理客户端请求')

	#不断接受客户端发送的消息
	while True:
		msg,addr = s.recvfrom(1024)
		msg = msg.decode().split()
		
		if msg[0] == 'L':
			#实参传递形参时,实参为可变数据类型时会对实参进行修改
			do_login(s,user,msg[1],addr) # 参数为客户端用户名称
		
		elif msg[0] == 'C':
			do_chat(s,user,msg[1],' '.join(msg[2:]))

		elif msg[0] == 'Q':
			do_quit(s,user,msg[1])
	

def do_child(s,addr):
	'''做管理员喊话'''
	#与父进程是两个独立的进程,不能使用父进程的user字典
	#故向自己发送消息从而向其他所有用户转发消息
	while True:
		text = input('管理员:')
		msg = "C 管理员 {}".format(text)

		s.sendto(msg.encode(),addr)


def do_login(s,user,name,addr):
	'''判断名称是否在user字典内'''
	if (name in user) or name == '管理员':
		s.sendto('该用户已存在'.encode(),addr)
		return
	s.sendto(b'OK',addr)

	#通知其他人
	msg = '\n欢迎{}进入聊天室'.format(name)
	for new_addr in user.values():
		s.sendto(msg.encode(),new_addr)

	#插入用户
	user[name] = addr

def do_chat(s,user,name,text):
	#将接受的消息转发给聊天室内的其他人
	msg = '\n{}说:{}'.format(name,text)
	for i in user:
		if i == name: continue
		s.sendto(msg.encode(),user[i])

def do_quit(s,user,name):
	#某用户退出聊天室,将用户从字典中删除
	#并将该用户的退出消息发送给聊天室内其他用户
	
	msg = '\n{}退出了聊天室'.format(name)
	for i in user:
		if i == name: 
			s.sendto(b'EXIT',user[i])
		s.sendto(msg.encode(),user[i])

	del user[name]


if __name__ == '__main__':
 	main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值