Python基於TCP實現聊天功能

秋夜雨巷發表於2024-03-09

Server端

import socket
import queue
import threading
import time

#socket.AF_INET指定使用IPv4地址族,socket.SOCK_STREAM指定使用TCP協議
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
print("伺服器IP: "+socket.gethostbyname(host))
serversocket.bind((host, 9090))
serversocket.listen(5)
#存放已連線的物件
clients = []
#存放公共訊息的容器
public_message = dict()

#接收新的物件
def init():
    while True:    
        # 當心客戶端連線時
        client,addr = serversocket.accept()  #阻塞執行緒
        if client in clients:
            print('老使用者')
        else:
            print('新的使用者加入:',end='')
            print(client.getpeername()[0])
            client.send(bytes('歡迎來到聊天室(匿名)!'.encode('utf-8')))
            clients.append(client)
			#執行緒啟動時會呼叫receive_msg函式,args為傳遞給函式的引數元組
            r = threading.Thread(target=receive_msg,args=(client,))
            r.start()

#接收訊息
def receive_msg(client):
    while True:
        time.sleep(1)
        try:
            if client in clients:
                data = client.recv(1024).decode('utf-8')
                if data!='':
                    print(data)
                    public_message[client] = queue.Queue()
                    public_message[client].put(data)
                else:
                    if client in clients:
                        print("使用者優雅的退出了")
                        clients.remove(client)
           
        except BaseException as error:

            print('使用者強制中斷了一個連線')
            # print('錯誤:',error)
            if client in clients:
                clients.remove(client)


#轉發訊息(非/阻塞)
def broadcast():
    while True:
        if len(clients)>1:
            public_message_clone = [i for i in public_message]   #解決字典迭代中操作報錯的問題
            for client in clients:
                for i in public_message_clone:
                    if i!=client and public_message[i].empty()==False:
                        data = public_message[i].get_nowait()  #注意
                        if data !='':
                            # 轉發訊息給客戶端
                            client.send(bytes(data.encode('utf-8'))) 
                            print('伺服器轉發了訊息')
         
                    
t1 = threading.Thread(target=init)
t2 = threading.Thread(target=broadcast)

t1.start()
t2.start()


#主執行緒監聽線上人數
while (True):
    print("當前線上人數為:%d"%(len(clients)))
    time.sleep(5)

Client

import socket,threading
#客戶端想要發訊息和收訊息同時進行,需要使用多執行緒達到併發效果

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
# 獲取計算機name
host = socket.gethostname()
# 獲取根據計算機name獲取計算機IP
host = socket.gethostbyname(host);
print(host)
s.connect((host, 9090))

# 接收訊息
def receive():
    while True:
        data = s.recv(1024).decode('utf-8')
        if data!='':
            print(data)

# 傳送訊息
def send_msg():
    while (True):
        msg = input(':')
        if msg=='exit':
            s.close()
            break
        s.send(bytes(msg.encode('utf-8')))
        
t1 = threading.Thread(target=receive,daemon=True)
t1.start()

send_msg()

image

相關文章