文章目錄
- 一、實驗名稱
- 二、實驗目的
- 三、實驗內容和要求
- 四、實驗環境
- 五、操作方法與實驗步驟
- 六、實驗資料記錄和結果分析
一、實驗名稱
建立聊天工具
很多人學習蟒蛇,不知道從何學起, 很多人學習python,掌握了基本語法之后,不知道在哪里尋找案例上手, 很多已經做了案例的人,卻不知道如何去學習更多高深的知識, 那么針對這三類人,我給大家提供一個好的學習平臺,免費獲取視頻教程,電子書,以及課程的源代碼! QQ群:101677771 歡迎加入,一起討論一起學習!
二、實驗目的
掌握Socket編程中流套接字的技術,實作多臺電腦之間的聊天,
三、實驗內容和要求
vii.掌握利用Socket進行編程的技術
viii.必須掌握多執行緒技術,保證雙方可以同時發送
ix.建立聊天工具
x.可以和多個人同時進行聊天
xi.必須使用圖形界面,顯示雙方的語錄
四、實驗環境
PC多臺,作業系統Win7,win10(32位、64位)
具備軟體python3.6 ,
五、操作方法與實驗步驟
服務端
1.調入多執行緒、與scoket包,用于實作多執行緒連接
2.記錄本地地址與埠,開啟監聽,等待請求
3.收到某個客戶端的請求,建立連接,為每一個客戶端分配一個執行緒,并記錄客戶端地址與埠
4.收到某個客戶端發送的資料,將資料轉發給所有與服務器連接的客戶機,
5.當某個客戶端斷開連接,通知所有與服務器連接的客戶機,
6.服務器一直保持監聽狀態,等待其他客戶端接入服務器
7.代碼
import socket
import threading
num=0
def chat(service_client_socket,addr):
# 等待接收客戶端訊息存放在2個變數service_client_socket和addr里
if not addr in user:
print('Accept new connection from %s:%s...' % addr)
# 如果addr不在user字典里則執行以下代碼
for scs in serv_clie_socket:
serv_clie_socket[scs].send(data +' 進入聊天室...'.encode('utf-8'))
# 發送user字典的data和address到客戶端
user[addr] = data.decode('utf-8') #data 是最新進入聊天室的客戶,解壓后放入user
serv_clie_socket[addr] = service_client_socket #將服務器與服務器埠號為addr的套接字放入字典
# 接收的訊息解碼成utf-8并存在字典user里,鍵名定義為addr
#print("可以開始聊天了>>>>>>")
# 如果addr在user字典里,跳過本次回圈
while True:
d = service_client_socket.recv(1024)
if (('EXIT'.lower() in d.decode('utf-8'))|(d.decode('utf-8') == 'error1')):
#如果EXIT在發送的data里
name = user[addr]
#user字典addr鍵對應的值賦值給變數name
user.pop(addr)
serv_clie_socket.pop(addr)
#洗掉user里的addr
for scs in serv_clie_socket:
#從user取出address
serv_clie_socket[scs].send((name + ' 離開了聊天室...').encode('utf-8'))
#發送name和address到客戶端
print('Connection from %s:%s closed.' % addr)
global num
num = num-1
break
else:
print('"%s" from %s:%s' %(d.decode('utf-8'), addr[0], addr[1]))
for scs in serv_clie_socket:
#從user遍歷出address
if serv_clie_socket[scs] != service_client_socket:
#address不等于addr時,執行下面的代碼
serv_clie_socket[scs].send(d)
#發送data到客戶端
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 創建socket物件
addr = ('127.0.0.1', 9999)
s.bind(addr) # 系結地址和埠
s.listen(128)
print('TCP Server on', addr[0], ":",addr[1],"......")
user = {} # 存放字典{addr:name}
serv_clie_socket = {} #存放{socket:不同執行緒的套接字}
while True:
try:
print("等待接收客戶端的連接請求....")
service_client_socket, addr = s.accept() # 等待接收客戶端的連接請求
print("接收到客戶端的連接請求....")
except ConnectionResetError:
print('Someone left unexcept.')
data = https://www.cnblogs.com/pythonQqun200160592/archive/2021/12/22/service_client_socket.recv(1024)
if data.decode()=='error1':
print(addr,"關閉了登錄視窗,,,")
continue
print("data = "https://www.cnblogs.com/pythonQqun200160592/archive/2021/12/22/,data.decode())
#為服務器分配執行緒
num=num+1
r = threading.Thread(target=chat, args=(service_client_socket,addr), daemon=True)
r.start()
print("聊天室人數:",num)
客戶端
1.調入多執行緒、與scoket包,用于實作多執行緒連接,調入tkinter包,用于圖形化頁面展示
2.記錄本地地址與埠,向服務器發送連接請求,建立持續連接
3.圖形化登錄界面,記錄輸入的用戶名,發送給服務器
4.進入聊天界面,從服務器接收到的訊息顯示在左邊,發送給服務器的訊息顯示在右邊
5.退出時,彈出警示界面,退出后,與服務器斷開連接,結束,
6.代碼
7.其他:客戶端代碼中的server改成服務器地址,客戶端可以在不同的電腦上運行連接服務器,通過服務器與其他的客戶端通訊,
#客戶端
import tkinter
from tkinter import font
import tkinter.messagebox
import socket
import threading
import time
string=''
def my_string(s_input):
string = s_input.get()
def Send(sock):
'''
發送資料的方法
引數:
sock:定義一個實體化socket物件
server:傳遞的服務器IP和埠
'''
if string!='':
message = name + ' : ' + string
data = https://www.cnblogs.com/pythonQqun200160592/archive/2021/12/22/message.encode('utf-8')
sock.send(data)
if string.lower() == 'EXIT'.lower():
exit()
def recv(sock):
sock.send(name.encode('utf-8'))
while True:
data = https://www.cnblogs.com/pythonQqun200160592/archive/2021/12/22/sock.recv(1024)
#加一個時間戳
time_tuple = time.localtime(time.time())
str = ("{}點{}分".format(time_tuple[3],time_tuple[4]))
rrecv = tkinter.Label(t,text=data.decode('utf-8'),width=40,anchor='w',bg='pink')#接收的訊息靠左邊
rrecv.pack()
def left():
global string
string = rv1.get()
Send(s)
if string!='':
rleft = tkinter.Label(t,text=string,width=40,anchor='e')#發送的訊息靠右邊
rleft.pack()
rv1.set('')
def Creat():
global name
name = n.get()
#接收行程
tr = threading.Thread(target=recv, args=(s,), daemon=True)
# daemon=True 表示創建的子執行緒守護主執行緒,主執行緒退出子執行緒直接銷毀
tr.start()
l.destroy()
e.destroy()
b.destroy()
t.title("聊天室")
t.geometry("500x600")
rL0 = tkinter.Label(t,text='%s的聊天室'%name,width=40)
rL0.pack()
rL1 = tkinter.Label(t,text='請輸入訊息:',width=20, height=1)
rL1.place(x=0,y=450)
rE1 = tkinter.Entry(t, textvariable = rv1)
rE1.place(x=200,y=450)
rB1 = tkinter.Button(t, text="發送",command=left)
rB1.place(x=380,y=450)
#發送行程
def JieShu():
tkinter.messagebox.showwarning(title='你確定退出嗎?', message='剛才你點擊了關閉按鈕')
s.send("error1".encode('utf-8'))
exit(0)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server = ('10.100.207.40', 9999)
s.connect(server)#建立連接
t=tkinter.Tk()
t.title("多人聊天室")
t.geometry("300x200+500+200")
l = tkinter.Label(t,text='多人聊天室歡迎您,請輸入你的名稱',width=40, height=8)
l.pack()
n = tkinter.StringVar()
e = tkinter.Entry(t, width=15,textvariable = n)
e.pack()
rv1 = tkinter.StringVar()
name = n.get()
b = tkinter.Button(t, text="登錄",width=40, height=10,command=Creat)
b.pack()
t.protocol("WM_DELETE_WINDOW", JieShu)
t.mainloop()
s.close()
六、實驗資料記錄和結果分析
1.服務器啟動,等待客戶機連接請求
2.客戶端請求服務,客戶端彈出登錄視窗,輸入用戶名登錄
3.服務器接收到請求,分配埠,并持續監聽其他客戶機的請求
4.客戶端登陸后進入聊天視窗
5.進入聊天室的用戶,發送訊息,其他用戶都可以接收到,服務器也能看到
6.客戶機退出連接,其他用戶都可以接收到,服務器也能看到
7.其他客戶機可以中途進入聊天室
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/390239.html
標籤:其他
