Lua Copas, помогите прояснить, как обращаться с несколькими пользователями - PullRequest
1 голос
/ 01 июня 2011

Я немного сбит с толку и думаю, что это будет простой ответ, но мои поиски мне не очень помогают :( Я хочу иметь возможность отправлять skt: отправлять куда угодно. Я мог бы отправить его в функцию OutToUser какпараметр, но у меня будет много разных мест, в которых я захочу это сделать, и чувствую, что это будет слишком грязно. Я пытался сохранить что-то вроде Server.connections [key] = skt, где key это host и portно не могу понять, как получить хост и порт позже, когда мне это понадобится.

Есть ли хорошие решения?

edit Я понимаю, что это проблема области, ноне вижу хорошего решения, так как я новичок в lua.

require "copas"
Server = {}
function Server:new()
    local object = {}
    setmetatable(object, { __index = Server })
    return object
end

function Server:init()
    function handler(skt, host, port)
        while true do
            data = skt:receive()
            if data == "quit" then
                -- isn't going to work
                OutToUser(data)

                -- this would work fine of course
                -- skt:send(data .. "\r\n")
            end
        end
    end

    server = socket.bind("*", 49796)
    copas.addserver(server, 
        function(c) return handler(copas.wrap(c), c:getpeername()) end
    )
    copas.loop()
end

function OutToUser(data)
    skt:send(data .. "\r\n")
end

server = Server:new()
server:init()

Ответы [ 2 ]

1 голос
/ 01 июня 2011

Вы можете определить OutToUser в области действия обработчика:

function Server:init()
    local function handler(skt, host, port)

        --make the function local to here
        local function OutToUser(data)
            --references the skt variable in the enclosing scope
            --(the handler function)
            skt:send(data .. "\r\n")
        end

        while true do
            data = skt:receive()
            if data == "quit" then
                OutToUser(data)
            end
        end
    end

    local server = socket.bind("*", 49796)
    copas.addserver(server, 
        function(c) return handler(copas.wrap(c), c:getpeername()) end
    )
    copas.loop()
end

Функции всегда могут ссылаться на переменные в своей области (аргументы функций и переменные, объявленные с local), даже после того, как они вышли из этой области - вы можете использовать это как альтернативное решение, где вы заключаете переменные, которые вы хотите, чтобы функция использовала в области вне функции:

local function makeOTU(skt)

    --skt is visible in the scope of the function
    --that gets returned as a result

    return function(data)
        skt:send(data .. "\r\n")
    end
end

function Server:init()
    local function handler(skt, host, port)

    --create a function that references skt
    --as part of its closure
    local OutToUser = makeOTU(skt)

        while true do
            data = skt:receive()
            if data == "quit" then
                -- OutToUser is still referencing the
                -- skt from the call to makeOTU()
                OutToUser(data)
            end
        end
    end

    local server = socket.bind("*", 49796)
    copas.addserver(server, 
        function(c) return handler(copas.wrap(c), c:getpeername()) end
    )
    copas.loop()
end

Обратите внимание на использование ключевого слова local в обоих этих примерах: если вы пренебрегаете local, имя будет полностью игнорировать область и попадет в / из глобальной среды (которая это просто таблица, как и любая другая: когда вы вызываете новое состояние Lua, оно помещается в глобальный _G), а это не то, что вам нужно.

Важно, чтобы ваши переменные были локальными по отношению к их области видимости, а не глобальными. Взять, к примеру, эти две функции:

local function yakkity(file, message)

    line = message .. '\n' --without local,
                           --equivalent to _G["line"] = message

    function yak() --without local,
                   --equivalent to _G["yak"] = function()

        file:write(line) --since no local "line" is defined above,
                         --equivalent to file:write(_G["line"])
    end
    for i=1, 5 do
        yak()
    end
end

local function yakker(file, message)
    line = message .. '\n' --without local,
                           --equivalent to _G["line"] = message

    return function()
        file:write(line) --again, since no local "line" is defined above,
                         --equivalent to file:write(_G["line"])
    end
end

Поскольку их переменные не определены как локальные, они сгущают данные друг друга, оставляют свои вещи, лежащие там, где кто-либо может злоупотреблять ими, и просто ведут себя как неряшливые:

--open handles for two files we want:
local yesfile = io.open ("yesyes.txt","w")
local nofile = io.open ("no.txt","w")

--get a function to print "yes!" - or, rather,
--print the value of _G["line"], which we've defined to "yes!".
--We'll see how long that lasts...
local write_yes = yakker(yesfile,"yes!")

--Calling write_yes() now will write "yes!" to our file.
write_yes()

--when we call yakkity, though, it redefines the global value of "line"
--(_G["line"]) - as well as defining its yak() function globally!
--So, while this function call does its job...
yakkity(nofile, "oh no!")

--calling write_yes(), which once again looks up the value of _G["line"],
--now does the exact OPPOSITE of what it's supposed to-
write_yes() --this writes "oh no!" to yesfile!

--additionally, we can still write to the nofile handle we passed to yakkity()
--by calling the globally-defined yak() function!
yak() --this writes a sixth "oh no!" to nofile!

--even once we're done with the file and close our handle to it...
nofile:close()

--yak() still refers to that handle and will still try to write to it!
yak() --tries to write to the closed file handle and throws an error!
0 голосов
/ 01 июня 2011

Я думаю, все, что вам нужно сделать, это иметь функцию OutToUser, которая также принимает аргумент skt и передает его изнутри обработчика.

...