2012-10-15 37 views
9

Trong cài đặt ổ cắm lua hiện tại, tôi thấy rằng chúng tôi phải cài đặt hẹn giờ gọi lại theo định kỳ để chúng tôi kiểm tra API không chặn để xem chúng tôi có nhận được gì không.Ổ cắm Lua - Sự kiện không đồng bộ

Đây là tất cả tốt và tốt tuy nhiên trong trường hợp UDP, nếu người gửi có nhiều thông tin được gửi, chúng tôi có nguy cơ mất dữ liệu hay không. Giả sử một thiết bị khác gửi ảnh 2MB qua UDP và chúng tôi kiểm tra ổ cắm nhận 100msec mỗi lần. Tại 2MBps, hệ thống cơ bản phải lưu trữ 200Kbits trước khi cuộc gọi của chúng tôi truy vấn ngăn xếp TCP cơ bản.

Có cách nào để phát hiện sự kiện khi chúng tôi nhận dữ liệu trên ổ cắm cụ thể thay vì bỏ phiếu mà chúng tôi phải thực hiện ngay bây giờ không?

Trả lời

13

Có là một cách khác nhau để xử lý vấn đề này; cái mà bạn sẽ chọn phụ thuộc vào số lượng công việc bạn muốn làm. *

Nhưng trước tiên, bạn nên làm rõ (cho chính mình) cho dù bạn đang giao dịch với UDP hoặc TCP; không có "ngăn xếp TCP cơ bản" cho các ổ cắm UDP. Ngoài ra, UDP là giao thức sai để sử dụng để gửi toàn bộ dữ liệu như văn bản hoặc ảnh; nó là một giao thức không đáng tin cậy, do đó bạn không được đảm bảo nhận mọi gói, trừ khi bạn đang sử dụng thư viện socket được quản lý (chẳng hạn như ENet).

Lua51/LuaJIT + LuaSocket

Bỏ phiếu là phương pháp duy nhất.

  • Chặn: gọi socket.select không có đối số thời gian và chờ ổ cắm có thể đọc được.
  • Không chặn: gọi socket.select với đối số hết giờ là 0 và sử dụng sock:settimeout(0) trên ổ cắm bạn đang đọc.

Sau đó, chỉ cần gọi những liên tục này. Tôi khuyên bạn nên sử dụng coroutine scheduler cho phiên bản không chặn, để cho phép các phần khác của chương trình tiếp tục thực thi mà không gây ra quá nhiều sự chậm trễ.

Lua51/LuaJIT + LuaSocket + Lua Lanes (Recommended)

Tương tự như phương pháp trên, nhưng các ổ cắm tồn tại trong một làn đường (trạng thái Lua nhẹ trong chủ đề khác) đã sử dụng Lua Lanes (latest source). Điều này cho phép bạn ngay lập tức đọc dữ liệu từ ổ cắm và vào bộ đệm. Sau đó, bạn sử dụng linda để gửi dữ liệu đến chuỗi chính để xử lý.

Đây có lẽ là giải pháp tốt nhất cho vấn đề của bạn.

