首页 > 代码库 > python之epoll服务器源码分析

python之epoll服务器源码分析

#!/usr/bin/env python# -*- coding: utf8 -*-import socket, selectEOL1 = b/r/nEOL2 = b/r/n/r/n# 拼接成的responseresponse = bHTTP/1.0 200 OK/r/nDate: Mon, 1 Jan 1996 01:01:01 GMT/r/nresponse += bContent-Type: text/plain/r/nContent-Length: 13/r/n/r/nresponse += bHello, world!# 创建一个服务端的socket,来监听是否有请求过来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)  # 设置时非阻塞print(serversocket.fileno())epoll = select.epoll()  # 准备设计一个IO多路复用epoll.register(serversocket.fileno(), select.EPOLLIN)  # 把上面的serversocket的fileno() 和 监听准备读信号 注册到epoll中去try:    # 设置三个空字典    connections = {}    requests = {}    responses = {}    while True:        # 查看epoll是否有信号有的话,就放在events中        events = epoll.poll(1)        # 循环events,分别拿到 文件描述号 和对应的事件        for fileno, event in events:            # 如果当前的文件描述号是serversocket,那么说明有新的连接            if fileno == serversocket.fileno():                # 所以就得接受,创建了 连接,拿到了对方的IP地址                connection, address = serversocket.accept()                # connection就是客户端连接过来建立的socket,设置为非阻塞                connection.setblocking(0)                # 客户端建立的socket也注册到select模块的IO多路复用中去                epoll.register(connection.fileno(), select.EPOLLIN)                # 以Connection的文件描述号 作为键 socket作为值保存在connections中                connections[connection.fileno()] = connection                # 同时在requests和responses字典中,                # requests中 以connection.fileno() 作为键 以请求的内容作为值                # responses中 以connection.fileno() 作为键 以相应的内容作为值,这个我们返回的是固定的,仅仅返回hello world                requests[connection.fileno()] = b‘‘                responses[connection.fileno()] = response            # 如果请求的数据不是socketserver,那肯定是客户端的,判断是否是准备读的信号            elif event & select.EPOLLIN:                # 立马来开始读取数据,加到requests对象套接字的内容中去                requests[fileno] += connections[fileno].recv(1024)                # 判断换行 和 两个换行是否在接收过来的数据中                if EOL1 in requests[fileno] or EOL2 in requests[fileno]:                    # 如果是的话,就将这个套接字的监听更新为准备写                    epoll.modify(fileno, select.EPOLLOUT)                    # 打印40个-,然后换行,加上请求的内容                    print(- * 40 + /n + requests[fileno].decode()[:-2])            # 如果请求的数据不是socketserver,那肯定是客户端的,判断是否是准备写的信号            elif event & select.EPOLLOUT:                # 立马来开始读取数据,就将response的对应的套接字号对应的值拿出来,其实就是hello world,O(∩_∩)O哈哈~                # 并统计发送了多少个字节                byteswritten = connections[fileno].send(responses[fileno])                # 更新response对应套接字内容为剩下的内容                responses[fileno] = responses[fileno][byteswritten:]                # 如果内容发完了,剩下的长度就是0,如果长度是0                if len(responses[fileno]) == 0:                    # 就修改select,不监听该套接字的内容,其就变成了EPOLLHUP                    epoll.modify(fileno, 0)                    # 然后关闭该socket的管道                    connections[fileno].shutdown(socket.SHUT_RDWR)            elif event & select.EPOLLHUP:                # 如果不监听该套接字的内容,就将其注销掉                epoll.unregister(fileno)                # 关闭该套接字                connections[fileno].close()                # 从连接中删除该文件描述符                del connections[fileno]finally:    # 最后关闭serversocket服务器套接字    epoll.unregister(serversocket.fileno())    # 关闭epoll    epoll.close()    # 套接字关闭    serversocket.close()

 

python之epoll服务器源码分析