How epoll detect clientside close in Python?

后端 未结 10 561
清歌不尽
清歌不尽 2021-02-04 21:22

Here is my server

\"\"\"Server using epoll method\"\"\"

import os
import select
import socket
import time

from oodict import OODict

addr = (\         


        
10条回答
  •  北海茫月
    2021-02-04 21:49

    The issue why you're not detecting EPOLLHUP/EPOLLERR in your code is because of the bitwise operations you are doing. See when a socket is ready to read epoll will throw a flag with bit 1 which is equal to select.EPOLLIN (select.EPOLLIN == 1). Now say the client hangs up (gracefully or not) epoll on the server will throw a flag with bit 25 which is equal to EPOLLIN+EPOLLERR+EPOLLHUP. So with the bit 25 (event variable in your code) you can see how EPOLLERR is not being detected because all of your elif statements (with the exception of EPOLLOUT line) don't return 0 so the first elif statement is executed, for example:

    >>> from select import EPOLLIN,EPOLLOUT,EPOLLHUP,EPOLLERR
    >>> event = 25
    >>> event & EPOLLIN
    1
    >>> event & EPOLLERR
    8
    >>> event & EPOLLHUP
    16
    >>> event & EPOLLOUT
    0
    

    Notice how the first three don't return 0? That's why your code isn't detecting EPOLLERR/EPOLLHUP correctly. When a client hangs up you can still read from the socket as the server side is still up (of course it would return 0 data if you did) hence EPOLLIN but since the client hung up it's also EPOLLHUP and since it's EPOLLHUP it's also EPOLLERR as a hangup is somewhat of an error. I know I'm late on commenting on this but I hope I helped someone out there lol

    Here is a way I would rewrite your code to express what I'm saying better:

    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)
    

提交回复
热议问题