python之epoll服务器源码分析

#!/usr/bin/env python
# -*- coding: utf8 -*-

import socket, select

EOL1 = b‘/r/n‘
EOL2 = b‘/r/n/r/n‘

# 拼接成的response
response = b‘HTTP/1.0 200 OK/r/nDate: Mon, 1 Jan 1996 01:01:01 GMT/r/n‘
response += b‘Content-Type: text/plain/r/nContent-Length: 13/r/n/r/n‘
response += b‘Hello, 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()
时间: 2024-12-13 13:10:48

python之epoll服务器源码分析的相关文章

CSAPP Tiny web 服务器源码分析及搭建运行

1. Web基础 web客户端和服务器之间的交互使用的是一个基于文本的应用级协议HTTP(超文本传输协议).一个web客户端(即浏览器)打开一个到服务器的因特网连接,并且请求某些内容.服务器响应所请求的内容,然后关闭连接.浏览器读取这些内容,并把它显示在屏幕上. 对于web客户端和服务器而言,内容是与一个MIME类型相关的字节序列.常见的MIME类型: MIME类型 描述 text/html HTML页面 text/plain 无格式文本 image/gif GIF格式编码的二进制图像 imag

Python字典嵌套(源码分析/自定义)

今天在写监控脚本的时候遇到一个问题,就是我执行每一个监控模块(脚本)的时候,例如CPU.内存.磁盘脚本,都会返回一个字典格式的数据,但是我需要将这三个字典,组合成一个大字典,然后通过requests模块发送给api接口,so,我就在网上找了一些方法,然后总结,写成这编博文. 1.首先定义三个字典(不需要考虑字典的具体内容) >>> cpu_dict = {'cpu_count':8,'cpu_ratio':3.5} >>> memory_dict = {'memory_

HTTP服务器的本质:tinyhttpd源码分析及拓展

已经有一个月没有更新博客了,一方面是因为平时太忙了,另一方面是想积攒一些干货进行分享.最近主要是做了一些开源项目的源码分析工作,有c项目也有python项目,想提升一下内功,今天分享一下tinyhttpd源码分析的成果.tinyhttpd是一个非常轻量型的http服务器,c代码500行左右,可以帮助我们了解http服务器运行的实质.在分析之前,我们先说一下http报文. 一.http请求 http请求由三部分组成,分别是:起始行.消息报头.请求正文 Request Line<CRLF> Hea

Epoll详解及源码分析

Author:Echo Chen(陈斌) Email:[email protected] Blog:Blog.csdn.net/chen19870707 Date:Jan.7th, 2015 1.什么是epoll epoll是当前在Linux下开发大规模并发网络程序的热门人选,epoll 在Linux2.6内核中正式引入,和select相似,都是I/O多路复用(IO multiplexing)技术,按照man手册的说法:是为处理大批量句柄而作了改进的poll. Linux下有以下几个经典的服务器

K-近邻算法的Python实现 : 源码分析

网上介绍K-近邻算法的例子很多,其Python实现版本基本都是来自于机器学习的入门书籍<机器学习实战>,虽然K-近邻算法本身很简单,但很多初学者对其Python版本的源代码理解不够,所以本文将对其源代码进行分析. 什么是K-近邻算法? 简单的说,K-近邻算法采用不同特征值之间的距离方法进行分类.所以它是一个分类算法. 优点:无数据输入假定,对异常值不敏感 缺点:复杂度高 好了,直接先上代码,等会在分析:(这份代码来自<机器学习实战>) def classify0(inx, data

Python之美[从菜鸟到高手]--浅拷贝、深拷贝完全解读(copy源码分析)

可悲的我一直以为copy模块是用C写的,有时候需要深入了解deepcopy,文档描述的实在太简单,还是不知所云. 比如说最近看sqlmap源码中AttribDict的_deepcopy__有些疑惑, def __deepcopy__(self, memo): retVal = self.__class__() memo[id(self)] = retVal for attr in dir(self): if not attr.startswith('_'): value = getattr(se

【Zookeeper】源码分析之服务器(二)

一.前言 前面阐述了服务器的总体框架,下面来分析服务器的所有父类ZooKeeperServer. 二.ZooKeeperServer源码分析 2.1 类的继承关系 public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {} 说明:ZooKeeperServer是ZooKeeper中所有服务器的父类,其实现了Session.Expirer和ServerStats.Provider接口,Session

zg手册 之 python2.7.7源码分析(5)-- python的作用域和名空间

在 python 中, module,作用域,名空间这几个概念与虚拟机的运行机制有紧密的联系, 这里先了解 module,作用域,和名空间,为后面分析虚拟机的运行做准备. module 在python中一个文件对应是一个module,每个py文件被导入后都对应一个module对象. 这个对象包含有一个dict对象,保存着本py文件中对应的变量和函数的引用, 也保存从其他python文件(module)导入的变量或函数的引用. 名空间和作用域 python 有三个独立的名空间, local, gl

【Zookeeper】源码分析之服务器(四)之FollowerZooKeeperServer

一.前言 前面分析了LeaderZooKeeperServer,接着分析FollowerZooKeeperServer. 二.FollowerZooKeeperServer源码分析 2.1 类的继承关系 public class FollowerZooKeeperServer extends LearnerZooKeeperServer {} 说明:其继承LearnerZooKeeperServer抽象类,角色为Follower.其请求处理链为FollowerRequestProcessor -