python 网络编程学习 epoll多路复用

捋一下阻塞非阻塞,同步异步概念

阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态

  • 阻塞:当前进程调用结果未返回,进程等待
  • 非阻塞:当前进程调用结果未返回,进程不等待

同步和异步关注的是消息通信机制

  • 异步:主动请求数据后便可以继续处理其他任务,等待IO操作完毕的通知(一般有调用特殊接口)
  • 同步:指主动请求并等待IO操作完毕,当数据就绪后等待读写完毕再返回

构建一个epoll多路复用的server所需的基本步骤

  1. 先构造一个套接字服务器,绑定到指定ip端口。
  2. 设置套接字为非阻塞模式 setblocking(0)。
  3. 设定TCP_NODELAY选项,可以让服务器无缓冲就可以直接交换数据。
  4. 创建一个select.epoll()实例,把套接字的文件描述符传递给epoll实例,以便监控
  5. run方法监听套接字事件,EPOLLIN(读事件), EPOLLOUT(写事件),EPOLLHUP(异常中断)

套接字的响应设置为SERVER_RES

import socket                                                                                                                                                                      
import select                                                                       
                                                                                 
EOL1 = b'\n\n'                                                                   
EOL2 = b'\n\r\n'                                                                 
SERVER_RES = b"""HTTP/1.1 200 OK\r\nDate: Mon, 1 Apr 2016 23:00:01               
GMT\r\nContent-Type: text/plain\r\nContent-Length: 25\r\n\r\n                    
Hello from epoll server!"""                                                      
                                                                                 
                                                                                 
class EpollServer(object):                                                       
    def __init__(self, host='localhost', port=9999):                             
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)            
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)          
        self.sock.bind((host, port))                                             
        self.sock.listen(1)                                                      
        self.sock.setblocking(0)                                                 
        self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)          
        print "Started epoll server(%s:%s)..." % (host, port)                    
        self.epoll = select.epoll()                                              
        self.epoll.register(self.sock.fileno(), select.EPOLLIN)                  
                                                                                 
    def run(self):                                                               
        try:                                                                     
            connections = {}                                                     
            requests = {}                                                        
            responses = {}                                                       
            while True:                                                          
                events = self.epoll.poll(1)                                      
                for fileno, event in events:                                     
                    print fileno, event, "......"                                
                    if fileno == self.sock.fileno():                             
                        connection, address = self.sock.accept()                 
                        connection.setblocking(0)                                
                        self.epoll.register(connection.fileno(), select.EPOLLIN) 
                        connections[connection.fileno()] = connection            
                        requests[connection.fileno()] = b''                      
                        responses[connection.fileno()] = SERVER_RES              
                    elif event & select.EPOLLIN:                                 
                        requests[fileno] += connections[fileno].recv(1024)       
                        if EOL1 in requests[fileno] or EOL2 in requests[fileno]: 
                            self.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:                          
                            self.epoll.modify(fileno, 0)                         
                            connections[fileno].shutdown(socket.SHUT_RDWR)       
                    elif event & select.EPOLLHUP:                                
                        self.epoll.unregister(fileno)                            
                        connections[fileno].close()
                        del connections[fileno]                                  
        finally:                                                                 
            self.epoll.unregister(self.sock.fileno())                            
            self.epoll.close()                                                   
            self.sock.close()                                                    
                                                                                 
                                                                                 
if __name__ == '__main__':                                                       
    server = EpollServer('192.168.199.110', 6789)                                
    server.run()

用浏览器访问这个web服务的时候, 正常返回服务端发送的

Hello from epoll server!

你可能感兴趣的:(python,网络编程学习)