python制作聊天软件_一步一步教你做聊天软件(Python实现+非阻塞)
首先,我們需要知道實現(xiàn)怎么樣的聊天:
1、不是單工或者半雙工
2、我可以發(fā)消息,也可以不發(fā)消息,并且不影響我收消息
3、我的消息不會發(fā)給自己,我的消息可以發(fā)給其他所有人
4、暫時沒有GUI,只要會做了,弄一個GUI界面是很簡單的,我過兩天有時間再弄一個
知道這幾點要求后,還需要知道實現(xiàn)的方法:
1、基本的socket知識(客戶端是用單純的socket做的)
2、基本的socketserver知識(服務器是用socketserver做的,也可以使用socket+select做),socketserver里面的TCPServer,ThreadingMaxIn兩個模塊
3、使用簡單的線程知識(threaing),這個在客戶端獲取輸入時要求不能阻塞了程序而使用。
這里面幾個模塊要想全部理解有點難,但僅僅是用一下,還是很簡單的,(比如:筆者也有大量不會的地方,很多地方只是會用,特別是threading模塊)
下面,分步來完成這個軟件:
第一步:服務端,可以接受到來自客戶端發(fā)送的消息
from socketserver import TCPServer,ThreadingMixIn,StreamRequestHandler
class Server(ThreadingMixIn,TCPServer):
pass
class Handler(StreamRequestHandler):
def handle(self):
self.request.setblocking(0)? ? ? ? #設置為非阻塞模式
addr = self.request.getpeername()#獲取客戶端的地址(host,port)
print("連接的客戶端地址:%s"%(addr,))
while 1:? ? ? ? ? ? #這一塊是用來接收消息的
try:
data = self.request.recv(1024)
print(data.decode())
except BlockingIOError:
pass
server = Server(('127.0.0.1',13333),Handler)#啟動服務器
server.serve_forever()#將服務器掛起,檢查是否有事件發(fā)生(客戶端請求連接)
在簡書里面空格打得不是很方便,所以縮進有問題,但是最好不要直接復制粘貼,最好自己手打一遍。
在這段代碼中,Server繼承了ThreadingMixIn和TCPServer兩個類,繼承TCPServer是因為我們用的是tcp連接,當有客戶端連接,就會觸發(fā)Handler(),繼承ThreadingMixIn是為了能夠連接多個客戶端,如果不繼承這個的話,就只能連接一個客戶端(底層的原理我也不是很清楚)。
self.request這個可以類比為s = socket.socket(),我覺得可能socket和socketserver兩個都是繼承來自一個更底層的套接字模塊(我不確定),所以他們的方法也幾乎相同,self.request.recv()等同于s.recv()。
self.request.setblocking(0)? ? ? ? #設置為非阻塞模式,看網(wǎng)上很多都沒講清楚怎么用這個,我也是前幾天看著一個很好的博客才懂了這個,這個參數(shù)為0設置為非阻塞模式之后,收發(fā)消息會變成非阻塞模式的,并且會報BlockingIOError的錯,所以需要異常處理。參數(shù)如果為正數(shù)好像是設置阻塞時間(沒有驗證過)。
第二步:差不多了,開始寫客戶端的代碼
import socket,threading
s = socket.socket()
host = socket.gethostbyname("127.0.0.1")#我不是很請楚這個函數(shù)的作用,它的返回值還是"127.0.0.1",沒變化,也可以不要這個方法,直接寫地址就行
port =13333
s.connect((host,port))#連接服務器
id =1#這是本來準備用來給一個編號的,不過后來想想還是讓服務器給編號比較好
def get_input():#獲得輸入,這是一個子線程
while 1:
data =input("》》")
s.send(data.encode())
while 1:
threading_input = threading.Thread(target=get_input)
threading_input.start()#開始子線程
print(s.recv(1024).decode(encoding="utf-8",errors='ignore'))
這里需要說一下的就是threading_input = threading.Thread(target=get_input),target的參數(shù)是你需要執(zhí)行的子線程的函數(shù)名。
另外需要注意的就是編碼問題最好設置為強制編碼,不報錯。
待會你可以創(chuàng)建兩個客戶端連接服務器,然后他們就可以相互通信,不過現(xiàn)在顯然是不可以的,服務器并沒有想著要發(fā)送信息,那么就先來。
第三步:讓服務器開始發(fā)信息
其實知道了前面的知識,后面的你自己嘗試就可以完成,我直接把最終的代碼貼出來,并講述其中需要注意的地方
from socketserverimport TCPServer,ThreadingMixIn,StreamRequestHandler
data_list = []#這里是要點1
class Server(ThreadingMixIn,TCPServer):
pass
class Handler(StreamRequestHandler):
def handle(self):
#設置為非阻塞模式
self.request.setblocking(0)
addr =self.request.getpeername()
select.append(addr)
print("連接的客戶端地址:%s"%(addr,))
while 1:
#這一塊是用來接收消息的
try:
data =self.request.recv(1024)
data = (data,addr)
data_list.append(data)
except:
pass
#下面一塊都是用來發(fā)消息的
for iin data_list:
if addr == i[1]:
continue
try:
self.request.sendall(i[0])
data_list.remove(i)#這一句話涉及了共有變量的修改,會報錯
except BlockingIOError:
continue
except ValueError:#這里是要點2
continue
server = Server(('127.0.0.1',13333),Handler)
server.serve_forever()
要點一:線程中只有全局變量是共享的,而且可以相互通信,那么我就利用全局變量來實現(xiàn)將消息發(fā)給所有的客戶端(除了自己,一個簡單的條件判斷而已)
要點二:這個也是有變量共享引起的,講到這個,我就必須講一下線程,線程和進程的關系大家應該都知道,不知道可以百度,相對應進程,線程最大的優(yōu)點就是可以相互通信,但是一個缺點是,在Python中,(下面我談一下我的理解,雖然看了很多資料,但是我還是不怎么確定),線程在Python中也不是完全同步進行的,是通過時間輪詢執(zhí)行的(個人看法,網(wǎng)上很多大神講過這個,我說的好像有點問題,不過這只是現(xiàn)在的理解),在極短的時間內,進行著切換,那么現(xiàn)在有一個問題了,一個共享變量很有可能我取到了,但是當我執(zhí)行下一句代碼的時候,這個被另一個線程處理掉了。(這就是我所與到的問題,也有可能是線程通過多核同步進行也會遇到這樣的問題,所以我說我不確定。標準的方法是設定鎖,不過鎖的話有點麻煩,我直接用異常處理來解決了)
說完了,第四步就是設置一個GUI界面,并且再完善一下就可以用來多人聊天啦~@^@~
總結
以上是生活随笔為你收集整理的python制作聊天软件_一步一步教你做聊天软件(Python实现+非阻塞)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ubuntu与Windows之间设置共享
- 下一篇: 走向卓越,从远离这5种职场谎言开始