本文的文字及圖片來源於網絡,僅供學習、交流使用,不具備任何商業用途,版權歸原做者全部,若有問題請及時聯繫咱們以做處理。python
做者: Python應用寶典數據庫
PS:若有須要Python學習資料的小夥伴能夠加點擊下方連接自行獲取服務器
http://note.youdao.com/noteshare?id=3054cce4add8a909e784ad934f956cef微信
原理簡介網絡
在咱們今天的教程中,將用到即時通信的概念,即時通信容許兩人或多人同時使用網絡傳遞文字信息、文字、語音等。即時通信通常都基於socket鏈接,socket鏈接可用於發送或接受數據,通常的組合形式是IP+端口號。多線程
也就是說,在咱們的例子中,聊天的雙方,由一方要承擔「服務器 」 的責任,維持一個socket服務器,等待鏈接進入;另外一方則是「客戶端」,在服務器端維持等待狀態時便可發送請求,創建鏈接。socket
當你和ta想進入「小黑屋 」 裏聊天的時候,只有有一方充當服務器,另外一方充當客戶端便可,做爲「服務器端 」 的那我的,在微信中將IP和端口號告訴對方,便可構建鏈接,在小黑屋裏聊天,這個小黑屋裏的數據不會被任何數據庫保留(除非你本身作了一個保存的數據庫)。tcp
服務器端函數
聊天的時候,咱們有時候會遇到雙方同時發消息的狀況。這種聊天方式就叫全雙工聊天方式:「服務器」可向「客戶端」發送消息,「客戶端」也可向「服務端」發送消息,並且容許同時發送消息。學習
服務器端怎麼實現全雙工的聊天方式呢?其實很簡單,只要用多線程就好了,主線程用於接收客戶端的鏈接,鏈接成功後新建兩個線程:一個用於發送消息,一個用於接收消息:
首先,創建socket服務器:
1 import socket 2 import traceback 3 # 設定ip和端口號 4 host = '' 5 port = 51423 6 # 創建socket服務器 7 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 8 s.bind((host,port)) 9 s.listen() 10 while True: 11 # 等待鏈接 12 try: 13 clientsock, clientaddr = s.accept() 14 except KeyboardInterrupt: 15 raise 16 except: 17 traceback.print_exc() 18 continue
其中,AF_INET指的是用IPv4進行通訊,而SOCK_STREAM指的是TCP協議。端口號你能夠隨意設定,服務器端的IP地址默認爲空便可。
在while循環中不斷等待用戶的鏈接。若是有用戶鏈接成功了,咱們將進入下一步,分別創建發送和接受線程:
1 # 創建接收線程 2 t = _thread.start_new_thread(processRecv, (clientsock,)) 3 4 # 創建發送線程 5 r = _thread.start_new_thread(processSend, (clientsock,))
clientsock就是咱們獲得的socket鏈接,processRecv和processSend分別用於處理接受信息和處理髮送信息:
1 import _thread 2 def processRecv(clientsock): 3 """ 4 接受消息 5 :param clientsock: 客戶端的socket鏈接 6 """ 7 while True: 8 data = clientsock.recv(4096) 9 if not len(data): 10 break 11 print (data.decode('utf-8')) 12 clientsock.close() 13 14 def processSend(clientsock): 15 """ 16 發送消息 17 :param clientsock: 客戶端的socket鏈接 18 """ 19 while True: 20 data = input("> ") 21 data = data 22 clientsock.sendall(data.encode('utf-8')) 23 clientsock.close()
有個小細節要注意,socket鏈接的sendall函數只支持bytes類型的數據,因此咱們要encode('utf-8')。
服務端的全部代碼就這樣,沒錯,就是這麼簡單。
客戶端則更簡單,主線程自己設定爲接受消息,那麼咱們只須要多一個線程用於發送消息便可。客戶端的所有代碼以下:
1 import _thread 2 import sys 3 from socket import * 4 5 def send_message(tcpCliSock): 6 """ 7 發送信息 8 :param tcpCliSock: 與服務端的socket鏈接 9 """ 10 while True: 11 message = input('> ') 12 if not message: 13 break 14 tcpCliSock.send(message.encode('utf-8')) 15 16 tcpCliSock.close() 17 18 if(len(sys.argv) < 3): 19 HOST = 'localhost' 20 PORT = 51423 21 else: 22 HOST = sys.argv[1] 23 PORT = int(sys.argv[2]) 24 25 BUFSIZ = 1024 26 ADDR = (HOST,PORT) 27 28 tcpCliSock = socket(AF_INET,SOCK_STREAM) 29 tcpCliSock.connect(ADDR) 30 31 # 創建發送消息的線程 32 s = _thread.start_new_thread(send_message, (tcpCliSock,)) 33 34 while True: 35 rdata = tcpCliSock.recv(BUFSIZ) 36 if not rdata: 37 break 38 print (rdata.decode('utf-8')) 39 40 tcpCliSock.close()
其中,HOST部分填寫對方的IP,PORT部分填寫端口號。sys.argv用於經過參數輸入這兩個值,好比咱們將客戶端文件命名爲:client.py, 在cmd中輸入:
python client.py 127.0.0.1 51423