【问题标题】:Lua Copas, help clarifying how to handle multiple usersLua Copas,帮助阐明如何处理多个用户
【发布时间】:2011-06-03 01:36:22
【问题描述】:

我有点困惑,认为这将是一个简单的答案,但我的搜索对我没有多大帮助:(我希望能够在任何地方进行 skt:send。我可以将其发送到 OutToUser 函数一个参数,但我将有很多不同的地方我想做这个并且觉得这会变得太乱了。我尝试将它存储为 Server.connections[key] = skt,其中 key 是主机和端口但不知道以后需要时如何再次获取主机和端口。

有什么好的解决办法吗?

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()

【问题讨论】:

  • 您还需要在哪里将 skt 传递给 OutToUser?
  • 我更想弄清楚如何能够确定哪个用户正在做某事而不必绕过skt。因此,例如,我真正在做的不是 OutToUser,而是类似“determineResponse”之类的东西,然后它接受用户输入并确定如何处理它 - 可能会将某些内容回显给用户,或者跳转到另一个类的方法并保存我试图在这个例子中保持简单,并弄清楚如何在 OutToUser 中访问 skt 而不必将其作为参数传递。由于多个用户,它不能是单个全局变量。
  • 查看我的答案以获得两种可能的解决方案。

标签: scope lua


【解决方案1】:

您可以在处理程序的范围内定义 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,名称将完全忽略范围并进入/来自 the global environment(这只是一个像任何其他:当你调用一个新的 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!

【讨论】:

  • lua 中的作用域内容被证明是最困难的部分!你的回答让我重新思考如何解决这个问题,在弄乱了你的代码并将其合并到我的代码中之后,我想出了我需要做什么。谢谢!
【解决方案2】:

我认为您需要做的就是让 OutToUser 函数也接受 skt 参数,并从处理程序内部传递它。

【讨论】:

  • 这行得通,但我的目标是能够确定哪个用户在任何函数中做某事而不将套接字作为参数传入(因为它会得到到处乱跑)。
猜你喜欢
  • 1970-01-01
  • 2011-07-28
  • 2022-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-14
相关资源
最近更新 更多