网络编程:fork多进程网络通信应用实例--聊天室(群聊)

简单的群聊聊天室

1、功能

  类似于qq群聊

    【1】进入聊天室需要输入姓名, 姓名不能重复

    【2】有人进入聊天室此时会向其他人发起通知 ,xxx 进入了聊天室 

    【3】如果一个人发消息,则其他人都能收到 ,xxx 说 : xxxxxxx

    【4】如果某个人退出聊天室其他人也会收到通知, xxx 退出了聊天室

    【5】服务端可以喊话 :此时群里所有人都能收到服务端消息 。管理员 说:xxx

2、功能分析

  整体结构

    Q:分为几部分,如何封装,使用什么样的技术手段

    A:服务端 ,客户端, 在客户端和服务端将每个功能封装为一个函数

3、技术方案

  【1】转发

      一个客户端发送给服务器,服务器发送给其他人

  【2】套接字使用

      udp 完成操作

  【3】用户存储

      字典 或者 列表 (可变类型,能够遍历提取)

  【4】地址 用户名

  【5】发送和接受消息的控制

      发送和接收使用多进程分离互不影响

4、注意事项

  【1】注重封装

  【2】分段测试

5、代码编写流程

  搭建通信 --> 创建多进程 --->每个进程功能确定 --> 实现每一个功能模块

6、具体细节梳理

  【1】进入聊天室

      ① 客户端 

        ① 输入姓名, 将信息发送给服务器,adress,name

        ② 接受到服务端返回结果判断下一步执行什么

      ② 服务端

        ① 接受消息,判断请求类型

        ② 判断是否可以登录(姓名是否已经存在)

        ③ 返回给客户端是否登录(如果可以服务端会将姓名插入到存储用户信息的数据结构中)

        ④ 给所有人发送消息

  【2】聊天 

      ① 客户端

        ① 发起聊天:name ,msg

        ② 接受服务器回复

      ② 服务端

        ① 接受消息 ,判断消息类型

        ② 组织消息结构转发给其他客户端

  【3】退出聊天室

      ① 客户端

        ① 发送消息退出:Q,name

        ② 接收服务端回复

        ③ 退出程序

      ② 服务端

        ① 接收消息

        ② 判断请求类型

        ③ 从存储用户信息的数据结构中删除对应用户

        ④ 告知所有人,xxx退出 

【fork-socket-groupChat-server.py】
from
socket import * import os,sys #发送管理员消息 def do_child(s,addr): while True: msg = input("管理员消息:") msg = "C 管理员 " + msg s.sendto(msg.encode(),addr) #用户登录 def do_login(s,user,name,addr): if (name in user) or 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 user[name] = addr def do_chat(s,user,name,data): msg = "\n{} 说: {}".format(name,data) for i in user: if i != name: s.sendto(msg.encode(),user[i]) def do_quit(s,user,name): msg = "\n%s 离开了聊天室"%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): # 用于存储用户 {'Alex':('127.0.0.1',8888)} user = {} while True: msg,addr = s.recvfrom(1024) msgList = msg.decode().split(' ') if msgList[0] == 'L': do_login(s,user,msgList[1],addr) elif msgList[0] == 'C': # "C Levi [I miss you]" data = ' '.join(msgList[2:]) do_chat(s,user,msgList[1],data) elif msgList[0] == 'Q': do_quit(s,user,msgList[1]) # 创建套接字,网络连接,创建父子进程 def main(): #server address ADDR = ('0.0.0.0',8888) #创建套接字 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()
【fork-socket-groupChat-client.py】
from
socket import * import sys,os def login(s,ADDR): while True: name = input("请输入用户名:") msg = "L " + name s.sendto(msg.encode(),ADDR) #接收登录结果 data,addr = s.recvfrom(1024) if data.decode() == 'OK': print("@进入聊天室@") return name else: print(data.decode()) #发送消息 def do_child(s,name,addr): while True: 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) #接收消息 def do_parent(s): while True: msg,addr = s.recvfrom(1024) if msg.decode() == 'EXIT': sys.exit(0) print(msg.decode()+"\n发言(quit退出):",end="") #main控制套接字的创建 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) name = login(s,ADDR) if name: pid = os.fork() if pid < 0: sys.exit("创建子进程失败") elif pid == 0: do_child(s,name,ADDR) else: do_parent(s) else: return if __name__ == "__main__": main()

 

posted @ 2021-01-07 15:53  昱成  阅读(328)  评论(0编辑  收藏  举报