Python網(wǎng)絡(luò)編程基于多線程實(shí)現(xiàn)多用戶全雙工聊天功能示例
本文實(shí)例講述了Python網(wǎng)絡(luò)編程基于多線程實(shí)現(xiàn)多用戶全雙工聊天功能。分享給大家供大家參考,具體如下:
在前面一篇《Python網(wǎng)絡(luò)編程使用select實(shí)現(xiàn)socket全雙工異步通信功能》中,我們實(shí)現(xiàn)了1對1的異步通信,在文章結(jié)尾,給出了多對多通信的思路。
既然說了,咱就動(dòng)手試一試,本次用的是多線程來實(shí)現(xiàn),正好練練手~
首先講一下思路:
我們將服務(wù)器做為中轉(zhuǎn)站來處理信息,一方面與客戶端互動(dòng),另一方面進(jìn)行消息轉(zhuǎn)發(fā)。
大體思路確定下來后,需要確定一些通信規(guī)則:
1. 客戶端與服務(wù)器建立連接后,需要輸入用戶名登入,若用戶名已存在,將reuse反饋給用戶,用戶輸出錯(cuò)誤信息,退出
2. 用戶輸入正確的用戶名后,即可進(jìn)行通信了。如果未選擇通信對象,則服務(wù)器會反饋信息,提示用戶選擇通信對象
3. 選擇通信對象的方法為,輸入to:username,如果所選擇的對象不存在,反饋錯(cuò)誤信息,重新輸入
4.當(dāng)正確選擇通信對象后,雙方建立連接,通過服務(wù)器中轉(zhuǎn)信息進(jìn)行通信
5.在通信中,若發(fā)送‘quit',則結(jié)束發(fā)送消息的線程,并指示服務(wù)器該用戶準(zhǔn)備登出,服務(wù)器刪除該用戶后,反饋消息給用戶,用戶結(jié)束接收消息的線程并退出
6.如果A正在與C通信,此時(shí)B向A發(fā)送信息,則A的通信窗口變?yōu)榕cB的通信窗口,即接收到B消息后,A發(fā)出的消息不再是給C,而是默認(rèn)給B
實(shí)現(xiàn)代碼:
#!/usr/bin/python 'test TCP server' from socket import * from time import ctime import threading #多線程模塊 import re #正則表達(dá)式模塊 HOST = '' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) def Deal(sock, user): while True: data = sock.recv(BUFSIZ) #接收用戶的數(shù)據(jù) if data == 'quit': #用戶退出 del clients[user] sock.send(data) sock.close() print '%s logout' %user break elif re.match('to:.+', data) is not None: #選擇通信對象 data = data[3:] if clients.has_key(data): chatwith[sock] = clients[data] chatwith[clients[data]] = sock else: sock.send('the user %s is not exist' %data) else: if chatwith.has_key(sock): #進(jìn)行通信 chatwith[sock].send("[%s] %s: %s" %(ctime(), user, data)) else: sock.send('Please input the user who you want to chat with') tcpSerSock = socket(AF_INET, SOCK_STREAM) tcpSerSock.bind(ADDR) tcpSerSock.listen(5) clients = {} #提供 用戶名->socket 映射 chatwith = {} #提供通信雙方映射 while True: print 'waiting for connection...' tcpCliSock, addr = tcpSerSock.accept() print '...connected from:',addr username = tcpCliSock.recv(BUFSIZ) #接收用戶名 print 'The username is:',username if clients.has_key(username): #查找用戶名 tcpCliSock.send("Reuse") #用戶名已存在 tcpCliSock.close() else: tcpCliSock.send("Welcome!") #登入成功 clients[username] = tcpCliSock chat = threading.Thread(target = Deal, args = (tcpCliSock,username)) #創(chuàng)建新線程進(jìn)行處理 chat.start() #啟動(dòng)線程 tcpSerSock.close()
#!/usr/bin/python 'test tcp client' from socket import * import threading HOST = 'localhost' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) threads = [] def Send(sock, test): #發(fā)送消息 while True: data = raw_input('>') tcpCliSock.send(data) if data == 'quit': break def Recv(sock, test): #接收消息 while True: data = tcpCliSock.recv(BUFSIZ) if data == 'quit': sock.close() #退出時(shí)關(guān)閉socket break print data tcpCliSock = socket(AF_INET, SOCK_STREAM) tcpCliSock.connect(ADDR) print 'Please input your username:', username = raw_input() tcpCliSock.send(username) data = tcpCliSock.recv(BUFSIZ) if data == 'Reuse': print 'The username has been used!' else: print 'Welcome!' chat = threading.Thread(target = Send, args = (tcpCliSock,None)) #創(chuàng)建發(fā)送信息線程 threads.append(chat) chat = threading.Thread(target = Recv, args = (tcpCliSock,None)) #創(chuàng)建接收信息線程 threads.append(chat) for i in range(len(threads)): #啟動(dòng)線程 threads[i].start() threads[0].join() #在我們的設(shè)計(jì)中,send線程必然先于recv線程結(jié)束,所以此處只需要調(diào)用send的join,等待recv線程的結(jié)束。
當(dāng)然,本程序還有許多不足之處,比如通信雙方中A退出時(shí),另一方B的通信列表中仍然又A,此時(shí)如果B再向已經(jīng)登出的B發(fā)送消息,就會出錯(cuò)。博主比較懶,就不修復(fù)這個(gè)bug啦~
更多關(guān)于Python相關(guān)內(nèi)容可查看本站專題:《Python Socket編程技巧總結(jié)》、《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》、《Python入門與進(jìn)階經(jīng)典教程》及《Python文件與目錄操作技巧匯總》
希望本文所述對大家Python程序設(shè)計(jì)有所幫助。
相關(guān)文章
python簡單實(shí)現(xiàn)基于SSL的IRC bot實(shí)例
這篇文章主要介紹了python簡單實(shí)現(xiàn)基于SSL的IRC bot,實(shí)例分析了IRC機(jī)器人的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-06-06Matplotlib實(shí)戰(zhàn)之折線圖繪制詳解
折線圖是一種用于可視化數(shù)據(jù)變化趨勢的圖表,它可以用于表示任何數(shù)值隨著時(shí)間或類別的變化,本文主要介紹了如何利用Matplotlib實(shí)現(xiàn)折線圖的繪制,感興趣的可以了解下2023-08-08Python的Flask框架標(biāo)配模板引擎Jinja2的使用教程
Jinja2是Python世界的一款高人氣template engine,是許多開源Web框架的選擇,包括Flask這樣的明星級項(xiàng)目,這里我們就來共同學(xué)習(xí)Python的Flask框架標(biāo)配模板引擎Jinja2的使用教程2016-07-07經(jīng)驗(yàn)豐富程序員才知道的15種高級Python小技巧(收藏)
本文將介紹15個(gè)簡潔的Python技巧,向著簡潔更高效,學(xué)習(xí)易懂出發(fā),具說只有經(jīng)驗(yàn)豐富程序員才知道的15種高級Python小技巧,喜歡的朋友快來看看吧2021-10-10Tensorflow實(shí)現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)的詳細(xì)代碼
這篇文章主要為大家詳細(xì)介紹了Tensorflow實(shí)現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)的詳細(xì)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05Django配置celery(非djcelery)執(zhí)行異步任務(wù)和定時(shí)任務(wù)
這篇文章主要介紹了Django配置celery(非djcelery)執(zhí)行異步任務(wù)和定時(shí)任務(wù),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07