自己寫的聊天室專案
作業:(服務端,客戶端)
寫一個聊天室
功能:類似qq群聊
1.進入聊天室需要輸入姓名,提示一下姓名不能重複
2.有人進入聊天室會向其他人傳送通知
xxx 進入了聊天室
3.一個人發訊息,其他人會收到訊息,自己不收到
xxx 說:xxxxxxxxxxx
4.某人退出聊天室,其他人也會收到通知
xxx 退出了聊天室
5.管理員喊話功能(從服務端傳送訊息,所有客戶端都能接收到)
管理員說:xxxxxx
功能模型:轉發
需要的技術:套接字通訊 udp套接字
使用者儲存:字典或列表
訊息收發的隨意性:多程序(fork)
程式碼設計:
1.封裝 將每個功能封裝為函式
2.介面測試(每實現一步測試一步)
程式碼的編寫流程
1.搭建網路連線
2.建立多程序
3.每個程序功能編寫
4.專案功能模組實現
進入聊天室???????
客戶端:輸入姓名,將資訊發給服務端(L name)標誌位
等待服務端回覆 根據回覆判斷是否登入成功
服務端:接受請求資訊 判斷請求型別 判斷使用者名稱是否存在
如果存在回覆不能登入,如果不 存在回覆可以登入並插入到資料結構
傳送通知給其他使用者
def fun(l):
l.append(6)
#傳遞可變型別引數到函式中,列印原來的形參,同樣改變了
#對可變型別的修改會影響到原來的實參
#傳遞一個不可變型別引數,對引數的修改不會影響原引數
l=[1,2,3,4,5]
fun(l)
print(l)
def fun(l):
l=‘world’
#傳遞不可變型別引數到函式中,列印原來的形參,沒有改變
l=“hello”
fun(l)
print(l)
聊天
客戶端:建立父子程序 傳送聊天請求/接收聊天資訊
服務端:接收請求資訊 將訊息轉發給其他客戶端
退出
管理員訊息
程式碼:服務端
#!/usr/bin/env python3
#coding=utf-8
#文件說明,作者,聯絡方式,
‘’’
name=Yxp
email:[email protected]
date:2018-9
class:AID
introduce:Chatroom server
env:python3.5
‘’’
from socket import *
import os, sys
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,text):
msg ="\n%s說:%s"%(name,text)
for i in user:
if i!=name:
s.sendto(msg.encode(),user[i])
#退出聊天室
def do_quit(s,user,name):
msg=’\n’+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):
#儲存結構{‘zhangssan’?‘127.0.0.1’,9999)}
user={}
while True:
msg,addr = s.recvfrom(1024)
msgList = msg.decode().split(' ')
#區分請求型別
if msgList[0]=='L':
fanhui=do_login(s,user,msgList[1],addr)
elif msgList[0]=='C':
do_chat(s,user,msgList[1],' '.join(msgList[2:]))
elif msgList[0]=='Q':
do_quit(s,user,msgList[1])
#做管理員喊話
def do_child(s,addr):
while True:
msg=input(‘管理員訊息:’)
msg='C 管理員 '+msg#發給自己
s.sendto(msg.encode(),addr)
#建立網路,建立程序,呼叫功能函式
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()
客戶端
#client.py
from socket import *
import sys,os
#傳送訊息
def send_msg(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 recv_msg(s):
while True:
data,addr=s.recvfrom(2048)
if data.decode()==‘EXIT’:
sys.exit(0)
print(data.decode()+"\n發言:",end='')
#建立套接字,然後登入,建立子程序
def main():
if len(sys.argv)❤️:
print(‘argv is error’)
return
HOST=sys.argv[1]
PORT=int(sys.argv[2])
ADDR=(HOST,PORT)
#建立套接字
s=socket(AF_INET,SOCK_DGRAM)
while True:
name=input('請輸入姓名:')
msg='L '+name
#傳送登入請求
s.sendto(msg.encode(),ADDR)
#等待伺服器回覆
data,addr=s.recvfrom(1024)
if data.decode()=='OK':
print('您已進入聊天室')
break
else:
#不成功服務端會回覆不允許登陸原因
print(data.decode())
#建立父子程序,監聽的是同一個地址
pid=os.fork()
if pid<0:
sys.exit('建立子程序失敗')
elif pid==0:
#不讓服務端遍歷姓名
send_msg(s,name,ADDR)
else:
recv_msg(s)
if name==‘main’:
main()