原文地址: http://scotdoyle.com/python-epoll-howto.html

文章里面的代码可以 点击这里下载.

<p>
  第一个例子是一个简单的python3.0版本的服务器代码, 监听8080端口的http请求, 打印结果到命令行, 回应http response给客户端.
</p>

<ul>
  <li>
    行 9: 建立服务器的socket
  </li>
  <li>
    行 10: 允许11行的bind()操作, 即使其他程序也在监听同样的端口. 不然的话, 这个程序只能在其他程序停止使用这个端口之后的1到2分钟后才能执行.
  </li>
  <li>
    行 11: 绑定socket到这台机器上所有IPv4地址上的8080端口.
  </li>
  <li>
    行 12: 告诉服务器开始响应从客户端过来的连接请求.
  </li>
  <li>
    行 14: 程序会一直停在这里, 直到建立了一个连接. 这个时候, 服务器socket会建立一个新的socket, 用来和客户端通讯. 这个新的socket是accept()的返回值, address对象标示了客户端的IP地址和端口.
  </li>
  <li>
    行 15-17: 接收数据, 直到一个完整的http请求被接收完毕. <a href="http://www.jmarshall.com/easy/http/">这是一个简单的http服务器实现</a>.
  </li>
  <li>
    行 18: 为了方便验证, 打印客户端过来的请求到命令行.
  </li>
  <li>
    行 19: 发送回应.
  </li>
  <li>
    行 20-22: 关闭连接, 以及服务器的监听socket.
  </li>
</ul>

<p>
<p>
  <a href="http://docs.python.org/3.0/howto/sockets.html">python官方 HOWTO</a> 里面有具体如何使用socket编程的描述.
</p>

<div>
  <pre class="brush: python; title: Example; notranslate" title="Example">

import socket

EOL1 = b’nn' EOL2 = b’nrn' response = b’HTTP/1.0 200 OKrnDate: Mon, 1 Jan 1996 01:01:01 GMTrn' response += b’Content-Type: text/plainrnContent-Length: 13rnrn' response += b’Hello, world!'

serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serversocket.bind((‘0.0.0.0’, 8080)) serversocket.listen(1)

connectiontoclient, address = serversocket.accept() request = b'' while EOL1 not in request and EOL2 not in request: request += connectiontoclient.recv(1024) print(request.decode()) connectiontoclient.send(response) connectiontoclient.close()

serversocket.close()

<p>
  第2个例子, 我们在15行加上了一个循环, 用来循环处理客户端请求, 直到我们中断这个过程(在命令行下面输入键盘中断, 比如Ctrl-C). 这个例子更明显地表示出来了, 服务器socket并没有用来做数据处理, 而是接受服务器过来的连接, 然后建立一个新的socket, 用来和客户端通讯.
</p>

<p>
  最后的23-24行确保服务器的监听socket最后总是close掉, 即使出现了异常.
</p>

<div>
  <pre class="brush: python; title: Example; notranslate" title="Example">

import socket

EOL1 = b’nn' EOL2 = b’nrn' response = b’HTTP/1.0 200 OKrnDate: Mon, 1 Jan 1996 01:01:01 GMTrn' response += b’Content-Type: text/plainrnContent-Length: 13rnrn' response += b’Hello, world!'

serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serversocket.bind((‘0.0.0.0’, 8080)) serversocket.listen(1)

try: while True: connectiontoclient, address = serversocket.accept() request = b'' while EOL1 not in request and EOL2 not in request: request += connectiontoclient.recv(1024) print('-'*40 + ‘n’ + request.decode()[:-2]) connectiontoclient.send(response) connectiontoclient.close() finally: serversocket.close()

EOL1 = b’nn' EOL2 = b’nrn' response = b’HTTP/1.0 200 OKrnDate: Mon, 1 Jan 1996 01:01:01 GMTrn' response += b’Content-Type: text/plainrnContent-Length: 13rnrn' response += b’Hello, world!'

serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serversocket.bind((‘0.0.0.0’, 8080)) serversocket.listen(1) serversocket.setblocking(0)

epoll = select.epoll() epoll.register(serversocket.fileno(), select.EPOLLIN)

try: connections = {}; requests = {}; responses = {} while True: events = epoll.poll(1) for fileno, event in events: if fileno == serversocket.fileno(): connection, address = serversocket.accept() connection.setblocking(0) epoll.register(connection.fileno(), select.EPOLLIN) connections[connection.fileno()] = connection requests[connection.fileno()] = b'' responses[connection.fileno()] = response elif event & select.EPOLLIN: requests[fileno] += connections[fileno].recv(1024) if EOL1 in requests[fileno] or EOL2 in requests[fileno]: epoll.modify(fileno, select.EPOLLOUT) print('-'*40 + ‘n’ + requests[fileno].decode()[:-2]) elif event & select.EPOLLOUT: byteswritten = connections[fileno].send(responses[fileno]) responses[fileno] = responses[fileno][byteswritten:] if len(responses[fileno]) == 0: epoll.modify(fileno, 0) connections[fileno].shutdown(socket.SHUT_RDWR) elif event & select.EPOLLHUP: epoll.unregister(fileno) connections[fileno].close() del connections[fileno] finally: epoll.unregister(serversocket.fileno()) epoll.close() serversocket.close()

