您好,登錄后才能下訂單哦!
這篇文章主要介紹“socket的epoll模型怎么使用”,在日常操作中,相信很多人在socket的epoll模型怎么使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”socket的epoll模型怎么使用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
select模型雖好,卻有一個缺陷,只能對1024個文件描述符進行監視,雖然可以通過重新編譯內核獲得更大的監視數量,但這樣做還不如將目光投向更高級的epoll模型。select模型中,每一次都需要遍歷所有處于監視中的文件描述符,判斷他們哪個可寫,哪個可讀,這樣一來,你監視的越多,速度越慢,而在epoll模型中,所有添加到epoll中的事件都會網卡驅動程序建立起回調關系,簡言之,如果有一個連接可寫,那么這個可寫的事件就會報告給你,而你不需要挨個詢問他們哪個連接可寫,哪個連接可讀。
下面的示例,所實現的功能,和之前的示例一樣,但更加高效:
#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隊列大小為100
serversocket.listen(100)
serversocket.setblocking(0)
epoll = select.epoll()
#注冊一個in事件,等待有數據可讀
epoll.register(serversocket.fileno(), select.EPOLLIN)
try:
#保存連接,請求,和響應信息
connections = {};
message_queues = {} #存儲可發送的數據
while True:
#最多等待1秒鐘時間,有事件返回事件列表
events = epoll.poll(1)
for fileno, event in events:
#事件的句柄是server
if fileno == serversocket.fileno():
connection, address = serversocket.accept()
#設置為非阻塞的
connection.setblocking(0)
#新建的連接也注冊讀事件
epoll.register(connection.fileno(), select.EPOLLIN)
connections[connection.fileno()] = connection
message_queues[connection.fileno()] = MsgContainer()
#不是server,那就是建立的連接,現在連接可讀
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:
#可寫的事件被觸發
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()
#需要回寫的數據已經寫完了,再次注冊讀事件
epoll.modify(fileno, select.EPOLLIN)
elif event & select.EPOLLHUP:
#被掛起了,注銷句柄,關閉連接,這時候,是客戶端主動斷開了連接
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'請輸入端口號'
下面看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個線程嘗試建立連接,如果server端的accept隊列大小設置的小,例如設置為10,就會出現個別連接無法建立的情況,所以我這里設置為100。
到此,關于“socket的epoll模型怎么使用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。