[关闭]
@wsd1 2017-01-19T08:01:20.000000Z 字数 2087 阅读 1303

【专题7】skynet中simpleWeb分析

skynet


参考文档

http://cloudwu.github.io/lua53doc/manual.html#6.4.1

https://github.com/cloudwu/skynet/wiki

背景

SimpleWeb是skynet的一个web应用demo。虽然短小,但是不简单,充分利用了lua动态语言的特征。对其进行分析,有助于提升lua编程思路。

主文件 simpleweb.lua

源代码80多行,分为 建立socket、listen代码 和 agent处理连接的代码,其中逻辑很清晰简单,主要看agent的部分:

skynet.start(function()
    skynet.dispatch("lua", function (_,_,id)
        socket.start(id)
        -- limit request body size to 8192 (you can pass nil to unlimit)

        local code, url, method, header, body = 
        httpd.read_request(sockethelper.readfunc(id), 8192)  --<< 阻塞接收,这里着重分析

        if code then
            if code ~= 200 then
                response(id, code)  --<< 这里主动输出,比较简单,不分析了
            else
                ...
                response(id, code, table.concat(tmp,"\n")) 
            end
        else
            ...
        end
        socket.close(id)
    end)
end)

sockethelper.readfunc(id) 其实很简单,这个将socket id作为参数,返回一个堵塞读取函数,类似于 readbytes(n)。

httpd.read_request(sockethelper.readfunc(id), 8192)

httpd.read_request 函数的原型在 lualib/http/httpd.lua中:

function httpd.read_request(...)
    local ok, code, url, method, header, body = pcall(readall, ...)
    if ok then
        return code, url, method, header, body
    else
        return nil, code
    end
end

而,同一个文件中,readall 如下定义:

local function readall(readbytes, bodylimit)
    local tmpline = {}
    local body = internal.recvheader(readbytes, tmpline, "")
    --这个函数就不进入分析了,这里是一个阻塞调用,通过readbytes函数读取数据,通过tmpline输出各个头部字段,由于可能读出过多的数据,排除头部部分后,剩余返回 给 body
    if not body then
        return 413  -- Request Entity Too Large
    end
    local request = assert(tmpline[1])
    local method, url, httpver = request:match "^(%a+)%s+(.-)%s+HTTP/([%d%.]+)$"
    assert(method and url and httpver)
    httpver = assert(tonumber(httpver))
    if httpver < 1.0 or httpver > 1.1 then
        return 505  -- HTTP Version not supported
    end
    --分解头部
    local header = internal.parseheader(tmpline,2,{})
    if not header then
        return 400  -- Bad request
    end
    local length = header["content-length"]
    if length then
        length = tonumber(length)
    end
    local mode = header["transfer-encoding"]
    if mode then
        if mode ~= "identity" and mode ~= "chunked" then
            return 501  -- Not Implemented
        end
    end

    if mode == "chunked" then
        body, header = internal.recvchunkedbody(readbytes, bodylimit, header, body)
        if not body then
            return 413
        end
    else
        -- identity mode
        if length then
            if bodylimit and length > bodylimit then
                return 413
            end
            if #body >= length then
                body = body:sub(1,length)
            else
                local padding = readbytes(length - #body)
                body = body .. padding
            end
        end
    end

    return 200, url, method, header, body
end
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注