這篇文章主要介紹“python中怎么用socket實現協議TCP長連接框架”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“python中怎么用socket實現協議TCP長連接框架”文章能幫助大家解決問題。
“ 使用python實現協議中常見的TCP長連接框架。”
分析多了協議就會發現,很多的應用,特別是游戲類和IM類應用,它們的協議會使用長連接的方式,來保持客戶端與服務器的聯系,這些長連接,通常是TCP承載的。
如果我們要模擬這個客戶端的行為,根據不同應用服務器的實現情況,有些長連接不是必須的,但有些長連接,就必須去實現它。例如最近分析的某應用,雖然它主要使用HTTP協議進行交互,但它在TCP長連接中傳輸了一些必須的信息,如果不實現長連接,就會有很多信息無法處理。
在python中,很容易實現HTTP協議,當然,也容易實現TCP協議,它的TCP實現,使用socket庫就可以了,只是需要注意,TCP長連接中通常傳輸的是十六進制數據,協議非標準的,需要自行根據協議分析結果來封裝數據格式。
這里以一個使用到TCP長連接的協議為樣例,來給出協議的TCP長連接框架,大家有需要可以參考實現,當然,代碼也是從樣例中摘出來的,并不是完整的。
我的TCP長連接框架,首先是外部的包裝,初始化一些參數,例如長連接使用到的ip端口及socket套接字等:
self.longip='im.langren001.com' self.longport= 6656 self.threadLock = threading.Lock() self.sockmain = socket.socket(socket.AF_INET, socket.SOCK_STREAM); self.longlinktcpstart2() tlonglink = threading.Thread(target=lrsuser.longlinktcpth3,name='mainlink_'+ self.playinfo['uid'], args=(self,)) tlonglink.start() self.threadinfo.append(tlonglink)
這個里面調用了兩個函數,一個是longlinktcpstart2函數,作用是建立socket連接,并對一些連接建立初始時的交互進行實現,另一個是longlinktcpth3函數,是一個線程,實現對連接內的數據進行收發處理。一般來說,這兩個可以在一起實現,但為了方便socket異常斷開的處理,分成了兩個函數。
longlinktcpstart2的實現如下:
def longlinktcpstart2(self):
server_address = (self.longip, int(self.longport))
self.savelogs('longlinktcpstart2', 'Connecting to %s:%d.' % server_address)
self.sockmain.connect(server_address)
self.databuf = b''
message = genbaseinfo.genalive()
self.sockmain.sendall(message)
message = genbaseinfo.genfirstdata()
if len(message)==0:
self.savelogs('longlinktcpstart2', 'genfirstdata error ')
return False
self.sockmain.sendall(message)
self.longlinkcnt=2
cnt = 0
while (cnt < 2):
try:
buf = self.sockmain.recv(2048)
sz = len(buf)
self.savelogs('longlinktcpstart2', "recv data len "+str(sz) )
if sz > 0:
self.databuf +=buf
self.dealdatabuf()
if cnt == 0:
alivemsg = genbaseinfo.genalive()
self.sockmain.sendall(alivemsg)
self.savelogs('longlinktcpstart2', "sendalive")
regtime=int(round(time.time() * 1000))-random.randint(14400000,25200000)
regtime=regtime*1000
pcode = self.versionstr + '.0'
message = genbaseinfo.genseconddata()
if len(message) == 0:
self.savelogs('longlinktcpstart2', 'genseconddata error ')
return False
self.sockmain.sendall(message)
self.longlinkcnt = self.longlinkcnt + 1
elif cnt == 1:
pcode = self.versionstr + '.0'
message = genbaseinfo.genotherdata()
if len(message) == 0:
self.savelogs('longlinktcpstart2', 'genthirddata error ')
return False
self.sockmain.sendall(message)
self.longlinkcnt = self.longlinkcnt + 1
cnt = cnt + 1
else:
self.savelogs('longlinktcpstart2', 'recv data alive')
except: # socket.error
self.savelogs('longlinktcpstart2', 'socket error,do connect fail')
return False
return True這里面的genbaseinfo 相關的函數可以忽略,是用來生成發送的消息數據的實現,用自己的函數去替換即可。dealdatabuf函數是用來處理收到的消息數據實現,這兩個都要根據具體的協議分析情況去實現,注意,生成的用來發送的數據和接收到的需要處理的數據,都需要按十六進制處理,這里不做詳述。
線程longlinktcpth3是一個循環,協議不退出,循環不結束,實現如下:
def longlinktcpth3(self):
tmalive = 0;
r_inputs = set()
r_inputs.add(self.sockmain)
w_inputs = set()
w_inputs.add(self.sockmain)
e_inputs = set()
e_inputs.add(self.sockmain)
tm=int(round(time.time()))
self.savelogs('longlinktcpth3', 'enter' )
while (self.quitflag==0):
try:
r_list, w_list, e_list = select.select(r_inputs, w_inputs, e_inputs, 1)
for event in r_list:
try:
buf = event.recv(2048)
sz = len(buf)
self.savelogs('longlinktcpth3', "loop recv data len:"+ str(sz) )
if sz > 0:
self.databuf += buf
self.dealdatabuf()
alivemsg = genbaseinfo.genalive()
self.sockmain.sendall(alivemsg)
self.savelogs('longlinktcpth3', "sendalive")
else:
self.savelogs('longlinktcpth3', "遠程斷開連接,do reconnect")
r_inputs.clear()
time.sleep(3)
self.sockmain = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.longlinktcpstart2()
r_inputs = set()
r_inputs.add(self.sockmain)
w_inputs = set()
w_inputs.add(self.sockmain)
e_inputs = set()
e_inputs.add(self.sockmain)
except Exception as e:
self.savelogs('longlinktcpth3', str(e))
self.threadLock.acquire()
if (len(self.msglist) > 0):
msg = self.msglist.pop(0)
self.threadLock.release()
self.sockmain.sendall(msg)
self.savelogs('longlinktcpth3',"send a msg")
else:
self.threadLock.release()
tmnow=int(round(time.time()))
if tmnow-tm>30:
message = genbaseinfo.genotherdata()
if len(message) == 0:
self.savelogs('longlinktcpth3', 'genalivedata error ')
return False
self.sockmain.sendall(message)
self.savelogs('longlinktcpth3', "send alivemsg"+str(self.longlinkcnt))
self.longlinkcnt = self.longlinkcnt + 1 #這個要一條連接統一,不能亂,回頭加鎖
tm=tmnow
if len(w_list) > 0: # 產生了可寫的事件,即連接完成
self.savelogs('longlinktcpth3',str(w_list))
w_inputs.clear() # 當連接完成之后,清除掉完成連接的socket
if len(e_list) > 0: # 產生了錯誤的事件,即連接錯誤
self.savelogs('longlinktcpth3', str(e_list))
e_inputs.clear() # 當連接有錯誤發生時,清除掉發生錯誤的socket
except OSError as e:
self.savelogs('longlinktcpth3', 'socket error,do reconnect')
time.sleep(3)
self.sockmain = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.longlinktcpstart2()
r_inputs = set()
r_inputs.add(self.sockmain)
w_inputs = set()
w_inputs.add(self.sockmain)
e_inputs = set()
e_inputs.add(self.sockmain)
self.savelogs('longlinktcpth3', 'leave')由于這個代碼主要是在windows上使用,因此,longlinktcpth3線程采用了select來實現,而沒有使用epoll。在循環中,對異常進行了處理,如果發生異常,連接被斷開,則調用longlinktcpstart2重新連接,而不退出循環,其余的和longlinktcpstart2里面一致。
關于“python中怎么用socket實現協議TCP長連接框架”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。