欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

python用socket實(shí)現(xiàn)協(xié)議TCP長(zhǎng)連接框架

 更新時(shí)間:2022年02月10日 10:41:05   作者:多姿多彩  
大家好,本篇文章主要講的是python用socket實(shí)現(xiàn)協(xié)議TCP長(zhǎng)連接框架,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下

 使用python實(shí)現(xiàn)協(xié)議中常見(jiàn)的TCP長(zhǎng)連接框架。

分析多了協(xié)議就會(huì)發(fā)現(xiàn),很多的應(yīng)用,特別是游戲類和IM類應(yīng)用,它們的協(xié)議會(huì)使用長(zhǎng)連接的方式,來(lái)保持客戶端與服務(wù)器的聯(lián)系,這些長(zhǎng)連接,通常是TCP承載的。

如果我們要模擬這個(gè)客戶端的行為,根據(jù)不同應(yīng)用服務(wù)器的實(shí)現(xiàn)情況,有些長(zhǎng)連接不是必須的,但有些長(zhǎng)連接,就必須去實(shí)現(xiàn)它。例如最近分析的某應(yīng)用,雖然它主要使用HTTP協(xié)議進(jìn)行交互,但它在TCP長(zhǎng)連接中傳輸了一些必須的信息,如果不實(shí)現(xiàn)長(zhǎng)連接,就會(huì)有很多信息無(wú)法處理。

在python中,很容易實(shí)現(xiàn)HTTP協(xié)議,當(dāng)然,也容易實(shí)現(xiàn)TCP協(xié)議,它的TCP實(shí)現(xiàn),使用socket庫(kù)就可以了,只是需要注意,TCP長(zhǎng)連接中通常傳輸?shù)氖鞘M(jìn)制數(shù)據(jù),協(xié)議非標(biāo)準(zhǔn)的,需要自行根據(jù)協(xié)議分析結(jié)果來(lái)封裝數(shù)據(jù)格式。

這里以一個(gè)使用到TCP長(zhǎng)連接的協(xié)議為樣例,來(lái)給出協(xié)議的TCP長(zhǎng)連接框架,大家有需要可以參考實(shí)現(xiàn),當(dāng)然,代碼也是從樣例中摘出來(lái)的,并不是完整的。

我的TCP長(zhǎng)連接框架,首先是外部的包裝,初始化一些參數(shù),例如長(zhǎng)連接使用到的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.longlinktcpth2,name='mainlink_'+ self.playinfo['uid'], args=(self,))
        tlonglink.start()
        self.threadinfo.append(tlonglink)

這個(gè)里面調(diào)用了兩個(gè)函數(shù),一個(gè)是longlinktcpstart2函數(shù),作用是建立socket連接,并對(duì)一些連接建立初始時(shí)的交互進(jìn)行實(shí)現(xiàn),另一個(gè)是longlinktcpth2函數(shù),是一個(gè)線程,實(shí)現(xiàn)對(duì)連接內(nèi)的數(shù)據(jù)進(jìn)行收發(fā)處理。一般來(lái)說(shuō),這兩個(gè)可以在一起實(shí)現(xiàn),但為了方便socket異常斷開(kāi)的處理,分成了兩個(gè)函數(shù)。

 longlinktcpstart2的實(shí)現(xiàn)如下:

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 相關(guān)的函數(shù)可以忽略,是用來(lái)生成發(fā)送的消息數(shù)據(jù)的實(shí)現(xiàn),用自己的函數(shù)去替換即可。dealdatabuf函數(shù)是用來(lái)處理收到的消息數(shù)據(jù)實(shí)現(xiàn),這兩個(gè)都要根據(jù)具體的協(xié)議分析情況去實(shí)現(xiàn),注意,生成的用來(lái)發(fā)送的數(shù)據(jù)和接收到的需要處理的數(shù)據(jù),都需要按十六進(jìn)制處理,這里不做詳述。

線程longlinktcpth2是一個(gè)循環(huán),協(xié)議不退出,循環(huán)不結(jié)束,實(shí)現(xiàn)如下:

def longlinktcpth2(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('longlinktcpth2', '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('longlinktcpth2', "loop recv data len:"+ str(sz) )
                        if sz > 0:
                            self.databuf += buf
                            self.dealdatabuf()
                            alivemsg = genbaseinfo.genalive()
                            self.sockmain.sendall(alivemsg)
                            self.savelogs('longlinktcpth2', "sendalive")
                        else:
                            self.savelogs('longlinktcpth2', "遠(yuǎn)程斷開(kāi)連接,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('longlinktcpth2', str(e))
                self.threadLock.acquire()
                if (len(self.msglist) > 0):
                    msg = self.msglist.pop(0)
                    self.threadLock.release()
                    self.sockmain.sendall(msg)
                    self.savelogs('longlinktcpth2',"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('longlinktcpth2', 'genalivedata error ')
                        return False
                    self.sockmain.sendall(message)
                    self.savelogs('longlinktcpth2', "send alivemsg"+str(self.longlinkcnt))
                    self.longlinkcnt = self.longlinkcnt + 1 #這個(gè)要一條連接統(tǒng)一,不能亂,回頭加鎖
                    tm=tmnow
                if len(w_list) > 0:  # 產(chǎn)生了可寫(xiě)的事件,即連接完成
                    self.savelogs('longlinktcpth2',str(w_list))
                    w_inputs.clear()  # 當(dāng)連接完成之后,清除掉完成連接的socket
 
 
                if len(e_list) > 0:  # 產(chǎn)生了錯(cuò)誤的事件,即連接錯(cuò)誤
                    self.savelogs('longlinktcpth2', str(e_list))
                    e_inputs.clear()  # 當(dāng)連接有錯(cuò)誤發(fā)生時(shí),清除掉發(fā)生錯(cuò)誤的socket
            except OSError as e:
                self.savelogs('longlinktcpth2', '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('longlinktcpth2', 'leave')

由于這個(gè)代碼主要是在windows上使用,因此,longlinktcpth2線程采用了select來(lái)實(shí)現(xiàn),而沒(méi)有使用epoll。在循環(huán)中,對(duì)異常進(jìn)行了處理,如果發(fā)生異常,連接被斷開(kāi),則調(diào)用longlinktcpstart2重新連接,而不退出循環(huán),其余的和longlinktcpstart2里面一致。

由于TCP連接是流的概念,因此,需要對(duì)數(shù)據(jù)進(jìn)行緩存拼接,這就是上面代碼中databuf的作用,防止每次收到的數(shù)據(jù)不完整或者太多,方便后續(xù)的處理,這才是一個(gè)合格的碼農(nóng)的信仰的自我升華。

到此這篇關(guān)于python用socket實(shí)現(xiàn)協(xié)議TCP長(zhǎng)連接框架的文章就介紹到這了,更多相關(guān)python TCP長(zhǎng)連接內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入理解NumPy簡(jiǎn)明教程---數(shù)組3(組合)

    深入理解NumPy簡(jiǎn)明教程---數(shù)組3(組合)

    本篇文章對(duì)NumPy數(shù)組進(jìn)行較深入的探討。首先介紹自定義類型的數(shù)組,接著數(shù)組的組合,最后介紹數(shù)組復(fù)制方面的問(wèn)題,有興趣的可以了解一下。
    2016-12-12
  • Python實(shí)現(xiàn)樸素貝葉斯分類器的方法詳解

    Python實(shí)現(xiàn)樸素貝葉斯分類器的方法詳解

    這篇文章主要介紹了Python實(shí)現(xiàn)樸素貝葉斯分類器的方法,詳細(xì)分析了樸素貝葉斯分類器的概念、原理、定義、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2018-07-07
  • 深入理解Python單元測(cè)試unittest的使用示例

    深入理解Python單元測(cè)試unittest的使用示例

    本篇文章主要介紹了深入理解Python單元測(cè)試unittest的使用示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11
  • Python?format字符串格式化函數(shù)的使用

    Python?format字符串格式化函數(shù)的使用

    本文主要介紹了Python?format字符串格式化函數(shù)的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 淺析Python中else語(yǔ)句塊的使用技巧

    淺析Python中else語(yǔ)句塊的使用技巧

    這篇文章主要介紹了淺析Python中else語(yǔ)句塊的使用技巧的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-06-06
  • python: 判斷tuple、list、dict是否為空的方法

    python: 判斷tuple、list、dict是否為空的方法

    今天小編就為大家分享一篇python: 判斷tuple、list、dict是否為空的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-10-10
  • Python selenium+cookie實(shí)現(xiàn)免密登陸的示例代碼

    Python selenium+cookie實(shí)現(xiàn)免密登陸的示例代碼

    本文主要介紹了Python selenium+cookie實(shí)現(xiàn)免密登陸的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • django中使用Celery 布式任務(wù)隊(duì)列過(guò)程詳解

    django中使用Celery 布式任務(wù)隊(duì)列過(guò)程詳解

    這篇文章主要介紹了django中使用Celery 布式任務(wù)隊(duì)列實(shí)現(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • OpenCV簡(jiǎn)單標(biāo)準(zhǔn)數(shù)字識(shí)別的完整實(shí)例

    OpenCV簡(jiǎn)單標(biāo)準(zhǔn)數(shù)字識(shí)別的完整實(shí)例

    這篇文章主要給大家介紹了關(guān)于OpenCV簡(jiǎn)單標(biāo)準(zhǔn)數(shù)字識(shí)別的相關(guān)資料,要通過(guò)opencv 進(jìn)行數(shù)字識(shí)別離不開(kāi)訓(xùn)練庫(kù)的支持,需要對(duì)目標(biāo)圖片進(jìn)行大量的訓(xùn)練,才能做到精準(zhǔn)的識(shí)別出目標(biāo)數(shù)字,需要的朋友可以參考下
    2021-09-09
  • 基于python實(shí)現(xiàn)rpc遠(yuǎn)程過(guò)程調(diào)用

    基于python實(shí)現(xiàn)rpc遠(yuǎn)程過(guò)程調(diào)用

    本文主要介紹了基于python實(shí)現(xiàn)rpc遠(yuǎn)程過(guò)程調(diào)用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06

最新評(píng)論