python的select和epoll
1.select模型:
- linux中每個套接字都是文件,都有唯一的文件描述符,這些設備的文件描述符被放在一個數組中,然后select調用的時候遍歷這個數組,如果對於的文件描述符可讀則會返回改文件描述符。當遍歷結束之后,如果仍然沒有一個可用設備文件描述符,select讓用戶進程則會睡眠,直到等待資源可用的時候在喚醒,遍歷之前那個監視的數組。每次遍歷都是以輪詢的方式依次進行判斷的。
select實現回顯服務器:
from socket import *
from select import *
s = socket(2,1)
s.setsockopt(1,2,1)
s.bind(('',8080))
s.listen(1024)
s_list = [s.fileno(),] #fileno()獲取套接字的唯一描述符,每個套接字都是唯一不同的
s_dict = {}
while 1:
list_readable,a,b = select(s_list,[],[]) #分別對應: 輸入,輸出,錯誤輸出
for i in list_readable:
if i == s.fileno():
conn,userinfo = s.accept()
s_list.append(conn.fileno())
s_dict[conn.fileno()] = conn
else:
cs = s_dict[i]
recv_data = cs.recv(1024)
if len(recv_data) <= 0:
s_dict[i].close()
s_dict.pop(i)
s_list.remove(i)
else:
cs.send(recv_data)
2.epoll模型:
- select模型會受到文件描述符數量的限制,所以一般最多是1024個套接字,而epoll突破了此限制。
- epoll采用的是事件通知機制,而不再是以輪詢的方式挨個詢問每個文件描述符的狀態,節省cpu時間。
- epoll是select的進階版。一般情況下epoll效率更高
epoll實現回顯服務器:
from socket import *
from select import *
s = socket(2,1)
s.setsockopt(1,2,1)
s.bind(('',8080))
s.listen(1024)
s_dict = {}
epoll_instance = epoll()
epoll_instance.register(s.fileno(),EPOLLIN|EPOLLET)
while 1:
epoll_list = epoll_instance.poll()
for fd,event in epoll_list:
if fd == s.fileno():
cs,userinfo = s.accept()
epoll_instance.register(cs.fileno(),EPOLLIN|EPOLLET)
s_dict[cs.fileno()] = cs
else:
cs = s_dict[fd]
recv_data = cs.recv(1024)
print(recv_data.decode('gb2312'))
if len(recv_data) > 0 :
cs.send(recv_data)
else:
print('adsfasdf')
epoll_instance.unregister(fd)
cs.close()
s_dict.pop(fd)
- 注:EPOLLIN(可讀),EPOLLOUT(可寫)
- EPOLLET: 邊緣觸發模式(只通知一次)
- EPOLLLT:水平觸發模式(通知后沒有做處理的話還會繼續通知)