Python 基于 Socket 實(shí)現(xiàn)群聊
來源:博客園-huny
https://www.cnblogs.com/huny/p/14051152.html
【導(dǎo)語】互聯(lián)網(wǎng)時(shí)代,怎么能不懂點(diǎn)網(wǎng)絡(luò)編程?套接字(Sockets)是雙向通信信道的端點(diǎn),本文詳細(xì)介紹了使用Socket實(shí)現(xiàn)類似微信群聊的功能,快進(jìn)來一起學(xué)習(xí)下吧!
1.前言
套接字(Sockets)是雙向通信信道的端點(diǎn)。套接字可以在一個(gè)進(jìn)程內(nèi),在同一機(jī)器上的進(jìn)程之間,或者在不同主機(jī)的進(jìn)程之間進(jìn)行通信,主機(jī)可以是任何一臺(tái)有連接互聯(lián)網(wǎng)的機(jī)器。
套接字可以通過多種不同的通道類型實(shí)現(xiàn):Unix域套接字,TCP,UDP等。套接字庫提供了處理公共傳輸?shù)奶囟悾约耙粋€(gè)用于處理其余部分的通用接口。
1.1 socket模塊:
要?jiǎng)?chuàng)建套接字,必須使用套接字模塊中的socket.socket()函數(shù),該函數(shù)具有一般語法
s = socket.socket (socket_family, socket_type, protocol = 0)
1.2 常用方法

2. 示例1
2.1 服務(wù)器端
#sever.pyimport sockets = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)host = socket.gethostname()port = 8088s.bind((host,port))try:while True:receive_data,addr = s.recvfrom(1024)print("來自服務(wù)器" + str(addr) + "的消息:")print(receive_data.decode('utf-8'))msg = input('please input send to msg:')s.sendto(msg.encode('utf-8'),addr)except:s.close()
2.2 客戶端
#client.pyimport sockets = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)try:while True:host = socket.gethostname()port = 8088send_data = input('please input msg:')s.sendto(send_data.encode('utf-8'),(host,port))msg,addr = s.recvfrom(1024)print("來自服務(wù)器" + str(addr) + "的消息:")print(msg.decode('utf-8'))except:s.close()
服務(wù)器示例

客戶端示例

簡(jiǎn)易的UDP聊天實(shí)現(xiàn)了,下面我們來優(yōu)化一下示例。
3.示例優(yōu)化
服務(wù)端
#server.pyimport socketimport loggingdef main():s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 創(chuàng)建socket對(duì)象addr = ('127.0.0.1', 9999)s.bind(addr) # 綁定地址和端口logging.info('UDP Server on %s:%s...', addr[0], addr[1])user = {} # 存放字典{addr:name}while True:try:data, addr = s.recvfrom(1024) # 等待接收客戶端消息存放在2個(gè)變量data和addr里if not addr in user: # 如果addr不在user字典里則執(zhí)行以下代碼for address in user: # 從user遍歷數(shù)據(jù)出來addresss.sendto(data + ' 進(jìn)入聊天室...'.encode('utf-8'), address) # 發(fā)送user字典的data和address到客戶端user[addr] = data.decode('utf-8') # 接收的消息解碼成utf-8并存在字典user里,鍵名定義為addrcontinue # 如果addr在user字典里,跳過本次循環(huán)if 'EXIT'.lower() in data.decode('utf-8'):#如果EXIT在發(fā)送的data里name = user[addr] #user字典addr鍵對(duì)應(yīng)的值賦值給變量nameuser.pop(addr) #刪除user里的addrfor address in user: #從user取出addresss.sendto((name + ' 離開了聊天室...').encode(), address) #發(fā)送name和address到客戶端else:print('"%s" from %s:%s' %(data.decode('utf-8'), addr[0], addr[1]))for address in user: #從user遍歷出addressif address != addr: #address不等于addr時(shí)間執(zhí)行下面的代碼s.sendto(data, address) #發(fā)送data和address到客戶端except ConnectionResetError:logging.warning('Someone left unexcept.')if __name__ == '__main__':main()
客戶端
#clinet.pyimport socketimport threadingdef recv(sock, addr):'''一個(gè)UDP連接在接收消息前必須要讓系統(tǒng)知道所占端口也就是需要send一次,否則win下會(huì)報(bào)錯(cuò)'''sock.sendto(name.encode('utf-8'), addr)while True:data = sock.recv(1024)print(data.decode('utf-8'))def send(sock, addr):'''發(fā)送數(shù)據(jù)的方法參數(shù):sock:定義一個(gè)實(shí)例化socket對(duì)象server:傳遞的服務(wù)器IP和端口'''while True:string = input('')message = name + ' : ' + stringdata = message.encode('utf-8')sock.sendto(data, addr)if string.lower() == 'EXIT'.lower():breakdef main():'''主函數(shù)執(zhí)行方法,通過多線程來實(shí)現(xiàn)多個(gè)客戶端之間的通信'''s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)server = ('127.0.0.1', 9999)tr = threading.Thread(target=recv, args=(s, server), daemon=True)ts = threading.Thread(target=send, args=(s, server))tr.start()ts.start()ts.join()s.close()if __name__ == '__main__':print("-----歡迎來到聊天室,退出聊天室請(qǐng)輸入'EXIT(不分大小寫)'-----")name = input('請(qǐng)輸入你的名稱:')print('-----------------%s------------------' % name)main()
支持多人的簡(jiǎn)易聊天室示例,多個(gè)客戶端通過一個(gè)服務(wù)器進(jìn)行之間通信。




- EOF -
回復(fù)關(guān)鍵字“簡(jiǎn)明python ”,立即獲取入門必備書籍《簡(jiǎn)明python教程》電子版
回復(fù)關(guān)鍵字“爬蟲”,立即獲取爬蟲學(xué)習(xí)資料
版權(quán)申明:內(nèi)容來源網(wǎng)絡(luò),版權(quán)歸原創(chuàng)者所有。除非無法確認(rèn),都會(huì)標(biāo)明作者及出處,如有侵權(quán),煩請(qǐng)告知,我們會(huì)立即刪除并致歉。我們對(duì)文中觀點(diǎn)保持中立,僅供參考、交流之目的。

