python网络编程实验二 基于UDP的聊天室程序

实验内容

编写基于UDP的聊天室程序,实现多人聊天功能。自己设计应用协议,要求实现以下功能:

  1. 用户注册
  2. 用户登录
  3. 公聊
  4. 私聊

服务器端源码

#!/usr/bin/env python

import socket

#创建网络连接
def main():
    server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)#创建UDP套接字
    server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    address = (('0.0.0.0',8000))#设置服务器地址
    server.bind(address)#绑定地址
    doRequest(server)#处理客户端请求

#处理客户端请求
def doRequest(server):
    Users={}#用户数据字典,键为用户名,值为列表,包含登录密码、在线状态、地址
    while True:
        #接收客户端的消息
        msg,addr = server.recvfrom(1024)
        msglist = msg.decode().split(' ')#拆分数据
        if msglist[0] == '1':#注册
            doRegister(server,Users,msglist[1],msglist[2],addr)
        elif msglist[0] == '2':#登录
            doLogin(server,Users,msglist[1],msglist[2],addr)
        elif msglist[0] == '3':#公聊
            content = ' '.join(msglist[2:])#获取完整发送内容
            doChat(server,Users,msglist[1],content)
        elif msglist[0] == '4':#私聊
            content = ' '.join(msglist[3:])#获取完整发送内容
            doPrivateChat(server,Users,msglist[1],msglist[2],content)
        elif msglist[0] == '5':#退出
            doQuit(server,Users,msglist[1])
        else:
            server.sendto('发生未知错误'.encode(),addr)

#注册
def doRegister(server,Users,name,password,addr):
    #判断用户名是否已存在
    if name in Users.keys():
        server.sendto('用户名已存在'.encode(),addr)
        return
    #该用户名未注册过,将该用户名加入用户数据字典,并设为在线状态
    Users[name]= [password,1,addr]
    #通知客户端登录成功
    server.sendto('OK'.encode(),addr)
    #通知其他所有用户
    message='\n' + name + '进入聊天室'
    for user in Users.keys():
        if user != name:
            server.sendto(message.encode(),Users[user][2])
    #服务器打印查看数据
    print(message)
    print(Users)

#登录
def doLogin(server,Users,name,password,addr):
    #判断该用户名是否已注册
    if name not in Users.keys():
        server.sendto('用户名不存在,请先注册'.encode(),addr)
        return
    #判断密码是否正确
    if Users[name][0] != password:
        server.sendto('密码错误,请重试'.encode(),addr)
        return
    #判断该用户名是否已登录
    if Users[name][1] == 1:
        server.sendto('该用户已登陆'.encode(),addr)
        return
    #满足登录条件,标注在线状态
    Users[name][1]=1
    Users[name][2]=addr
    #通知客户端登录成功
    server.sendto('OK'.encode(),addr)
    #通知其他所有用户
    message='\n' + name + '进入聊天室'
    for user in Users.keys():
        if user != name:
            server.sendto(message.encode(),Users[user][2])
    #服务器打印查看数据
    print(message)
    print(Users)

#公聊
def doChat(server,Users,name,content):
    message = '\n[公聊]' + name + ':' + content
    for user in Users.keys():
        if user != name:#发信息给其他所有用户
            server.sendto(message.encode(),Users[user][2])

#私聊
def doPrivateChat(server,Users,name,object,content):
    #为了看得更清楚,添加5个tab,使私聊部分在右侧显示
    message = '\n                   [私聊]' + name + ':' + content 
    for user in Users.keys():
        if user == object:#发给目标用户
            server.sendto(message.encode(),Users[user][2])

#退出
def doQuit(server,Users,name):
    #标注离线状态
    Users[name][1] = 0
    message = '\n' + name + '退出聊天室'
    for user in Users.keys():
        if user == name:
            server.sendto('exit'.encode(),Users[user][2])
        else:
            server.sendto(message.encode(), Users[user][2])
    #服务器打印查看数据
    print(message)
    print(Users)

if __name__ == '__main__':
    main()

客户端源码

#!/usr/bin/env python

import socket
import os
import sys

def main():
    #输入IP地址和端口号
    if len(sys.argv)<3:
        print('参数错误')
        return
    address = (sys.argv[1],int(sys.argv[2]))
    client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)#创建UDP套接字
    while True:#注册或登录
        operation = input('选择操作类型(1.register  2.login):')
        if (operation != '1') & (operation != '2'):
            print('输入错误')
            continue
        name = input('输入用户名(不含空格):')
        password = input('输入密码(不含空格):')
        message = operation + ' ' + name + ' ' + password
        client.sendto(message.encode(),address)#发送
        data,addr = client.recvfrom(1024)#接收服务器的提示信息
        if data.decode() == 'OK':#操作成功
            print('操作成功,您已进入聊天室\n(输入quit退出,输入PC私聊,默认公聊)')
            break
        else:#操作失败
            print(data.decode())#打印失败的原因
    #创建进程
    pid = os.fork()
    if pid < 0:
        print('创建进程失败!')
        return
    elif pid == 0:#子进程发送信息
        sendmsg(client,name,address)
    else:#父进程接收信息
        recvmsg(client)

def sendmsg(client,name,address):
    while True:
        content=input('[公聊]我:')
        if content == 'quit':#退出聊天室
            message = '5 ' + name
            client.sendto(message.encode(),address)
            sys.exit('您已退出聊天室')#子进程退出
        elif content == 'PC':#进入私聊
            #为了看得更清楚,添加5个tab,使私聊部分在右侧显示
            object = input('                    输入私聊对象用户名:')
            content = input('                   [私聊]我:')
            message = '4 ' + name + ' ' + object + ' ' + content
        else:
            message = '3 ' + name + ' ' + content
        client.sendto(message.encode(),address)#发送消息

def recvmsg(client):
    while True:
        message,addr = client.recvfrom(1024)
        if message.decode() == 'exit':#服务器提示退出
            os._exit(0)#父进程退出
        #因为print覆盖了之前的input信息,重新输出一遍
        print(message.decode() + '\n[公聊]我:',end='')

if __name__ == "__main__":
    main()

你可能感兴趣的:(python网络编程实验二 基于UDP的聊天室程序)