我正在 Lua 中实现套接字,我正在使用的示例代码使用以下方法来保持连接处于活动状态:
while true do
-- handle socket traffic here
socket.sleep(1)
end
循环显然阻止了项目代码的其余部分运行,但如果我退出循环,套接字服务器会立即表示连接已关闭。
那么如何在我的 Lua 代码的其余部分正常运行时同时保持套接字打开?(是否有某种后台作业支持?协程可以用于此目的吗?)
正如你所说,我使用 Lua Lanes 启动了一个正在执行套接字 i/o 并在后台运行的线程。
http://kotisivu.dnainternet.net/askok/bin/lanes/
看看这个答案,它提供了有关使用 Lua 通道和套接字的信息。
那里提供的双线程轮询解决方案可能是最可行的,但是那里也有关于协程的信息。
(您的问题与此问题相似(并且我已将其适当地标记为重复),但为方便起见,这是我的答案的副本!)
有多种方法可以处理此问题;你会选择哪一个取决于你想做多少工作。*
但首先,您应该(对自己)澄清您是在处理 UDP 还是 TCP;UDP 套接字没有“底层 TCP 堆栈”。此外,UDP 是用于发送整个数据(如文本或照片)的错误协议;它是一个不可靠的协议,因此不能保证您接收到每个数据包,除非您使用托管套接字库(例如ENet)。
轮询是唯一的方法。
socket.select
不带时间参数的调用并等待套接字可读。socket.select
使用超时参数调用0
,并sock:settimeout(0)
在您正在读取的套接字上使用。然后简单地重复调用这些。我建议对非阻塞版本使用协程调度程序,以允许程序的其他部分继续执行而不会造成太多延迟。
与上述方法相同,但套接字存在于使用Lua Lanes制作的另一个通道(另一个线程中的轻量级 Lua 状态)中(最新来源)。这使您可以立即从套接字读取数据并进入缓冲区。然后,您使用linda将数据发送到主线程进行处理。
这可能是您问题的最佳解决方案。
我已经做了一个简单的例子,可以在这里找到。它依赖于 Lua Lanes 3.4.0 ( GitHub repo ) 和修补过的 LuaSocket 2.0.2 ( source , patch , blog post re' patch )
结果是有希望的,但如果你从中派生出我的示例代码,你肯定应该重构它。
如果你有点自虐,你可以尝试从头实现一个套接字库。LuaJIT的FFI 库使这从纯 Lua 成为可能。Lua Lanes 对此也很有用。
对于 Windows,我建议查看William Adam 的博客。他在 LuaJIT 和 Windows 开发方面有过一些非常有趣的冒险经历。至于 Linux 和其他,请查看 C 教程或 LuaSocket 的源代码,并将它们转换为 LuaJIT FFI 操作。
(如果 API 需要,LuaJIT 支持回调;但是,与从 Lua 轮询到 C 相比,存在显着的性能成本。)
ENet是一个很棒的库。它提供了 TCP 和 UDP 之间的完美组合:需要时可靠,否则不可靠。它还抽象了操作系统特定的细节,就像 LuaSocket 一样。你可以使用 Lua API 来绑定它,或者直接通过 LuaJIT 的 FFI 访问它(推荐)。
*双关语无意。
其他答案很好,但有点错过这里最重要的一点:
为什么?因为多个套接字是如此普遍,所以操作系统(尤其是 *ix 系统)以epoll
函数的形式实现了“多轮询”。
ZeroMQ 等所有高性能网络库都只保留几个线程,并在其中运行。这降低了内存要求,但不会牺牲速度。
所以我的建议是直接连接到 OS 库,这在 Lua中非常容易。您不必自己编写代码 - 快速 google 搜索给我带来了这个 epoll 包装器[1] 然后您仍然可以使用协程仅从实际有一些数据的套接字中读取。
您可能还想看看ZeroMQ 库本身。
[1] Neopallium为 ZMQ 创建了 Lua 绑定,所以我认为它是合法的。
您确实可以为此目的使用协程。这就是流行的库Copas所做的。
根据您的用例,您可以使用 Copas 或查看其源代码以了解它是如何工作的。您还可以查看使用 Copas的lua-websockets 。