编写基于UDP的聊天室程序,实现多人聊天功能。自己设计应用协议,要求实现以下功能:
#!/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()