在Python中如何使用Linux的epoll
从2.6开始,Python包含了访问Linux epoll库的API。这篇文章用几个简单的python 3例子来展示下这个API。欢迎大家质疑和反馈。
示例1用python3.0搭建了一个简单的服务:在8080端口监听HTTP请求,把它打印到控制台,并返回一个HTTP响应消息给客户端。
- 第9行:创建服务器socket。
- 第10行:允许在11行使用bind()来监听指定端口,即使这个端口最近被其他程序监听。没有这个设置的话,服务不能运行,直到一两分钟后,这个端口不再被之前的程序使用。
- 第11行:监听这台机器所有可用的IPv4地址上面的8080端口。
- 第12行:通知服务端socket开始接受来自客户端的连接。
- 第 14行:这行代码直到接收到一个客户端连接才会完成。这时,服务端socket会在服务端机器上面创建一个新的socket,用来和客户端通信。这个新的 socket在代码里面就是accept()调用返回的clientconnection 对象。返回的address对象代表着客户端的IP和端口。
- 第15-17行:组装从客户端传输过来的数据,直到HTTP请求完成。HTTP协议可以参考这里。
- 第18行:把请求打印到控制台,验证操作是否正确。
- 第19行:发送响应回客户端。
- 第20-22行:关闭和客户端的连接以及服务端监听socket。
官方howto中对python socket编程有更详细的描述。
Example 1 (All examples use Python 3)
1 import socket 2 3 EOL1 = b'\n\n' 4 EOL2 = b'\n\r\n' 5 response = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n' 6 response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n' 7 response += b'Hello, world!' 8 9 serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 10 serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 11 serversocket.bind(('0.0.0.0', 8080)) 12 serversocket.listen(1) 13 14 connectiontoclient, address = serversocket.accept() 15 request = b'' 16 while EOL1 not in request and EOL2 not in request: 17 request += connectiontoclient.recv(1024) 18 print(request.decode()) 19 connectiontoclient.send(response) 20 connectiontoclient.close() 21 22 serversocket.close()
示例2在15行增加了一个循环来不断的处理来自客户端的连接,直到用户中断(比如键盘中断)。这个例子更清楚的说明服务端socket从不和客户端交换数据。相反的,它接收客户端的连接,然后在这台服务器上面创建一个新的socket用来和客户端通信。
在23-24行的finally语句,可以确保服务端负责监听的socket会关闭,即使有异常发生。
Example 2
1 import socket 2 3 EOL1 = b'\n\n' 4 EOL2 = b'\n\r\n' 5 response = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n' 6 response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n' 7 response += b'Hello, world!' 8 9 serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 10 serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 11 serversocket.bind(('0.0.0.0', 8080)) 12 serversocket.listen(1) 13 14 try: 15 while True: 16 connectiontoclient, address = serversocket.accept() 17 request = b'' 18 while EOL1 not in request and EOL2 not in request: 19 request += connectiontoclient.recv(1024) 20 print('-'*40 + '\n' + request.decode()[:-2]) 21 connectiontoclient.send(response) 22 connectiontoclient.close() 23 finally: 24 serversocket.close()