码迷,mamicode.com
首页 > 编程语言 > 详细

Python-Epoll

时间:2014-09-04 20:45:30      阅读:379      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   http   color   os   io   ar   for   

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

Asynchronous Socket Programming Examples with epoll

Programs using epoll often perform actions in this sequence:

  1. Create an epoll object
  2. Tell the epoll object to monitor specific events on specific sockets
  3. Ask the epoll object which sockets may have had the specified event since the last query
  4. Perform some action on those sockets
  5. Tell the epoll object to modify the list of sockets and/or events to monitor
  6. Repeat steps 3 through 5 until finished
  7. Destroy the epoll object
 1  import socket, select
 2   
3 EOL1 = b\n\n 4 EOL2 = b\n\r\n 5 response = bHTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n 6 response += bContent-Type: text/plain\r\nContent-Length: 13\r\n\r\n 7 response += bHello, 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)
   #Since sockets are blocking by default, this is necessary to use non-blocking (asynchronous) mode.
13 serversocket.setblocking(0) 14 15 epoll = select.epoll() 16 epoll.register(serversocket.fileno(), select.EPOLLIN) 17 18 try: 19 connections = {}; requests = {}; responses = {} 20 while True: 21 events = epoll.poll(1) 22 for fileno, event in events: 23 if fileno == serversocket.fileno():
          #Events are returned as a sequence of (fileno, event code) tuples. fileno is a synonym for file descriptor           and is always an integer.
24 connection, address = serversocket.accept() 25 connection.setblocking(0) 26 epoll.register(connection.fileno(), select.EPOLLIN) 27 connections[connection.fileno()] = connection 28 requests[connection.fileno()] = b‘‘ 29 responses[connection.fileno()] = response 30 elif event & select.EPOLLIN: 31 requests[fileno] += connections[fileno].recv(1024) 32 if EOL1 in requests[fileno] or EOL2 in requests[fileno]: 33 epoll.modify(fileno, select.EPOLLOUT) 34 print(-*40 + \n + requests[fileno].decode()[:-2]) 35 elif event & select.EPOLLOUT: 36 byteswritten = connections[fileno].send(responses[fileno]) 37 responses[fileno] = responses[fileno][byteswritten:] 38 if len(responses[fileno]) == 0: 39 epoll.modify(fileno, 0) 40 connections[fileno].shutdown(socket.SHUT_RDWR) 41 elif event & select.EPOLLHUP: 42 epoll.unregister(fileno) 43 connections[fileno].close() 44 del connections[fileno] 45 finally: 46 epoll.unregister(serversocket.fileno()) 47 epoll.close() 48 serversocket.close()

epoll有两种工作模式:LT(level-triggered,水平触发),ET(edge-triggered,边缘触发)。默认情况下,epoll采用LT模式工作,这时可以处理阻塞和非阻塞套接字。ET模式只支持非阻塞套接字。ET模式与LT模式的区别在于,当一个新的事件到来时,ET模式下当然可以从epoll_wait调用中获取到这个事件,可是如果这次没有把这个事件对应的套接字缓冲区处理完,在这个套接字没有新的事件再次到来时,在ET模式下是无法再次从epoll_wait调用中获取这个事件的;而LT模式则相反,只要一个事件对应的套接字缓冲区还有数据,就总能从epoll_wait中获取这个事件。

1  import socket, select
 2
 3  EOL1 = b\n\n
 4  EOL2 = b\n\r\n
 5  response  = bHTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n
 6  response += bContent-Type: text/plain\r\nContent-Length: 13\r\n\r\n
 7  response += bHello, 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  serversocket.setblocking(0)
14
15  epoll = select.epoll()
16  epoll.register(serversocket.fileno(), select.EPOLLIN | select.EPOLLET)
17
18  try:
19     connections = {}; requests = {}; responses = {}
20     while True:
21        events = epoll.poll(1)
22        for fileno, event in events:
23           if fileno == serversocket.fileno():
24              try:
25                 while True:
26                    connection, address = serversocket.accept()
27                    connection.setblocking(0)
28                    epoll.register(connection.fileno(), select.EPOLLIN | select.EPOLLET)
29                    connections[connection.fileno()] = connection
30                    requests[connection.fileno()] = b‘‘
31                    responses[connection.fileno()] = response
32              except socket.error:
33                 pass
34           elif event & select.EPOLLIN:
35              try:
36                 while True:
37                    requests[fileno] += connections[fileno].recv(1024)
38              except socket.error:
39                 pass
40              if EOL1 in requests[fileno] or EOL2 in requests[fileno]:
41                 epoll.modify(fileno, select.EPOLLOUT | select.EPOLLET)
42                 print(-*40 + \n + requests[fileno].decode()[:-2])
43           elif event & select.EPOLLOUT:
44              try:
45                 while len(responses[fileno]) > 0:
46                    byteswritten = connections[fileno].send(responses[fileno])
47                    responses[fileno] = responses[fileno][byteswritten:]
48              except socket.error:
49                 pass
50              if len(responses[fileno]) == 0:
51                 epoll.modify(fileno, select.EPOLLET)
52                 connections[fileno].shutdown(socket.SHUT_RDWR)
53           elif event & select.EPOLLHUP:
54              epoll.unregister(fileno)
55              connections[fileno].close()
56              del connections[fileno]
57  finally:
58     epoll.unregister(serversocket.fileno())
59     epoll.close()
60     serversocket.close()

Performance Considerations

Listen Backlog Queue Size

In Examples 1-4, line 12 has shown a call to the serversocket.listen() method. The parameter for this method is the listen backlog queue size. It tells the operating system how many TCP/IP connections to accept and place on the backlog queue before they are accepted by the Python program. Each time the Python program calls accept() on the server socket, one of the connections is removed from the queue and that slot can be used for another incoming connection. If the queue is full, new incoming connections are silently ignored causing unnecessary delays on the client side of the network connection. A production server usually handles tens or hundreds of simultaneous connections, so a value of 1 will usually be inadequate. For example, when using abto perform load testing against these sample programs with 100 concurrent HTTP 1.0 clients, any backlog value less than 50 would often produce performance degradation.

相关:http://www.linuxidc.com/Linux/2013-02/79858.htm

TCP Options

The TCP_CORK option can be used to "bottle up" messages until they are ready to send. This option, illustrated in lines 34 and 40 of Example 5, might be a good option to use for an HTTP server using HTTP/1.1 pipelining.

相关:http://blog.sina.com.cn/s/blog_7303a1dc0101gcld.html

   http://blog.csdn.net/dog250/article/details/5941637

On the other hand, the TCP_NODELAY option can be used to tell the operating system that any data passed to socket.send() should immediately be sent to the client without being buffered by the operating system. This option, illustrated in line 14 of Example 6, might be a good option to use for an SSH client or other "real-time" application.

Python-Epoll

标签:des   style   blog   http   color   os   io   ar   for   

原文地址:http://www.cnblogs.com/zxpgo/p/3956755.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!