功能介绍:
- 进入聊天室需要先输入姓名,姓名不能重复
- 有人进入聊天室,会向其他人发送通知(不给自己发),格式:某某进入聊天室
- 一个人发消息,其他人都会收到消息(自己不收),格式:某某说:啥啥啥
- 有人退出聊天室,会向其他亲人发送通知(不给自己发),格式:某某退出了聊天室
- 管理员说话:服务端发出消息,所有的客户端都接收消息,格式:管理员说:啥啥啥
拿到一个项目,我们不是着急着想代码该怎么写, 而是这个项目该怎么写,基本的思路是什么。
对于这个项目,必须的是有客户端和服务端
客户端主要用来发送消息和接收别人发的消息
服务端主要用来处理客户端的消息和发送管理员消息
那么具体的该怎么分析呢?
对功能模块的分析:消息的转发
对于消息的发送与接收需要的技术是:套接字、udp(主要是udp不需要连接,比较方便)
登录的用户如何存储:使用字典或列表(这使用字典,字典更方便)
消息收发的随意性:使用多进程fork(多进程还有Process,后边会讲到,在这先不说了)
这个项目的整体思路是什么或者说我们编写代码的流程是什么?
- 搭建网络连接(实现客户端和服务端正常连接)
- 创建多进程(为编写功能做铺垫,实现消息的收发不受父进程的影响)
- 每个进程的功能编写(父子进程要实现什么功能)
- 每个功能模块的代码实现(将父子进程的功能代码写完,完成测试)
开始进入正题了,首先我们实现网络的正常连接,保证后边的功能可以正常的进行
服务端代码
# chat_server.py
from socket import *
def main():
# 设置服务器地址
HOST = '0.0.0.0'
PORT = 8000
ADDR = (HOST, PORT)
# 创建udp套接字
sockfd = socket(AF_INET, SOCK_DGRAM)
# 设置端口释放
sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
# 绑定地址
sockfd.bind(ADDR)
while True:
# 接收客户端的消息
data, addr = sockfd.recvfrom(1024)
print(data.decode())
# 反馈给客户端的消息
data = sockfd.sendto('收到消息'.encode(), addr)
if __name__ == "__main__":
main()
对应的客户端代码
# chat_client.py
from socket import *
import sys
def main():
if len(sys.argv) < 3:
s = '''
输入有误
请按要求输入, 如:
python3 chat_client.py 127.0.0.1 8000
'''
print(s)
return
# 获取终端输入的地址
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST, PORT)
# 创建udp套接字
sockfd = socket(AF_INET, SOCK_DGRAM)
# 消息的收发
while True:
data = input('>>')
# 发送消息
sockfd.sendto(data.encode(), ADDR)
# 接收服务端反馈的消息
data, addr = sockfd.recvfrom(1024)
print(data.decode())
if __name__ == "__main__":
main()
此时实现了客户端与服务端的连接,运行(先运行服务端)结果是:
连接没问题我们就开始创建多进程了
服务端:
父进程:处理客户端请求和转发消息
子进程:创建一个单独的进程用来发送管理员消息
客户端:
父进程:接收消息
子进程:发送消息
改写服务端代码
# chat_server.py
from socket import *
import os # 创建fork多进程先导入os模块
# 做管理员发送消息
def do_child():
pass
# 处理客户端的消息
def do_parent():
pass
def main():
# 设置服务器地址
HOST = '0.0.0.0'
。。。
# 绑定地址
sockfd.bind(ADDR)
# 创建进程
p = os.fork()
if p < 0:
print('创建进程失败')
elif p == 0:
do_child()
else:
do_parent()
if __name__ == "__main__":
main()
改写客户端代码
# chat_client.py
from socket import *
import sys
import os
# 发送消息
def send_msg():
pass
# 接收消息
def recv_msg()