Lua套接字 - 异步事件

use*_*749 9 sockets lua

在当前的lua套接字实现中,我看到我们必须安装一个定期回调的计时器,以便我们检查非阻塞API以查看是否收到了任何内容.

这一切都很好,但在UDP情况下,如果发件人发送了大量信息,我们是否有丢失数据的风险.假设另一台设备通过UDP发送2MB照片,我们每100毫秒检查一次套接字.在2MBps时,底层系统必须在我们的调用查询底层TCP堆栈之前存储200Kbits.

当我们收到特定套接字上的数据而不是我们现在要做的轮询时,有没有办法让事件被触发?

Dec*_*eco 13

有各种方法来处理这个问题; 您将选择哪一个取决于您想要做多少工作.*

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

Lua51/LuaJIT + LuaSocket

轮询是唯一的方法.

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

然后简单地反复调用它们.我建议使用协程调度程序用于非阻塞版本,以允许程序的其他部分继续执行而不会导致太多延迟.

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

与上面的方法相同,但是套接字存在于使用Lua Lanes(最新源代码)制作的另一个通道(另一个线程中的轻量级Lua状态)中.这允许您立即从套接字读取数据并进入缓冲区.然后,使用linda将数据发送到主线程进行处理.

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

我在这里提供了一个简单的例子.它依赖于Lua Lanes 3.4.0(GitHub repo)和修补的LuaSocket 2.0.2(源代码,补丁,博客文章重新补丁)

结果很有希望,但如果你从中得到它,你肯定应该重构我的示例代码.

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

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

对于Windows,我建议看一下William Adam的博客.他在LuaJIT和Windows开发方面有过一些非常有趣的冒险经历.至于Linux和其他内容,请查看C的教程或LuaSocket的源代码,并将它们转换为LuaJIT FFI操作.

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

LuaJIT + ENet

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

*双关语无意识.


lip*_*ipp 5

我使用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是个不错的选择!