Tôi đã tạo một ví dụ đơn giản về điều này, có sẵn here. Nó dựa vào Lua Lanes 3.4.0 (GitHub repo) và một LuaSocket vá 2.0.2 (source, patch, blog post re' patch)

Kết quả là đầy hứa hẹn, mặc dù bạn chắc chắn nên refactor code ví dụ của tôi nếu bạn lấy được từ nó.

LuaJIT + hệ điều hành cụ socket

Nếu bạn là một chút bạo dâm, bạn có thể thử thực hiện một thư viện socket từ đầu. LuaJIT 's FFI library làm cho điều này có thể từ Lua thuần túy. Lua Lanes sẽ hữu ích cho việc này.

Đối với Windows, tôi khuyên bạn nên xem William Adam's blog. Anh ấy đã có một số cuộc phiêu lưu rất thú vị với sự phát triển LuaJIT và Windows. Đối với Linux và phần còn lại, hãy xem hướng dẫn cho C hoặc nguồn của LuaSocket và dịch chúng sang các hoạt động LuaJIT FFI.

(LuaJIT hỗ trợ callbacks nếu API đòi hỏi nó, tuy nhiên, có một chi phí hiệu suất signficant so với bỏ phiếu từ Lua tới C.)

LuaJIT + eNet

ENet là một thư viện tuyệt vời. Nó cung cấp sự kết hợp hoàn hảo giữa TCP và UDP: đáng tin cậy khi mong muốn, không đáng tin cậy nếu không. Nó cũng tóm tắt các chi tiết cụ thể của hệ điều hành, giống như LuaSocket. Bạn có thể sử dụng API Lua để liên kết nó hoặc truy cập trực tiếp qua FFI của LuaJIT (được khuyến nghị).

* Pun không chủ ý.

3

Lua vốn đã đơn luồng; không có thứ như "sự kiện". Không có cách nào để làm gián đoạn việc thực thi mã Lua. Vì vậy, trong khi bạn có thể giàn khoan một cái gì đó lên trông giống như một sự kiện, bạn sẽ chỉ nhận được một nếu bạn gọi là một chức năng mà thăm dò những sự kiện có sẵn.

Nói chung, nếu bạn đang cố gắng sử dụng Lua cho loại công việc cấp thấp này, bạn đang sử dụng công cụ sai. Bạn nên sử dụng C hoặc một cái gì đó để truy cập vào loại dữ liệu này, sau đó chuyển nó sang Lua khi nó sẵn sàng.

+1

Tôi nhận ra Lua thực sự là hệ thống chuỗi đơn lẻ với sự kiện hệ thống sử dụng gọi lại. Tôi đã chỉ hy vọng chúng tôi sẽ nhận được một cuộc gọi trở lại khi có dữ liệu có sẵn thay vì tiếp tục nhìn vào nó. – user4749

+0

Bạn vẫn phải chuyển quyền kiểm soát cho bất kỳ người nào đang thực hiện cuộc gọi lại để nhận cuộc gọi lại. Vì vậy, bất cứ khi nào bạn đã làm điều đó, chỉ cần kiểm tra xem liệu dữ liệu có ở đó không. –

+0

Tôi không đồng ý nhiều. Sử dụng lua-ev hoặc một sự kiện khác KHÔNG áp đặt bỏ phiếu!Sử dụng Lua + "Một số vòng lặp sự kiện" được sử dụng rất hiệu quả trong các thiết bị nhúng (trong đó node.js là lớn) cho các tác vụ nghiêm trọng với hiệu suất rất tốt và dấu chân mem thấp. Đối với một số trường hợp, đây là một trận đấu hoàn hảo. Có các mô đun xung quanh giúp dễ dàng làm việc với hệ điều hành ở mức rất thấp (https://github.com/justincormack/ljsyscall). – lipp

1

Có thể bạn đang sử dụng một khóa không chặn select() tới "cuộc thăm dò ý kiến" cho mọi dữ liệu mới có sẵn. Luasocket không cung cấp bất kỳ giao diện nào khác để xem liệu có sẵn dữ liệu mới hay không, nhưng nếu bạn lo ngại rằng nó mất quá nhiều thời gian khi bạn làm điều này 10 lần mỗi giây, hãy xem xét viết một phiên bản đơn giản chỉ kiểm tra một ổ cắm bạn cần và tránh tạo và ném các bảng Lua. Nếu đó không phải là một lựa chọn, cân nhắc đi nil-select() thay vì {} cho những danh sách bạn không cần phải đọc và thông qua bảng tĩnh thay vì tự vệ tạm thời:

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

thay vì

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

Ok .. Đây là một ý tưởng tốt và nó có thể hoạt động rất tốt – user4749

5

Tôi sử dụng lua-ev https://github.com/brimworks/lua-ev cho tất cả nội dung ghép kênh IO. Nó rất dễ sử dụng phù hợp với Lua (và function) của nó giống như một sự quyến rũ. Nó là một trong hai lựa chọn/thăm dò ý kiến ​​/ epoll hoặc kqueue dựa và thực hiện rất tốt quá.

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 

Theo tôi, Lua + luasocket + lua-ev chỉ là một nhóm mơ ước xây dựng các ứng dụng mạng hiệu quả và mạnh mẽ (cho thiết bị/môi trường nhúng). Có nhiều công cụ mạnh mẽ hơn ngoài kia! Nhưng nếu nguồn lực của bạn bị hạn chế, Lua là một lựa chọn tốt!

+0

Điều này có thể được sử dụng trên iPhone/Android với Gideros không? (www.giderosmobile.com) Tôi chưa thấy một cổng iPhone/Android. – user4749

+0

Xin lỗi, tôi không biết liệu có thể mở rộng mô-đun Lua bằng các ràng buộc C "bản địa" trong thế giới của gideros/corona hay không. lua-ev (dựa trên libev) biên dịch cho Unix "bất kỳ" nào. – lipp

Các vấn đề liên quan