溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python網(wǎng)絡(luò)編程基于多線程實(shí)現(xiàn)多用戶全雙工聊天功能示例

發(fā)布時(shí)間:2020-10-12 20:19:22 來源:腳本之家 閱讀:178 作者:jiange_zh 欄目:開發(fā)技術(shù)

本文實(shí)例講述了Python網(wǎng)絡(luò)編程基于多線程實(shí)現(xiàn)多用戶全雙工聊天功能。分享給大家供大家參考,具體如下:

在前面一篇《Python網(wǎng)絡(luò)編程使用select實(shí)現(xiàn)socket全雙工異步通信功能》中,我們實(shí)現(xiàn)了1對1的異步通信,在文章結(jié)尾,給出了多對多通信的思路。

既然說了,咱就動手試一試,本次用的是多線程來實(shí)現(xiàn),正好練練手~

首先講一下思路:

我們將服務(wù)器做為中轉(zhuǎn)站來處理信息,一方面與客戶端互動,另一方面進(jìn)行消息轉(zhuǎn)發(fā)。

大體思路確定下來后,需要確定一些通信規(guī)則:

1. 客戶端與服務(wù)器建立連接后,需要輸入用戶名登入,若用戶名已存在,將reuse反饋給用戶,用戶輸出錯誤信息,退出

2. 用戶輸入正確的用戶名后,即可進(jìn)行通信了。如果未選擇通信對象,則服務(wù)器會反饋信息,提示用戶選擇通信對象

3. 選擇通信對象的方法為,輸入to:username,如果所選擇的對象不存在,反饋錯誤信息,重新輸入

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()  #啟動線程
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)):  #啟動線程
    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ā)送消息,就會出錯。博主比較懶,就不修復(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ì)有所幫助。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI