skynet源码分析(15)--skynet中http之sockethelper

作者:[email protected],转载请注明作者

这个sockethelper可讲的东西不多,它提供一个connect函数给外部使用,这个connect能够支持阻塞和非阻塞连接两种方式。

另外提供readfunc和writefunc两个函数,这两个函数将fd参数隐藏起来,形成闭包,再返回闭包。

local socket = require "skynet.socket"
local skynet = require "skynet"

local readbytes = socket.read
local writebytes = socket.write

local sockethelper = {}
--不支持tostring
local socket_error = setmetatable({} , { __tostring = function() return "[Socket Error]" end })

sockethelper.socket_error = socket_error

--预读字符串str
local function preread(fd, str)
    return function (sz)
        if str then --预读字符串不为空
            if sz == #str or sz == nil then
                local ret = str
                str = nil
                return ret
            else --数据不匹配
                if sz < #str then --读到的数据长度不够
                    local ret = str:sub(1,sz)
                    str = str:sub(sz + 1)
                    return ret
                else --读到的数据长度够长了
                    sz = sz - #str
                    local ret = readbytes(fd, sz) --再读剩下想要读的内容
                    if ret then
                        return str .. ret
                    else
                        error(socket_error)
                    end
                end
            end
        else --预读为空
            local ret = readbytes(fd, sz)
            if ret then
                return ret
            else
                error(socket_error)
            end
        end
    end
end

--功能就是从fd上读数据
-- 返回的是闭包
-- 这个闭包把fd给隐藏了
function sockethelper.readfunc(fd, pre)
    if pre then
        return preread(fd, pre)
    end
    return function (sz)
        local ret = readbytes(fd, sz)
        if ret then
            return ret
        else
            error(socket_error)
        end
    end
end

sockethelper.readall = socket.readall

--往fd上写数据
-- 返回的也是闭包
-- 闭包把fd隐藏了
function sockethelper.writefunc(fd)
    return function(content)
        local ok = writebytes(fd, content)
        if not ok then
            error(socket_error)
        end
    end
end

--连接到服务器
--阻塞和非阻塞都支持
function sockethelper.connect(host, port, timeout)
    local fd
    if timeout then --非阻塞,使用协程实现
        local drop_fd
        local co = coroutine.running()
        -- asynchronous connect
        skynet.fork(function()
            fd = socket.open(host, port)
            if drop_fd then
                -- sockethelper.connect already return, and raise socket_error
                socket.close(fd)
            else
                -- socket.open before sleep, wakeup.
                skynet.wakeup(co)
            end
        end)
        skynet.sleep(timeout) --这里也是协程实现的,sleep的时候让出cpu
        if not fd then
            -- not connect yet
            drop_fd = true
        end
    else
        -- block connect
        fd = socket.open(host, port)
    end
    if fd then
        return fd
    end
    error(socket_error)
end

function sockethelper.close(fd)
    socket.close(fd)
end

function sockethelper.shutdown(fd)
    socket.shutdown(fd)
end

return sockethelper

你可能感兴趣的:(skynet源码分析(15)--skynet中http之sockethelper)