溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何使用socket的select模型

發(fā)布時間:2021-12-18 14:46:15 來源:億速云 閱讀:142 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“如何使用socket的select模型”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“如何使用socket的select模型”吧!

Select模型在windows下和linux下都可以使用,更高級的epoll模型只能在linux下使用。

在開始select之前,先糾正一個錯誤,MsgContainer中的__check_head函數(shù)應(yīng)當(dāng)改為下面的樣子:

def __check_head(self):
    if self.msg_len == 0 and len(self.msgpond) > 5:
        self.__get_msg_len()
    self.__get_msg()

這個錯誤竟然沒有人反饋,可見,大家只是看一看,都沒有實際驗證或使用。。。。。

select模型其實很好理解,我們給它三個數(shù)組,數(shù)組里存放的是socket,每一次的select,模型會從這三個數(shù)組中分別挑出來可讀的,可寫的,發(fā)生異常的socket,并分別放入到三個數(shù)組中,這樣,應(yīng)用層遍歷這三個數(shù)組,做相應(yīng)的操作??创a:

#coding=utf-8
import select
import socket
import sys
from MsgContainer import MsgContainer

def start_server(port):
   HOST='0.0.0.0'
   PORT=port

   server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
   #server.setblocking(False)
   server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR  , 1)
   server.bind((HOST,PORT))   #套接字綁定的IP與端口
   server.listen(10)           #開始TCP監(jiān)聽

   inputs = [server]           #存放需要被檢測可讀的socket
   outputs = []                #存放需要被檢測可寫的socket
   message_queues = {}         #存儲可發(fā)送的數(shù)據(jù)

   while inputs:
       readable , writable , exceptional = select.select(inputs, outputs, inputs)
       # 可讀
       for s in readable:
           if s is server:
               connection, client_address = s.accept()
               inputs.append(connection)
               message_queues[connection] = MsgContainer()
           else:
               data = s.recv(3)        #故意設(shè)置的這么小
               if data :
                   message_queues[s].add_data(data)
                   #已經(jīng)從這個socket當(dāng)中收到數(shù)據(jù),如果你想寫,那么就將其加入到outputs中,等到select模型檢查它是否可寫
                   if s not in outputs:
                       outputs.append(s)
               else:
                   #收到為空的數(shù)據(jù),意味著對方已經(jīng)斷開連接,需要做清理工作
                   if s in outputs :
                       outputs.remove(s)
                   inputs.remove(s)
                   s.close()
                   del message_queues[s]

       #可寫
       for w in writable:
           #此處一定要判斷w是否真的可寫,有可能w既在readable中,也在writable中,而讀到的數(shù)據(jù)是空,這樣其實是關(guān)閉了連接
           if not w in message_queues:
               continue
           mc = message_queues[w]
           msgs = mc.get_all_msg()
           print msgs
           for msg in msgs:
               msg = mc.pack_msg(msg)
               w.send(msg)
           mc.clear_msg()
           outputs.remove(w)
       # 異常
       for s in exceptional:
           inputs.remove(s)
           if s in outputs:
               outputs.remove(s)
           s.close()
           del message_queues[s]

if __name__ == '__main__':
   if len(sys.argv) == 2:
       port = int(sys.argv[1])
       start_server(port)
   else:
       print u'請輸入端口號'

這里就幾個你可能疑惑的問題做重點講解。

發(fā)現(xiàn)一個可讀的socket時,如何去接收數(shù)據(jù)呢?此前我提供的例子,都是在wihle循環(huán)里不停的讀取,在select模型中,仍然可以這樣使用,但是要注意,需要把socket設(shè)置為非阻塞的,這樣才能從while循環(huán)中退出來。本篇的例子沒有使用while循環(huán),而是每次讀取3個字節(jié)的數(shù)據(jù),如果對方發(fā)過來的數(shù)據(jù)長度是9,那么第一次讀取后,接收緩沖區(qū)里還有6個字節(jié)的數(shù)據(jù)可讀,在下一次select操作過程中,這個socket仍然會被放入到readtable中,這樣,就可以繼續(xù)讀剩下的數(shù)據(jù)了。

       在遍歷writable數(shù)組時,一定要判斷該socket是不是真的可寫。我在實際測試中發(fā)現(xiàn)了這樣的情況,一個socket既在readtable中也在writable中,但在讀的時候,數(shù)據(jù)是空,對方關(guān)閉了連接,此時在去寫數(shù)據(jù),就會發(fā)生錯誤,所以我通過對message_queues做了一個簡單的檢查來判斷socket是不是真的可寫。

在每一次寫操作執(zhí)行后,都從socket從writable中刪除,這樣做的原因很簡單,該寫的數(shù)據(jù)已經(jīng)寫完了,如果不刪除,下一次select操作時,又會把他放入到writable中,可是現(xiàn)在已經(jīng)沒有數(shù)據(jù)需要寫了啊,這樣做沒有意義,只會浪費(fèi)select操作的時間,因為它要遍歷outputs中的每一個socket,判斷他們是否可寫以決定是否將其放入到writtable中。

       在exceptional中,是發(fā)生錯誤和異常的socket,有了這個數(shù)組,就在也不用操心錯誤和異常了,不然程序?qū)懫饋矸浅5膹?fù)雜,有了統(tǒng)一的管理,發(fā)生錯誤后的清理工作將變得非常簡單。

到此,相信大家對“如何使用socket的select模型”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI