上一篇文章我们提到了关于epoll模型的封装, 在这一节我们将在httpserver中使用我们封装好的selecploop和epollloop类

在httpserver主要有两个类,第一个是httprequest类

这个类主要是封装请求内容的合集,使用的这个类将request中的信息全部封装好,然后在代码中直接传递request类的实例就好了,比如说,要获取请求的header直接就是request.header()

就可以返回头部分的信息了.话不多说,直接贴代码,这次代码同样没有人任何的注释,我会用文字详细的解释每个方法的用途. 下面是httprequest类的代码:

class HttpRequest(object):
    def __init__(self,header,body):
        (self.request_method,
            self.request_path,self.request_version)=header.splitlines()[0].rstrip('rn').split()
        self.header = header
        self.body =body
        self.header_map= {}
        try:
            for lines in self.header.splitlines():
                print lines
                if lines.find(":")!=-1:
                    index  = lines.index(':')
                    (key,value) = lines[:index],lines[index:]
                    self.header_map[key] = value
        except:
            print 'faile generator header map'
            pass
    def method(self):
        return self.request_method
    def path(self):
        return self.request_path
    def version(self):
        return self.request_version
    def body(self):
        return self.body
    def header(self):
        return self.header
    def get(self,name):
        if self.header_map[name]:
            return self.header_map[name]

我们在这个类里面把一个请求的内容全部分割好,当把这个类的实例传到其他的地方的时候,就可以直接是使用相应的方法获取我们想要的值.

下面来说说最关键的httpserver类

这个类似httpserver服务器的核心部分的代码,主要的功能是:

  1. init()初始化socket套接字,同时设置一些相关的socket的配置,比如说SEND_BUF_SIZE ,RECV_BUF_SIZE ,socket.SO_REUSEADDR等socket属性

  2. add_app()的主要功能是把我们下一节的application传入我们的httpserver类.我们后面具体在详细讲

  3. start_response(),finish_response(),这两个函数会被handle_one_request()调用,主要的功能就是把应用层返回到的结果组装成一个完整的http response ,然后使用sendall()函数返回给客户端
  4. run()是httpserver的启动函数,首先判断程序运行的平台选择对应的io复用模型,其次实例epoll或者select模型,最后调用selectloop.start()方法开始监听连接主循环.

下面呢就是精简版的Httpserver的代码:

class HttpServer(object):
    """strt httpserver"""
    def __init__(self, (host,port),timeout =10,request_size=10):
        self.clients = 0
        self.clientmap={}
        self.outputs = []
        self.timeout = timeout
        SEND_BUF_SIZE = 4096
        RECV_BUF_SIZE = 1024
        self.server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.server.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
        self.server.bind((host,port))
        self.server.listen(request_size)
    def add_app(self,application):
        self.application = application
    def start_response(self,status,response_headers,exc_info = None):
        self.header_set = (status,response_headers)
    def finish_response(self,result):
        try:

            status,response_headers =self.header_set
            print response_headers
            response ='HTTP/1.1 {status}\r\n'.format(status = status)
            if response_headers != []:
                for header in response_headers:
                    response += '{0}: {1}\r\n'.format(*header)
            else:response+='\r\n'
            response +='\r\n'            
            response += result
            return response
        except:
            print '*****error in finish_response****** '
            return 'error  in finish_response'

    def parse_request(self,text):
        try:
            (header,body) = text.split('\r\n\r\n')
        except:
            header =text
            body =''
        return HttpRequest(header,body)

    def handle_one_request(self,data):

        print (''.join(
            '{line}'.format(line= line)
            for line in data.splitlines()
            ))

        result = self.application(self.parse_request(data))
        print 'there is result ....'
        self.start_response(result[0],result[1])
        return  self.finish_response(result[2])

    def run(self):
        print '>>>>>>>>>>>>>start run server <<<<<<<<<<<<<<<'
        try:
            sysstr = platform.system()
        except:
            sysstr = "Other System"
        if sysstr== "Windows":
            print 'using SelectLoop on Windows'

            loop = SelectLoop(self.server,self.timeout,self.handle_one_request)
            loop.start()
        elif sysstr=="Linux":
            print 'using EPollLoop on Linux'
            loop =  EPollLoop(self.server,self.timeout,self.handle_one_request)
            loop.start()

进入主循环之后,epoll或者select就不断的监听新进入的连接,它们都维持一个文件描述符的队列,所有的socket连接的文件描述符都在里面.

当一个新的连接来临时,epoll通过epoll_ctl()来注册一个文件描述符 到监听的队列,同时分配一个回调函数(主要的功能是等该连接准备就绪时把该连接加入到就绪表里面),当有一个或者多个连接准备就绪时,就开始进入业务处理遍历 ,我们将就绪表里面的对象全部遍历一遍,接受里面的数据或者是发送数据.同时把数据通过回调函数来处理,

可以看到我们这里的回调函数就是 handle_one_request() ,好了收到的数据已经到了 我们的回调函数handle_one_request() 里面了,让我们看看handle_one_request() 函数主要是做什么的: 首先handle_one_request() 将接收到的数据通过parse_request()函数来处理,返回一个httprequest类的实例,然后把这个实例传入到application里面

self.application(self.parse_request(data))这是有一个很关键的代码

到这里我们的httpserver算是完成了,接下来要把舞台交给我们应用层了,这个application有点WSGI的感觉(Web Server Gateway Interface) 图片名称

下一篇将进入应用层来讨论构建应用框架的内容



Copyright © 2019 outshineamaze.
All rights reserved.

results matching ""

    No results matching ""