研究rfile如何解析消息头和消息正文,并返回结果的过程。

rfile和wfile 根据 client_socket 由HttpProtocal 类的setup函数生成。

生成流程,如下代码:

def server():

client_socket = sock.accept()
pool.spawn_n(serv.process_request,client_socket)

def process_request(self,sock_params):

sock,address = sock_params
proto.__init__(sock,address,self)

class BaseRequestHandler:

def __init__(self,request,client_address,server):
    self.request = request
    self.client_address = client_address
    self.server = server

class HttpProtocol

def setup(self):
    conn = self.connection = self.request
    try:
        self.rfile = conn.makefile('rb',self.rbufsize)
        self.wfile = conn.makefile('wb',self.wbufsize)
    except (AttributeError,NotImplementedError):
        if hasattr(conn,'send') and hasattr(conn,'recv'):
            # it's an SSL.Connection
            self.rfile = socket._fileobject(conn,"rb",self.rbufsize)
            self.wfile = socket._fileobject(conn,"wb",self.wbufsize)

其中sock 由 eventlet 所重写的listen函数生成,基于eventlet.greenio模块的GreenSocket 类。

self.connection调用makefile创建一个与该套接字相关连的文件

通过调试 self.rfile.readline函数(位于socket模块),可以判断python对于http的协议主要是根据数据中的/r/n分隔符,区分开消息头和消息正文,且消息正文长度由content-length消息头决定.

客户端发送数据:

POST /oauth/access_token HTTP/1.1
User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7
NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Host: localhost
Accept: /
Content-Length: 51
Content-Type: application/x-www-form-urlencoded

函数入下:

def readline(self,size=-1):
    buf = self._rbuf
    buf.seek(0,2)  # seek end
    if buf.tell() > 0:
        # check if we already have it in our buffer
        buf.seek(0)
        bline = buf.readline(size)
        if bline.endswith('\n') or len(bline) == size:
            self._rbuf = StringIO()
            self._rbuf.write(buf.read())
            return bline
        del bline
    if size < 0:
        # Read until \n or EOF,whichever comes first
        if self._rbufsize <= 1:
            # Speed up unbuffered case
            buf.seek(0)
            buffers = [buf.read()]
            self._rbuf = StringIO()  
            data = None
            recv = self._sock.recv
            while True:
                try:
                    while data != "\n":
                        data = recv(1)
                        if not data:
                            break
                        buffers.append(data)
                except error,e:
                    # The try..except to catch EINTR was moved outside the
                    # recv loop to avoid the per byte overhead.
                    if _exception_was_EINTR(e):
                        continue
                    raise
                break
            return "".join(buffers)


        buf.seek(0,2)  # seek end
        self._rbuf = StringIO()  # reset _rbuf.  we consume it via buf.
        while True:
            try:
                data = self._sock.recv(self._rbufsize)
            except error,e:
                if _exception_was_EINTR(e):
                    continue
                raise
            if not data:
                break
            nl = data.find('\n')
            if nl >= 0:
                nl += 1
                buf.write(data[:nl])
                self._rbuf.write(data[nl:])
                del data
                break
            buf.write(data)
        return buf.getvalue()
    else:
        # Read until size bytes or \n or EOF seen,whichever comes first
        buf.seek(0,2)  # seek end
        buf_len = buf.tell()
        if buf_len >= size:
            buf.seek(0)
            rv = buf.read(size)
            self._rbuf = StringIO()
            self._rbuf.write(buf.read())
            return rv
        self._rbuf = StringIO()  # reset _rbuf.  we consume it via buf.
        while True:
            try:
                data = self._sock.recv(self._rbufsize)
            except error,e:
                if _exception_was_EINTR(e):
                    continue
                raise
            if not data:
                break
            left = size - buf_len
            # did we just receive a newline?
            nl = data.find('\n',left)
            if nl >= 0:
                nl += 1
                # save the excess data to _rbuf
                self._rbuf.write(data[nl:])
                if buf_len:
                    buf.write(data[:nl])
                    break
                else:
                    # Shortcut.  Avoid data copy through buf when
                    # returning
                    # a substring of our first recv().
                    return data[:nl]
            n = len(data)
            if n == size and not buf_len:
                # Shortcut.  Avoid data copy through buf when
                # returning exactly all of our first recv().
                return data
            if n >= left:
                buf.write(data[:left])
                self._rbuf.write(data[left:])
                break
            buf.write(data)
            buf_len += n
            #assert buf_len == buf.tell()
        return buf.getvalue()

注:如果消息正文transfer-encoding:chunked 方式传输,则不实用上述解析方式。

最终消息头数据存储在self.environ变量中,消息正文由env[‘eventlet.input’]保存。

其中env[‘eventlet.input’] 的创建方式如下

env[‘wsgi.input’] =Input(self.rfile,length,\
wfile=wfile,wfile_line=wfile_line,chunked_input=chunked)

若self.rfile 所读取的数据为”,则表明收到客户端答复,释放网络资源。

openstack swift和wsgi源码分析2 eventlet HTTP协议解析过程中rfile工作原理的更多相关文章

  1. HTML5实现直播间评论滚动效果的代码

    这篇文章主要介绍了HTML5实现直播间评论滚动效果的代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. canvas中普通动效与粒子动效的实现代码示例

    canvas用于在网页上绘制图像、动画,可以将其理解为画布,在这个画布上构建想要的效果。本文详细的介绍了粒子特效,和普通动效进行对比,非常具有实用价值,需要的朋友可以参考下

  3. H5混合开发app如何升级的方法

    本篇文章主要介绍了H5混合开发app如何升级的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  4. canvas学习和滤镜实现代码

    这篇文章主要介绍了canvas学习和滤镜实现代码,利用 canvas,前端人员可以很轻松地、进行图像处理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. 前端监听websocket消息并实时弹出(实例代码)

    这篇文章主要介绍了前端监听websocket消息并实时弹出,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. localStorage的过期时间设置的方法详解

    这篇文章主要介绍了localStorage的过期时间设置的方法详解的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  7. 详解HTML5 data-* 自定义属性

    这篇文章主要介绍了详解HTML5 data-* 自定义属性的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  8. HTML5之消息通知的使用(Web Notification)

    通知可以说是web中比较常见且重要的功能,私信、在线提问、或者一些在线即时通讯工具我们总是希望第一时间知道对方有了新的反馈。本篇文章主要介绍了HTML5之消息通知的使用(Web Notification),感兴趣的小伙伴们可以参考一下

  9. HTML5中的Web Notification桌面通知功能的实现方法

    这篇文章主要介绍了HTML5中的Web Notification桌面通知功能的实现方法,需要的朋友可以参考下

  10. HTML5仿微信聊天界面、微信朋友圈实例代码

    小编最近开发一个基于html5开发的一个微信聊天前端界面,功能很全面,下面小编给大家分享实例代码,需要的朋友参考下

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部