@wsd1
2017-01-19T08:01:20.000000Z
字数 2087
阅读 1636
skynet
http://cloudwu.github.io/lua53doc/manual.html#6.4.1
https://github.com/cloudwu/skynet/wiki
SimpleWeb是skynet的一个web应用demo。虽然短小,但是不简单,充分利用了lua动态语言的特征。对其进行分析,有助于提升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