2012-10-15 4 views
9

현재 루아 소켓 구현에서 우리는 주기적으로 다시 호출하는 타이머를 설치해야 비 블로킹 API를 체크하여 아무것도받지 못했는지 확인할 수 있습니다.루아 소켓 - 비동기 이벤트

이것은 모두 좋은 것으로 UDP의 경우 발신자가 많은 정보를 보낸다면 데이터가 손실 될 수 있습니다. 다른 장치가 UDP를 통해 2MB 사진을 보내고 소켓이 100msec마다 수신되는지 확인합니다. 2MBps에서 호출이 기본 TCP 스택을 쿼리하기 전에 기본 시스템이 200Kbits를 저장해야합니다.

지금해야 할 폴링 대신 특정 소켓의 데이터를 수신 할 때 이벤트를 발생시키는 방법이 있습니까?

답변

13

local rset = {socket} 
... later 
...select(rset, nil, 0) 

: 그 옵션이 아니라면, 대신 일시적으로 사람의 정적 테이블을 읽고 전달하는 데 필요하지 않은 목록에 대한 select() 대신 {}nil을 통과 고려 이 문제를 다룰 수있는 다양한 방법이 있습니다. 어느 쪽을 선택 하느냐하는 것은 당신이하고 싶은 일의 양에 달려 있습니다. *

그러나 먼저 UDP 또는 TCP를 다루고 있는지 명확히해야합니다. UDP 소켓에는 "기본 TCP 스택"이 없습니다. 또한 UDP는 텍스트 나 사진과 같은 전체 데이터를 전송하는 데 사용하는 잘못된 프로토콜입니다. 그것은 신뢰할 수없는 프로토콜이므로 관리되는 소켓 라이브러리 (예 : ENet)를 사용하지 않는 한 모든 패킷을받을 수 있다고 보장 할 수 없습니다.

Lua51/LuaJIT + LuaSocket

폴링이 유일한 방법이다.

  • 블로킹 : 시간 인수가없는 socket.select을 호출하고 소켓을 읽을 수있을 때까지 기다립니다.
  • 비 블로킹 : 0의 시간 종료 인수를 사용하여 socket.select을 호출하고 읽고있는 소켓에서 sock:settimeout(0)을 사용하십시오.

다음을 반복적으로 호출하십시오. 비 차단 버전으로 coroutine scheduler을 사용하여 프로그램의 다른 부분을 너무 오래 지연시키지 않고 계속 실행할 수 있도록하는 것이 좋습니다.

Lua51/LuaJIT + LuaSocket + Lua Lanes 위의 방법으로

동일 (권장)하지만, 소켓이 다른 차선 (다른 스레드에서 경량 루아 상태)에 존재 Lua Lanes (latest source)를 사용했다. 이렇게하면 소켓에서 버퍼로 즉시 데이터를 읽을 수 있습니다. 그런 다음 linda을 사용하여 메인 스레드로 데이터를 보내 처리합니다.

아마도이 문제가 가장 좋은 해결책 일 수 있습니다.

