-
功能 : 类似qq群聊功能
【1】 有人进入聊天室需要输入姓名,姓名不能重复
【2】 有人进入聊天室,其他人会收到通知
xxx 进入聊天室
【3】 一个人发消息,其他人会收到消息
xxx : xxxxxxxx
【4】 有人退出聊天室,则其他人会收到通知
xxx 离开了聊天室
【5】 扩展功能:服务器可以向所有群用户发送公告
管理员消息: xxxxxxxxxxx
-
确定技术模型
【1】 消息的网络传输:socket–>udp
【2】 发送模型 :
转发 客户端–>服务端–>其他客户端
【3】 服务端用户存储 {name:addr}
【4】 收发关系处理 : 多进程分别处理消息接收和发送 -
整体设计
【1】 封装方法 ,函数 -
注意点
【1】 写一个模块测试一个模块
【2】 注释的添加 -
具体实现
【1】 网络连接搭建
【2】 进入聊天室
1. 客户端: * 输入姓名
* 将姓名发送给服务器
* 接收反馈
* OK则进入,否则重新输入
-
服务端: * 接收姓名
* 判断是否允许进入,通知客户端
* 不允许则结束,允许则将信息保存到数据字典
* 将登陆信息告知其他人【3】 实现聊天
【4】 退出聊天室
【5】 管理员公告
客户端
client.py
from socket import *
import os,sys
# 服务器地址
ADDR = ('127.0.0.1',8888)
def udp_client():
return socket(AF_INET,SOCK_DGRAM)
def login(s):
while True:
name = input("请输入姓名:")
msg = "L " + name # L表示请求类型
# 给服务器发送
s.sendto(msg.encode(),ADDR)
# 等待回复
data,addr = s.recvfrom(1024)
if data.decode() == 'OK':
print("您已进入聊天室")
break
else:
print(data.decode())
return name
def send_msg(s,name):
while True:
try:
text = input("发言:")
except KeyboardInterrupt:
text = "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)
def recv_msg(s):
while True:
data,addr = s.recvfrom(2048)
# 收到服务器EXIT则退出
if data.decode() == 'EXIT':
sys.exit()
print(data.decode()+'\n发言:',end='')
def chat(s,name):
# 创建进程
pid = os.fork()
if pid < 0:
sys.exit("Error!")
elif pid == 0:
send_msg(s,name)
else:
recv_msg(s)
def main():
s = udp_client()
name = login(s)
chat(s,name)
main()
服务端
server.py
# -*- coding:utf-8 -*-
"""
Chat room server
env: python3.5
exc: for socket and fork
"""
from socket import *
import os,sys
# 服务端地址
ADDR = ('0.0.0.0',8888)
# 存储用户{name:addr}
user = {}
# 搭建网络连接
def udp_server():
# 创建套接字
s = socket(AF_INET,SOCK_DGRAM)
s.bind(ADDR)
return s
def do_login(s,name,addr):
if (name in user) or ('管理员' in name):
s.sendto("该用户已存在".encode(),addr)
return
s.sendto(b'OK',addr)
# 通知其他人
msg = "\n欢迎 %s 进入聊天室"%name
for i in user:
s.sendto(msg.encode(),user[i])
# 加入字典
user[name] = addr
def do_chat(s,name,text):
msg = "\n%s : %s"%(name,text)
for i in user:
if i != name:
s.sendto(msg.encode(),user[i])
def do_quit(s,name):
msg = "\n%s 退出了聊天室"%name
for i in user:
if i != name:
s.sendto(msg.encode(),user[i])
else:
s.sendto(b'EXIT',user[i])
# 删除用户
del user[name]
def request(s):
while True:
data,addr = s.recvfrom(1024)
msgList = data.decode().split(' ')
# 区分请求类型
if msgList[0] == 'L':
do_login(s,msgList[1],addr)
elif msgList[0] == 'C':
# 重组消息
text = ' '.join(msgList[2:])
do_chat(s,msgList[1],text)
elif msgList[0] == 'Q':
do_quit(s,msgList[1])
# 代码的流程控制部分
def main():
s = udp_server()
# 单独创建进程发送管理员消息
pid = os.fork()
if pid < 0:
print("Error")
elif pid == 0:
while True:
msg = input("管理员消息:")
msg = "C 管理员消息 " + msg
# 发送给父进程
s.sendto(msg.encode(),ADDR)
else:
request(s) # 接收请求
main()
核心思想:客户端、服务端建立连接;
服务端单独封装一个接受和处理请求服务,用于将客户端发来的消息,以特定协议的规则进行解析,根据解析结果调用不同函数进行特定功能执行。
客户度单独封装登陆模块,聊天模块用多进程来进行实现,子进程用于实现消息的发送,父进程用于实现消息的接收。