Python3群聊聊天室

类似群聊

需求

  • 有人进入聊天室需要输入姓名,姓名不能重复
  • 有人进入聊天室时,其他人会收到通知:xxx 进入了聊天室
  • 一个人发消息,其他人会收到:xxx : xxxxxxxxxxx
  • 有人退出聊天室,则其他人也会收到通知:xxx退出了聊天室

技术分析

客户端/服务端

client/server

存储人员信息: 服务端
   存什么 : 名字  地址
   怎么存 : {name:address}
            [(name,address),...]
            class Person:
                def __init__(self,name,address):
                   self.name = name
                   self.address = address
 
消息的网络传递 : udp
    消息发送:转发的方法   客户端-》服务端-》客户端
    收发消息: 多进程,一个负责发送,一个负责接收
功能模块划分 封装方法 : 函数封装
框架模型

进入聊天室

聊天

退出聊天室
网络协议设置
       请求类型     数据参量
进入     LOGIN      name

聊天     CHAT       name  说话的内容

退出     EXIT
功能模块逻辑具体分析
框架模型
    服务端 : 1. 创建udp网络服务端
             2. 循环接收各种客户端请求
             3. 根据请求做出调用

    客户端 : 1. 创建udp网络

进入聊天室
    客户端 : 1. 输入姓名
             2. 发送给服务端
             3. 接收服务端反馈
             4. YES 进入聊天 NO 回到第一步

    服务端 : 1. 接收请求
             2. 判断是否有这个姓名
             3. 根据判断发送结果
                 YES -》存储用户 告知其他人
                 NO -》over

聊天
   客户端 :1. 创建子进程
           2. 父进程循环发送消息
              子进程循环接收消息

   服务端 : 1. 接收请求
            2. 将消息转发给其他人


退出聊天室
   客户端 1. 输入EXIT 表示退出
         2. 发送请求

   服务端 1. 接收请求
         2. 告知其他人
         3. 删除该用户
  • 后续可继续优化完善
客户端代码如下:
# -*- coding: UTF-8 -*-
'''
PyCharm
@Project :群聊聊天室 
@File    :chat_client.py
@Author  :
@Date    :2020/10/24
'''
"""
    群聊 客户端代码
"""

from socket import *
from multiprocessing import Process
import sys

# 服务器地址
ADDR = ('127.0.0.1', 8888)


# 处理登录
def login(socketed):
    while True:
        # 进入聊天室
        name = input('用户名:>>>')

        # 发送姓名
        msg = 'LOGIN ' + name
        socketed.sendto(msg.encode(), ADDR)
        # 接收结果
        data, address = socketed.recvfrom(1024)
        if data.decode() == 'YES':
            print('进入聊天室')
            return name
        else:
            print('用户已存在')


# 接收消息
def chat(socketed):
    while True:
        data, address = socketed.recvfrom(1024 * 10)
        # 美化打印内容
        msg = "\n" + data.decode() + "\n发言:"
        print(msg, end="")  # end="" 不换行


# 发送消息
def receive(socketed, name):
    while True:
        # try 处理异常退出
        try:
            news = input('发言:')
        except KeyboardInterrupt:
            news = 'EXIT'

        if news == 'EXIT':
            msg = 'EXIT ' + name
            socketed.sendto(msg.encode(), ADDR)
            sys.exit('已退出聊天室')

        msg = 'CHAT %s %s' % (name, news)
        socketed.sendto(msg.encode(), ADDR)


# 程序启动函数
def main():
    socketed = socket(AF_INET, SOCK_DGRAM)
    # socketed.bind(('0.0.0.0', 2222))  # 确保地址不会变化
    name = login(socketed)  # 进入聊天室

    # 创建子进程 用于接收消息
    process = Process(target=chat, args=(socketed,))
    process.daemon = True  # 父进程退出子进程也退出
    process.start()

    # 父进程发送消息
    receive(socketed, name)

    socketed.close()

    process.join()


if __name__ == '__main__':
    main()

服务端代码如下:
# -*- coding: UTF-8 -*-
'''
PyCharm
@Project :群聊聊天室
@File    :chat_server.py
@Author  :
@Date    :2020/10/24
'''
"""
    群聊  服务端
"""

from socket import *
from multiprocessing import Process

# 服务器地址
HOST='0.0.0.0'
PORT= 8888
ADDR = (HOST,PORT)
# 用字典储存用户
user = {}  # 储存用户信息 {name:address}


# 处理进入聊天室
def login(socketed, name, address):
    if name in user or '管理' in name:
        socketed.sendto('NO'.encode(), address)
    else:
        socketed.sendto('YES'.encode(), address)
        # 循环通知其他人
        msg = '欢迎%s进入聊天室' % name
        for other in user:
            socketed.sendto(msg.encode(), user[other])
        user[name] = address  # 增加该用户


# 处理聊天
def chat(socketed, name,content):
    msg = "%s : %s" % (name, content)
    for other in user:
        if other == name:
            continue  # 除去自己
        socketed.sendto(msg.encode(), user[other])


# 处理退出
def exits(socketed, name):
    del user[name]  # 删除用户
    msg = '%s退出聊天室' % name
    for other in user:
        socketed.sendto(msg.encode(), user[other])

# 处理客户端请求
def request(socketed):
    # 循环接收各种客户端请求
    while True:
        # 接收所有客户端请求
        data, address = socketed.recvfrom(1024)
        # 对数据结构进行简单解析
        tmp = data.decode().split(' ',2)

        if tmp[0] == 'LOGIN':
            # tmp---> ['LOGIN','name']
            # 进入函数
            login(socketed, tmp[1], address)
        elif tmp[0] == 'CHAT':
            # tmp---> ['LOGIN','name','news']
            #  聊天函数
            chat(socketed, tmp[1],tmp[2])
        elif tmp[0] == 'EXIT':
            # 退出函数
            exits(socketed, tmp[1])

# 程序启动函数
def main():
    # UDP套接字
    socketed = socket(AF_INET, SOCK_DGRAM)
    socketed.bind(ADDR)
    # 创建子进程
    process=Process(target=request,args=(socketed,))
    process.daemon=True # 父进程退出子进程也退出
    process.start()
    while True:
        # 发送管理员消息
        content = input("管理员消息:")
        # 服务端退出
        if content == "EXIT":
            break
        msg = "CHAT 管理员消息: "+content
        # 从父进程发送给子进程
        socketed.sendto(msg.encode(),ADDR)




if __name__ == '__main__':
    main()

  • 执行需先执行服务端后再执行客户端
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值