EOL1 = b’nn' EOL2 = b’nrn' response = b’HTTP/1.0 200 OKrnDate: Mon, 1 Jan 1996 01:01:01 GMTrn' response += b’Content-Type: text/plainrnContent-Length: 13rnrn' response += b’Hello, world!'

serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serversocket.bind((‘0.0.0.0’, 8080)) serversocket.listen(1) serversocket.setblocking(0)

epoll = select.epoll() epoll.register(serversocket.fileno(), select.EPOLLIN | select.EPOLLET)

try: connections = {}; requests = {}; responses = {} while True: events = epoll.poll(1) for fileno, event in events: if fileno == serversocket.fileno(): try: while True: connection, address = serversocket.accept() connection.setblocking(0) epoll.register(connection.fileno(), select.EPOLLIN | select.EPOLLET) connections[connection.fileno()] = connection requests[connection.fileno()] = b'' responses[connection.fileno()] = response except socket.error: pass elif event & select.EPOLLIN: try: while True: requests[fileno] += connections[fileno].recv(1024) except socket.error: pass if EOL1 in requests[fileno] or EOL2 in requests[fileno]: epoll.modify(fileno, select.EPOLLOUT | select.EPOLLET) print('-'*40 + ‘n’ + requests[fileno].decode()[:-2]) elif event & select.EPOLLOUT: try: while len(responses[fileno]) > 0: byteswritten = connections[fileno].send(responses[fileno]) responses[fileno] = responses[fileno][byteswritten:] except socket.error: pass if len(responses[fileno]) == 0: epoll.modify(fileno, select.EPOLLET) connections[fileno].shutdown(socket.SHUT_RDWR) elif event & select.EPOLLHUP: epoll.unregister(fileno) connections[fileno].close() del connections[fileno] finally: epoll.unregister(serversocket.fileno()) epoll.close() serversocket.close()

EOL1 = b’nn' EOL2 = b’nrn' response = b’HTTP/1.0 200 OKrnDate: Mon, 1 Jan 1996 01:01:01 GMTrn' response += b’Content-Type: text/plainrnContent-Length: 13rnrn' response += b’Hello, world!'

serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serversocket.bind((‘0.0.0.0’, 8080)) serversocket.listen(1) serversocket.setblocking(0)

epoll = select.epoll() epoll.register(serversocket.fileno(), select.EPOLLIN)

try: connections = {}; requests = {}; responses = {} while True: events = epoll.poll(1) for fileno, event in events: if fileno == serversocket.fileno(): connection, address = serversocket.accept() connection.setblocking(0) epoll.register(connection.fileno(), select.EPOLLIN) connections[connection.fileno()] = connection requests[connection.fileno()] = b'' responses[connection.fileno()] = response elif event & select.EPOLLIN: requests[fileno] += connections[fileno].recv(1024) if EOL1 in requests[fileno] or EOL2 in requests[fileno]: epoll.modify(fileno, select.EPOLLOUT) connections[fileno].setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 1) print('-'*40 + ‘n’ + requests[fileno].decode()[:-2]) elif event & select.EPOLLOUT: byteswritten = connections[fileno].send(responses[fileno]) responses[fileno] = responses[fileno][byteswritten:] if len(responses[fileno]) == 0: connections[fileno].setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 0) epoll.modify(fileno, 0) connections[fileno].shutdown(socket.SHUT_RDWR) elif event & select.EPOLLHUP: epoll.unregister(fileno) connections[fileno].close() del connections[fileno] finally: epoll.unregister(serversocket.fileno()) epoll.close() serversocket.close()

EOL1 = b’nn' EOL2 = b’nrn' response = b’HTTP/1.0 200 OKrnDate: Mon, 1 Jan 1996 01:01:01 GMTrn' response += b’Content-Type: text/plainrnContent-Length: 13rnrn' response += b’Hello, world!'

serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serversocket.bind((‘0.0.0.0’, 8080)) serversocket.listen(1) serversocket.setblocking(0) serversocket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

epoll = select.epoll() epoll.register(serversocket.fileno(), select.EPOLLIN)

try: connections = {}; requests = {}; responses = {} while True: events = epoll.poll(1) for fileno, event in events: if fileno == serversocket.fileno(): connection, address = serversocket.accept() connection.setblocking(0) epoll.register(connection.fileno(), select.EPOLLIN) connections[connection.fileno()] = connection requests[connection.fileno()] = b'' responses[connection.fileno()] = response elif event & select.EPOLLIN: requests[fileno] += connections[fileno].recv(1024) if EOL1 in requests[fileno] or EOL2 in requests[fileno]: epoll.modify(fileno, select.EPOLLOUT) print('-'*40 + ‘n’ + requests[fileno].decode()[:-2]) elif event & select.EPOLLOUT: byteswritten = connections[fileno].send(responses[fileno]) responses[fileno] = responses[fileno][byteswritten:] if len(responses[fileno]) == 0: epoll.modify(fileno, 0) connections[fileno].shutdown(socket.SHUT_RDWR) elif event & select.EPOLLHUP: epoll.unregister(fileno) connections[fileno].close() del connections[fileno] finally: epoll.unregister(serversocket.fileno()) epoll.close() serversocket.close()

摘自:http://www.linjunhalida.com/article/python%E4%B8%8B%E4%BD%BF%E7%94%A8epoll