用python写的一个简易聊天室,用到多线程,udp套接字

写一个聊天室

功能:类似qq群聊
1.进入聊天室需要输入名字
    客户端先发给服务端,服务端再发给客户端
2.有人进入聊天室会向其他人发送通知
    *** 进入聊天室
3.一个人发消息,其他人会收到消息
    *** 说:*****
4.某人退出聊天室,其他人也会收到通知
    *** 退出了聊天室
5.管理员喊话:服务端发送消息,所有的客户端都能收到
    管理员说:*****

功能模型: 转发  
需要的技术:套接字通信  udp套接字

用户存储:字典或列表
消息收发的随意性

代码设计
1.封装:将每个功能封装为函数   
2.接口测试(每实现一步测试一步)

代码编写流程

搭建网络连接-->创建多进程-->每个进程功能编写-->项目功能模块实现


进入聊天室


客户端: 输入名字 将信息发给服务端(L name)
        等待服务端回复  根据回复判断是否登录成功
服务端: 接受请求信息 判断请求类型 判断用户名是否存在
        如果不存在回复可以登录,并插入到数据结构
        发送通知给其他用户

聊天
客户端:创建父子进程  发送聊天请求 /接受聊天信息

服务端:接受请求信息,将消息转发给其他客户端

客户端

# client.py

from socket import *
import sys
import os


# 接受消息
def recv_msg(s):
    while True:
        data, addr = s.recvfrom(2048)
        if data.decode() == 'EXIT':
            sys.exit(0)
        print(data.decode() + '发言:', end = "")


# 发送消息
def send_msg(s, name, ADDR):
   while True:
        try:
            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)
        except KeyboardInterrupt:
            msg = "Q " + name
            s.sendto(msg.encode(), ADDR)
            sys.exit("退出聊天室")


# 创建套接字,登录,创建子进程
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
        # print('11111')
        # 发送登录请求
        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:
        send_msg(s, name, ADDR)
    else:
        recv_msg(s)


if __name__ == '__main__':
    main()







 

服务端

#!/usr/bin/env python3
# coding = utf-8


'''
name:zsj
email:zhangshuaijun_py@163.com
date:2018-9
introduce:Chatroom server
env: python3.5

'''
from socket import *
import os
import sys


# 登录判断
def do_login(s, user, name, addr):
    if (name in user) or name == '管理员':
        s.sendto('用户名已存在'.encode(), addr)
        return
    else:
        s.sendto('OK'.encode(), 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%s 说 %s\n' % (name, text)
    for i in user:
        if i != name:
            s.sendto(msg.encode(), user[i])


# 退出聊天室
def do_quit(s, user, name):
    msg = 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):
    # 存储结构({'zhangsan':(127.0.0.1,9999)})
    user = {}
    while True:
        msg, addr = s.recvfrom(1024)
        msgList = msg.decode().split(' ')
        # 区分请求类型
        if msgList[0] == 'L':  # 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_child(s, addr):
    while True:
        msg = input('管理员消息:')
        msg = 'C 管理员 ' + msg
        s.sendto(msg.encode(), addr)


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

    # 创建数据报套接字
    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()

 

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值