1. 程式人生 > 實用技巧 >網路程式設計:fork多程序網路通訊應用例項--聊天室(群聊)

網路程式設計: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()