Проблема, по которой вы не обнаруживаете EPOLLHUP / EPOLLERR в своем коде, связана с побитовыми операциями, которые вы делаете. Посмотрите, когда сокет будет готов к чтению, epoll выдаст флаг с битом 1, равным select.EPOLLIN (select.EPOLLIN == 1). Теперь предположим, что клиент вешает трубку (изящно или нет). Epoll на сервере сгенерирует флаг с битом 25, который равен EPOLLIN + EPOLLERR + EPOLLHUP. Таким образом, с битом 25 (переменная события в вашем коде) вы можете видеть, как EPOLLERR не обнаруживается, потому что все ваши операторы elif (за исключением строки EPOLLOUT) не возвращают 0, поэтому выполняется первый оператор elif, например :
>>> from select import EPOLLIN,EPOLLOUT,EPOLLHUP,EPOLLERR
>>> event = 25
>>> event & EPOLLIN
1
>>> event & EPOLLERR
8
>>> event & EPOLLHUP
16
>>> event & EPOLLOUT
0
Обратите внимание, как первые три не возвращают 0? Вот почему ваш код не определяет EPOLLERR / EPOLLHUP правильно. Когда клиент вешает трубку, вы все равно можете читать из сокета, так как серверная сторона все еще работает (конечно, он вернул бы 0 данных, если вы это сделали), следовательно, EPOLLIN, но, поскольку клиент повесил трубку, это также EPOLLHUP и, так как это EPOLLHUP, это также EPOLLERR как зависание является своего рода ошибкой. Я знаю, что опоздал комментировать это, но я надеюсь, что помог кому-то там LOL
Вот способ, которым я бы переписал ваш код, чтобы лучше выразить то, что я говорю:
import os
import select
import socket
import time
from oodict import OODict
addr = ('localhost', 8989)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(8)
s.setblocking(0) # Non blocking socket server
epoll = select.epoll()
read_only = select.EPOLLIN | select.EPOLLPRI | select.EPOLLHUP | select.EPOLLERR
read_write = read_only | select.EPOLLOUT
biterrs = [25,24,8,16,9,17,26,10,18] #Bitwise error numbers
epoll.register(s.fileno(),read_only)
cs = {}
data = ''
while True:
time.sleep(1)
events = epoll.poll(1) # Timeout 1 second
print 'Polling %d events' % len(events)
for fileno, event in events:
if fileno == s.fileno():
sk, addr = s.accept()
sk.setblocking(0)
print addr
cs[sk.fileno()] = sk
epoll.register(sk.fileno(),read_only)
elif (event is select.EPOLLIN) or (event is select.EPOLLPRI):
data = cs[fileno].recv(4)
print 'recv ', data
epoll.modify(fileno, read_write)
elif event is select.EPOLLOUT:
print 'send ', data
cs[fileno].send(data)
data = ''
epoll.modify(fileno, read_only)
elif event in biterrs:
print 'err'
epoll.unregister(fileno)