【问题标题】:Persistent socket in Lua in parallel with other Lua codeLua 中的持久套接字与其他 Lua 代码并行
【发布时间】:2013-02-25 18:56:20
【问题描述】:

我正在 Lua 中实现套接字,我正在使用的示例代码使用以下方法来保持连接处于活动状态:

while true do
  -- handle socket traffic here
  socket.sleep(1)
end

循环显然会阻止项目代码的其余部分运行,但如果我退出循环,套接字服务器会立即表示连接已关闭。

那么如何在我的 Lua 代码的其余部分正常运行时同时保持套接字打开? (是否有某种后台作业支持?协程可以用于此目的吗?)

【问题讨论】:

  • 是监听器调用吗?
  • 如果是,可以看一下github上的luasocket的listener代码示例
  • 这似乎是等到它收到所有的数据,然后才打印出来。我需要将在“后台”连续运行的套接字代码,处理传入的数据,而其余的项目代码正在“在前台”运行。 (如果Lua中有背景和前景之类的东西)
  • OpenResty 执行您所描述的操作,即只要您使用its I/O functions,它就会在套接字阻塞时使用协程运行后台任务。考虑使用 openresty 服务器而不是标准解释器。

标签: sockets lua


【解决方案1】:

我使用 Lua Lanes 启动了一个线程,该线程正在执行套接字 i/o 并按照您的说明在后台运行。

http://kotisivu.dnainternet.net/askok/bin/lanes/

看看这个答案,它提供了有关使用 Lua 通道和套接字的信息。

LuaLanes and LuaSockets

那里提供的双线程轮询解决方案可能是最可行的,但是那里也有关于协程的信息。

【讨论】:

    【解决方案2】:

    (您的问题类似于this question(我已适当地将其标记为重复),但为方便起见,这是我的答案的副本!)

    有多种方法可以处理此问题;您将选择哪一项取决于您要完成多少工作。*

    但首先,您应该(对自己)澄清您是在处理 UDP 还是 TCP; UDP 套接字没有“底层 TCP 堆栈”。此外,UDP 是用于发送整个数据(如文本或照片)的错误协议;它是一个不可靠的协议,因此不能保证您接收到每个数据包,除非您使用托管套接字库(例如 ENet)。

    Lua51/LuaJIT + LuaSocket

    轮询是唯一的方法。

    • 阻塞:调用socket.select,不带时间参数,等待套接字可读。
    • 非阻塞:调用socket.select,超时参数为0,并在您正在读取的套接字上使用sock:settimeout(0)

    然后简单地重复调用这些。 我建议对非阻塞版本使用coroutine scheduler,以允许程序的其他部分继续执行而不会造成太多延迟。

    Lua51/LuaJIT + LuaSocket + Lua Lanes(推荐)

    与上述方法相同,但套接字存在于使用Lua Laneslatest source)创建的另一个通道(另一个线程中的轻量级 Lua 状态)中。这使您可以立即从套接字读取数据并进入缓冲区。然后,您使用linda 将数据发送到主线程进行处理。

    这可能是您问题的最佳解决方案。

    我已经为此做了一个简单的例子,可以使用here。它依赖于 Lua Lanes 3.4.0 (GitHub repo) 和修补过的 LuaSocket 2.0.2 (source, patch, blog post re' patch)

    结果很有希望,但如果你从中派生出我的示例代码,你肯定应该重构它。

    LuaJIT + 操作系统特定的套接字

    如果你有点自虐,你可以尝试从头开始实现一个套接字库。 LuaJIT's FFI library 使这从纯 Lua 成为可能。 Lua Lanes 对此也很有用。

    对于 Windows,我建议查看 William Adam's blog。他在 LuaJIT 和 Windows 开发方面有过一些非常有趣的冒险经历。至于 Linux 等,请查看 C 教程或 LuaSocket 的源代码,并将它们翻译成 LuaJIT FFI 操作。

    (如果 API 需要,LuaJIT 支持 callbacks;但是,与从 Lua 轮询到 C 相比,存在显着的性能成本。)

    LuaJIT + ENet

    ENet 是一个很棒的库。它提供了 TCP 和 UDP 之间的完美组合:需要时可靠,否则不可靠。它还抽象了操作系统特定的细节,就像 LuaSocket 一样。可以使用 Lua API 进行绑定,也可以通过 LuaJIT 的 FFI 直接访问(推荐)。

    *双关语无意。

    【讨论】:

      【解决方案3】:

      其他答案很好,但有点错过这里最重要的一点:

      如今在处理套接字时很少需要使用线程

      为什么?因为多套接字是如此普遍,所以操作系统(尤其是 *ix 系统)以epoll 函数的形式实现了“多轮询”。

      ZeroMQ 等所有高性能网络库都只保留几个线程,并在其中运行。这降低了内存需求,但不会牺牲速度。

      所以我的建议是直接连接到 OS 库,这在 Lua 中真的很容易。您不必自己编写代码 - 快速 google 搜索给我带来了this epoll wrapper [1] 然后您仍然可以使用协程仅从实际有一些数据的套接字中读取。

      您可能还想看看ZeroMQ library itself

      [1]Neopallium 为 ZMQ 创建了 Lua 绑定,所以我认为它是合法的。

      【讨论】:

        【解决方案4】:

        您确实可以为此目的使用协程。这就是流行的库Copas 所做的。

        根据您的用例,您可以使用 Copas 或查看其源代码以了解它是如何工作的。您还可以查看使用 Copas 的 lua-websockets

        【讨论】:

          猜你喜欢
          • 2019-10-11
          • 1970-01-01
          • 2013-06-26
          • 2017-11-07
          • 2011-09-22
          • 1970-01-01
          • 1970-01-01
          • 2012-02-19
          • 1970-01-01
          相关资源
          最近更新 更多