간단한 예제를 만들었습니다. here을 사용할 수 있습니다. 그것은 루아 레인 3.4.0 (GitHub repo) 및 패치 LuaSocket 2.0.2 (source, patch, blog post re' patch)

당신이 그것에서 파생하는 경우 당신은 확실히 내 예제 코드를 리팩토링해야하지만 결과는, 유망한에 의존한다. 조금 자학 경우

LuaJIT + OS 별 소켓

, 당신은 처음부터 소켓 라이브러리를 구현하는 시도 할 수 있습니다. LuaJITFFI library은 순수 루아에서 가능합니다. 루아 레인 (Lua Lanes)도 이와 같이 유용 할 것입니다.

Windows의 경우 William Adam's blog을 살펴 보시기 바랍니다. 그는 LuaJIT 및 Windows 개발에 대한 흥미로운 모험을 경험했습니다. Linux와 나머지 부분에서는 C 또는 LuaSocket 소스에 대한 자습서를보고 LuaJIT FFI 작업으로 변환하십시오.

합니다 (API가 필요한 경우 LuaJIT가 callbacks을 지원하지만, signficant 성능 비용 루아에서 C와 폴링에 비해이)

LuaJIT + ENET

ENet 좋은 라이브러리입니다. 그것은 TCP와 UDP 사이의 완벽한 믹스를 제공합니다 : 원하는 경우 신뢰할 수 있고 그렇지 않은 경우에는 신뢰할 수 없습니다. 또한 LuaSocket과 마찬가지로 운영 체제 관련 세부 사항을 추상화합니다. Lua API를 사용하여 바인딩하거나 LuaJIT의 FFI를 통해 직접 액세스 할 수 있습니다 (권장).

* 우연한 사람.

3

루아는 본질적으로 단일 스레드입니다. "사건"같은 것은 없습니다. 루아 코드 실행을 중단시키는 방법은 없습니다. 따라서 이벤트처럼 보일 수있는 뭔가를 조작 할 수있는 동안 어떤 이벤트를 사용할 수 있는지 폴링 한 함수를 호출 한 경우에만 얻을 수 있습니다.

일반적으로 이러한 종류의 하위 작업에 Lua를 사용하려는 경우 잘못된 도구를 사용하고있는 것입니다. 이런 종류의 데이터에 액세스하려면 C 또는 무언가를 사용해야하며 준비가되면 루아에 전달해야합니다.

+1

루아가 실제로 콜백을 사용하는 시스템 이벤트가있는 단일 스레드 시스템이라는 것을 알고 있습니다. 나는 계속해서 그것을 보지 않고 사용할 수있는 데이터가있을 때 전화를받을 수 있기를 바랬다. – user4749

+0

콜백 수신을 위해 콜백을 수행하고 있던 사람이라면 컨트롤을 전송해야합니다. 그래서 당신이 그랬을 때마다 데이터가 있는지 확인하십시오. –

+0

나는 크게 동의하지 않습니다. lua-ev 또는 다른 이벤트를 사용하면 폴링이 부과되지 않습니다!Lua + 사용 "일부 이벤트 루프"는 매우 우수한 성능과 낮은 메모리 사용량으로 심각한 작업을 위해 임베디드 장치 (node.js가 큰 위치)에서 매우 생산적으로 사용됩니다. 어떤 상황에서는 완벽한 일치입니다. 매우 낮은 수준 (https://github.com/justincormack/ljsyscall)의 OS로 작업하기가 매우 쉬운 모듈이 있습니다. – lipp

1

사용 가능한 새로운 데이터를 "폴링"하려면 비 블로킹 select()을 사용하고있을 것입니다. Luasocket은 새로운 데이터를 사용할 수 있는지 알기 위해 다른 인터페이스를 제공하지 않지만,이 작업을 초당 10 회 수행 할 때 너무 많은 시간이 걸린다는 우려가 있다면 단순화 된 버전 작성을 고려하십시오. 당신이 필요로하는 하나의 소켓 만 검사하고 루아 테이블을 생성하고 버리는 것을 피한다. 대신이

...select({socket}, {}, 0) 
+0

좋습니다 .. 이것은 좋은 아이디어이며 아주 잘 작동 할 수 있습니다 – user4749

5

모든 IO 멀티플렉싱 작업에는 lua-ev https://github.com/brimworks/lua-ev을 사용합니다. 루아 (그리고 그것의 function)를 매력처럼 사용하는 것은 매우 쉽습니다. 그것은/poll/epoll 또는 kqueue 기반을 선택하거나 매우 훌륭하게 수행합니다. 내 의견 루아 + luasocket의 +의 루아-EV에서

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 

은 (임베디드 디바이스/환경) 효율적이고 강력한 네트워킹 애플리케이션을 구축하기위한 단지 드림 팀이다. 거기에 더 강력한 도구가 있습니다! 그러나 리소스가 제한적이라면 루아는 좋은 선택입니다!

+0

Gideros와 함께 iPhone/Android에서 사용할 수 있습니까? (www.giderosmobile.com) iPhone/Android 포트를 보지 못했습니다. – user4749

+0

죄송합니다, gideros/corona 세계에서 "native"C 바인딩으로 Lua 모듈을 확장 할 수 있는지 여부는 잘 모르겠습니다. lua-ev (libev를 기반으로 함)는 "any"Unix 용으로 컴파일됩니다. – lipp