溫馨提示×

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

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

socket的epoll模型怎么使用

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

這篇文章主要介紹“socket的epoll模型怎么使用”,在日常操作中,相信很多人在socket的epoll模型怎么使用問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”socket的epoll模型怎么使用”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

select模型雖好,卻有一個(gè)缺陷,只能對(duì)1024個(gè)文件描述符進(jìn)行監(jiān)視,雖然可以通過重新編譯內(nèi)核獲得更大的監(jiān)視數(shù)量,但這樣做還不如將目光投向更高級(jí)的epoll模型。select模型中,每一次都需要遍歷所有處于監(jiān)視中的文件描述符,判斷他們哪個(gè)可寫,哪個(gè)可讀,這樣一來,你監(jiān)視的越多,速度越慢,而在epoll模型中,所有添加到epoll中的事件都會(huì)網(wǎng)卡驅(qū)動(dòng)程序建立起回調(diào)關(guān)系,簡(jiǎn)言之,如果有一個(gè)連接可寫,那么這個(gè)可寫的事件就會(huì)報(bào)告給你,而你不需要挨個(gè)詢問他們哪個(gè)連接可寫,哪個(gè)連接可讀。

下面的示例,所實(shí)現(xiàn)的功能,和之前的示例一樣,但更加高效:

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

def start_server(port):
   serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
   serversocket.bind(('0.0.0.0', port))
   #accept隊(duì)列大小為100
   serversocket.listen(100)
   serversocket.setblocking(0)

   epoll = select.epoll()
   #注冊(cè)一個(gè)in事件,等待有數(shù)據(jù)可讀
   epoll.register(serversocket.fileno(), select.EPOLLIN)


   try:
       #保存連接,請(qǐng)求,和響應(yīng)信息
       connections = {};
       message_queues = {}         #存儲(chǔ)可發(fā)送的數(shù)據(jù)
       while True:
           #最多等待1秒鐘時(shí)間,有事件返回事件列表
           events = epoll.poll(1)
           for fileno, event in events:
               #事件的句柄是server
               if fileno == serversocket.fileno():
                   connection, address = serversocket.accept()
                   #設(shè)置為非阻塞的
                   connection.setblocking(0)
                   #新建的連接也注冊(cè)讀事件
                   epoll.register(connection.fileno(), select.EPOLLIN)
                   connections[connection.fileno()] = connection
                   message_queues[connection.fileno()] = MsgContainer()
                   #不是server,那就是建立的連接,現(xiàn)在連接可讀
               elif event & select.EPOLLIN:
                   data = connections[fileno].recv(1024)
                   if data :
                       epoll.modify(fileno, select.EPOLLOUT)
                       message_queues[fileno].add_data(data)
                   else:
                       epoll.modify(fileno, 0)
                       connections[fileno].shutdown(socket.SHUT_RDWR)
                       del connections[fileno]
                       del message_queues[fileno]
               elif event & select.EPOLLOUT:
                   #可寫的事件被觸發(fā)
                   if not fileno in message_queues or not fileno in connections:
                       continue
                   clientsocket = connections[fileno]
                   mc = message_queues[fileno]
                   msgs = mc.get_all_msg()
                   for msg in msgs:
                       msg = mc.pack_msg(msg)
                       clientsocket.send(msg)
                   mc.clear_msg()
                   #需要回寫的數(shù)據(jù)已經(jīng)寫完了,再次注冊(cè)讀事件
                   epoll.modify(fileno, select.EPOLLIN)
               elif event & select.EPOLLHUP:
                   #被掛起了,注銷句柄,關(guān)閉連接,這時(shí)候,是客戶端主動(dòng)斷開了連接
                   epoll.unregister(fileno)
                   if fileno in connections:
                       connections[fileno].close()
                       del connections[fileno]
                   if fileno in message_queues:
                       del message_queues[fileno]
   finally:
       epoll.unregister(serversocket.fileno())
       epoll.close()
       serversocket.close()

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

下面看client端的代碼:

#coding=utf-8
import sys
import time
import datetime
import socket
import cPickle
import threading
from MsgContainer import MsgContainer


def start_client(addr,port,msgCount):
   mc = MsgContainer()
   PLC_ADDR = addr
   PLC_PORT = port
   time_lst = []
   s = socket.socket()
   s.connect((PLC_ADDR, PLC_PORT))
   seconds1 = int(time.time())
   i = 0
   while True:
       seconds = int(time.time())
       microseconds = datetime.datetime.now().microsecond
       data = {'sec':seconds,'micsec':microseconds}
       data = cPickle.dumps(data)
       data = mc.pack_msg(data)
       s.send(data)
       recv_data = s.recv(1024)
       mc.add_data(recv_data)
       msgs = mc.get_all_msg()
       seconds = int(time.time())
       microseconds = datetime.datetime.now().microsecond
       for msg in msgs:
           msgdict = cPickle.loads(msg)
           time_lst.append(((seconds-msgdict['sec'])*1000000 + microseconds-msgdict['micsec'])/1000.0)
       mc.clear_msg()
       i += 1
       if i>msgCount:
           print sum(time_lst)/float(len(time_lst))
           break
   s.close()

if __name__ == '__main__':

   if len(sys.argv) == 4:
       addr = sys.argv[1]
       port = int(sys.argv[2])
       msgCount = int(sys.argv[3])
       t_lst = []
       for i in range(100):
           t = threading.Thread(target=start_client,args=(addr,port,msgCount))
           t_lst.append(t)

       for t in t_lst:
           t.start()

       for t in t_lst:
           t.join()

   #start_client('123.56.190.151',8091,100

在客戶端,每次起100個(gè)線程嘗試建立連接,如果server端的accept隊(duì)列大小設(shè)置的小,例如設(shè)置為10,就會(huì)出現(xiàn)個(gè)別連接無法建立的情況,所以我這里設(shè)置為100。

到此,關(guān)于“socket的epoll模型怎么使用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

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

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

AI