読者です 読者をやめる 読者になる 読者になる

py-epoll

Python

Pythonのepollのバインディングは、ぱっと探した限り3つある。

それぞれ独立して書かれており、特徴がある。
まず、PyEpollは、

import select
import epoll

for attr in ['poll', 'error', 'POLLIN', 'POLLPRI', 'POLLOUT', 'POLLERR', 'POLLHUP', 'POLLNVAL']:
    setattr(select, attr, getattr(epoll, attr))

import asyncore

のように、epollをラップして、Pythonのselectモジュールから透過的に使えるようになっているらしい。(試していない。)

Twistedのepollも独立して書かれたモジュールのようで、PyrexでepollのAPIをラップしているようだ。ただし、これは直接使うのではなく、twisted.internet.epollreactorを通して使うのが普通だろう。


で、表題のpy-epollなわけだが、これが一番epollのAPIを素直にラップしたバインディングだと思われる。

epollの勉強のために、試しに、id:odz氏のコードを参考にechoサーバを書いてみた。
・・・が、リソースの開放の仕方がよく分からない。まねしないように。

import os
from epoll import *
from socket import *

PORT       = 10007
MAX_EVENTS = 10
BACKLOG    = 10

sock = socket(AF_INET, SOCK_STREAM, 0)
sock.bind(("127.0.0.1", PORT))
sock.listen(BACKLOG)

clients = {}

try:
    epfd = epoll_create(MAX_EVENTS)
    try:
        epoll_ctl(epfd, EPOLL_CTL_ADD, sock.fileno(), EPOLLIN)
        while 1:
            events = epoll_wait(epfd, 10, -1)
            if events:
                for event, fd in events:
                    if fd == sock.fileno():
                        client, addr = sock.accept()
                        clients[client.fileno()] = client
                        client.setblocking(0)
                        epoll_ctl(epfd, EPOLL_CTL_ADD, client.fileno(), EPOLLIN|EPOLLET)
                    else:
                        client = clients[fd]
                        buf = client.recv(1024)
                        if len(buf) <= 0:
                            epoll_ctl(epfd, EPOLL_CTL_DEL, fd, EPOLLIN)
                            client.close()
                            del clients[fd]
                        else:
                            client.send(buf)
    finally:
        os.close(epfd)
        for s in clients.values():
            s.close()
finally:
    sock.close()