Luasocket - 如何发送/接收UDP广播消息?

问题描述 投票:0回答:2

我已经尝试这样做有一段时间了。我尝试遵循此http://lua.2524044.n2.nabble.com/UDP-Broadcast-td3995269.html,但无济于事。我已成功在客户端和服务器之间发送unicast消息。我已确认我的广播地址是正确的。我唯一能想到的另一件事就是嗅探我的接口以确保没有网络问题。我明天会处理这个问题,但想将其发布在这里,看看是否有人会注意到一个愚蠢的错误。

注意:我在同一台笔记本电脑上运行客户端和服务器。

客户

local socket = require("socket")
local s_address, s_port = "192.168.1.135", 33333
local d_address, d_port = "192.168.1.255", 22222

udp = socket.udp()
assert(udp)
assert(udp:settimeout(1))
assert(udp:setoption('broadcast', true))
assert(udp:setoption('dontroute',true))
assert(udp:setsockname(s_address, s_port))

while true do
  tosend = string.format("client %s:%s", s_address, s_port)
  print(string.format('sending to %s:%s...', d_address, d_port))
  udp:sendto(tosend, d_address, d_port)

  data, msg = udp:receive()
  toprint = string.format("data = \"%s\"", data)
  print(toprint)
  socket.sleep(.5)
end

服务器

local socket = require("socket")
local s_address, s_port = "192.168.1.135", 11111
local p_address, p_port = "192.168.1.255", 22222

udp = socket.udp()
assert(udp)
assert(udp:setoption('broadcast', true))
assert(udp:setoption('dontroute',true))
assert(udp:settimeout(1))
assert(udp:setsockname(s_address, s_port))
assert(udp:setpeername(p_address, p_port))

while true do
  data = udp:receive()
  print(string.format('listening on %s:%s...', p_address, p_port))
  toprint = string.format("data = \"%s\"", data)
  print(toprint)
  if data then
    msg_back = "server received your message"
    udp:send(msg_back)
  end
  socket.sleep(.5)
end

输出
两面不断打印

data = "nil"

networking lua udp broadcast luasocket
2个回答
1
投票

我一直在寻求自己实现 luasocket 广播,这是互联网上为数不多的甚至提出该主题的页面之一。最后,在 luasocket API 和一些我能够适应的 python 代码之间,我找到了一个适合我的解决方案:

local socket = require 'socket'
local HOME_ADDR = '192.168.0.1'
local SUBNET_PATTERN = '%d+%.%d+%.%d+%.'

local function get_own_address()
  local s = assert(socket.udp())
  assert(s:setpeername(HOME_ADDR, 80))
  local host = s:getsockname()
  s:close()
  return host
end

function broadcast(message, address, port)
  local broadcaster = assert(socket:udp())
  assert(broadcaster:setoption('broadcast', true))
  assert(broadcaster:setoption('dontroute', true))   -- do we need this?

  print(('Broadcasting %q to %s:%i'):format(message, address, port))
  assert(broadcaster:sendto(message, address, port))
  broadcaster:close()
end

function antiphony(message, timeout, call_port, response_port, response_mask)
  local message, timeout, mask = tostring(message), tonumber(timeout) or 1.5, response_mask or '*a'
  local send_port, recv_port = call_port or 10500, response_port or 10501
  local broadcast_address = get_own_address():match(SUBNET_PATTERN) .. '255'
  local listener = assert(socket.bind('*', recv_port, 64))
  local clients, responses, starttime = {}, {}

  listener:settimeout(0)
  broadcast(message, broadcast_address, send_port)
  starttime = socket.gettime()
  repeat clients[listener:accept() or false] = true
  until socket.gettime() - starttime > timeout

  for client in pairs(clients) do 
    if client then
      responses[client:getpeername()] = tostring(client:receive(mask))
      client:close()
    end
  end
  listener:close()

  return responses
end

function listen(response_callback, timeout, listen_port, reply_port)
  local recv_port, send_port = tonumber(listen_port) or 10500, tonumber(reply_port) or 10501
  local callback = response_callback or function()end
  local address = get_own_address():match(SUBNET_PATTERN) .. '255'
  local sleeper = socket.udp()

  sleeper:settimeout(timeout)
  sleeper:setsockname(address, recv_port)
  repeat
    local data, ip, port = sleeper:receivefrom(1024)
    if data then callback(ip, send_port, data) end
  until not data
end

function respond(message, data_handler) 
  return function(ip_addr, port, data)
    assert(ip_addr and port, ('Invalid address: %s:%s'):format(tostring(ip_addr), tostring(port)))
    local msg = tostring(type(data_handler) == 'function' and (data_handler(data, message) or messsage) or message)
    local sender = assert(socket.connect(ip_addr, port))
    assert(sender:send(msg))
    sender:close()
  end
end

--[[

-- Listener / Responder:
listen(respond('polo', print), 600) -- 10 minute timeout

-- Broadcaster / Receiever:
for address, response in pairs(antiphony('marco')) do 
  print(address, response) 
end

]]

0
投票

我已经迟到了,但是对于有同样问题的人来说,你可以将所有客户端的IP和端口存储在一个表中,当你想广播一条消息时,你将循环遍历表中的所有客户端并向每个客户端发送一条消息其中。

© www.soinside.com 2019 - 2024. All rights reserved.