在当前的lua套接字实现中,我看到我们必须安装一个定期回调的计时器,以便我们检查非阻塞API以查看是否收到了任何内容.
这一切都很好,但在UDP情况下,如果发件人发送了大量信息,我们是否有丢失数据的风险.假设另一台设备通过UDP发送2MB照片,我们每100毫秒检查一次套接字.在2MBps时,底层系统必须在我们的调用查询底层TCP堆栈之前存储200Kbits.
当我们收到特定套接字上的数据而不是我们现在要做的轮询时,有没有办法让事件被触发?
Dec*_*eco 13
有各种方法来处理这个问题; 您将选择哪一个取决于您想要做多少工作.*
但首先,您应该(自己)澄清您是在处理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(源代码,补丁,博客文章重新补丁)
结果很有希望,但如果你从中得到它,你肯定应该重构我的示例代码.
如果你有点自虐,你可以尝试从头开始实现一个套接字库.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直接访问它(推荐).
*双关语无意识.
我使用lua-ev https://github.com/brimworks/lua-ev进行所有IO多路复用的东西.它很容易使用Lua(和它的function)就像魅力.它既可以选择/ poll/epoll或kqueue,也可以表现得非常好.
local ev = require'ev'
local loop = ev.Loop.default
local udp_sock -- your udp socket instance
udp_sock:settimeout(0) -- make non blocking
local udp_receive_io = ev.IO.new(function(io,loop)
local chunk,err = udp_sock:receive(4096)
if chunk and not err then
-- process data
end
end,udp_sock:getfd(),ev.READ)
udp_receive_io:start(loop)
loop:loop() -- blocks forever
Run Code Online (Sandbox Code Playgroud)
在我看来,Lua + luasocket + lua-ev只是一个用于构建高效且强大的网络应用程序(用于嵌入式设备/环境)的梦之队.那里有更强大的工具!但如果你的资源有限,Lua是个不错的选择!