Receive UDP packets with RMXP
#1
I'm trying to make two (or more) RPG Maker XPs communicate over the network through UDP. The idea is to implement a basic hello/discovery protocol.

I'm using the "module Win32/module Winsock/class Socket/class TCPSocket" library that you find in any netplay-related project.
Plus, I added a UDPSocket class:

Code:
#===============================================================================
# ** UDPSocket - Creates and manages UDP sockets.
#-------------------------------------------------------------------------------
# Author    Ruby
# Version   1.8.1
#===============================================================================

class UDPSocket < Socket

  #--------------------------------------------------------------------------
  # ? Creates a new socket and connects it to the given host and port.
  #--------------------------------------------------------------------------  
  def self.open(*args)
    socket = new(*args)
    if block_given?
      begin
        yield socket
      ensure
        socket.close
      end
    end
    return socket
  end

  #--------------------------------------------------------------------------
  # ? Creates a new socket and connects it to the given host and port.
  #--------------------------------------------------------------------------  
  def initialize
    super(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
  end
end

As you can see it's almost identical to the TCPSocket class, but it uses SOCK_DGRAM and IPPROTO_UDP, and doesn't connect the socket (it's initialized without arguments).

I have managed to send unicast and broadcast to a listener written in ruby that runs outside RPG Maker XP (I have installed Ruby on my Windows machine), but I couldn't make RPG Maker XP receive UDP packets of any kind.

This code sends UDP broadcast packets from RMXP and it works perfectly:

Code:
BROADCAST_ADDR = "255.255.255.255"
ANYCAST_ADDR = "0.0.0.0"
UNICAST = "192.168.0.4"
port = 4323
    
# SEND
    
@socket = UDPSocket.new
@socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, [0,0,0,1].pack("cccc"), 4)
@socket.connect([Socket::AF_INET, Socket.getservice(port), Socket.getaddress(BROADCAST_ADDR).split(".").collect { |b| b.to_i }].flatten.pack("snC4x8"))
@socket.send("This is a broadcast")

In order to receive broadcast packets, a stand-alone ruby app would do something like this:

Code:
require 'socket'

$port = 4323

sThread = Thread.start do     # run server in a thread
  server = UDPSocket.open
  server.bind('0.0.0.0', $port)
  2000.times { p server.recvfrom(64) }
  server.close
end

sThread.join

# Wait for Enter Key to be pressed.
$stdin.gets

(ignore all the unnecessary code)
which, inside RPG Maker XP, based on the API documentation, would be something like

Code:
# Broadcast
@insocket = UDPSocket.new
@insocket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, [0,0,0,1].pack("cccc"), 4)
@insocket.bind(Socket.sockaddr_in(port, ANYCAST_ADDR))
# Receive data
while true
  if @insocket.ready?
    p @insocket.recvfrom(64)
  end
end

where recvfrom is defined as:

Code:
class Socket
  #--------------------------------------------------------------------------
  # ? Returns received data.
  #--------------------------------------------------------------------------  
  def recvfrom(len, flags = 0)
    buf = "\0" * len
    buf2 = "\0" * 32
    buf3 = "\0" * 4
    SocketError.check if Winsock.recvfrom(@fd, buf, buf.size, flags, buf2, buf3) == -1
    return buf, buf2
  end
end

with also:

Code:
module Winsock
  #--------------------------------------------------------------------------
  # * Receive From
  #--------------------------------------------------------------------------
  def self.recvfrom(*args)
    Win32API.new(DLL, "recvfrom", "ppllpp", "l").call(*args)
  end
end

(ignore all the unnecessary code)
Well, it doesn't work, that is @insocket.ready? returns true, but @insocket.recvfrom returns a string of "\000" values.
The exact behavior is that:
a) when an external app is actually broadcasting data that string is returned at the first received packet and then it is returned immediately for the following calls;
b) when no message is being broadcasted, @insocket.ready? returns true anyway, @insocket.recvfrom does not return at all and of course I get the "the script is hanging" message.

The problem seems to be in the decoding phase, because the difference between a) and b) tells me that RMXP is receiving those packets. Also, @insocket.ready?, which is based on the dll function select, does not work as expected.

So... HEEEEELPPPP!!!!

Update: it appears that this behavior of select with udp socket is a problem for many.
Reply }


Messages In This Thread
Receive UDP packets with RMXP - by Charlie Fleed - 02-18-2010, 10:38 PM

Possibly Related Threads…
Thread Author Replies Views Last Post
   [RMXP] Showing skill gained by leveling up on battle result FrQise 12 12,648 05-07-2021, 02:05 PM
Last Post: FrQise
   RMXP SKill animations too bright (overlaying the battle screen) Starmage 4 10,152 06-13-2016, 03:41 AM
Last Post: Starmage
   [RMXP]Game Over and Atoa Battle Status mishaps firestalker 8 10,932 08-07-2014, 01:59 AM
Last Post: firestalker
Star Multilanguage script petition for RMXP Iqus 11 19,236 01-07-2013, 10:50 AM
Last Post: Narzew
   [RMXP] Actor Cloning dagarath 2 9,173 03-08-2011, 07:18 AM
Last Post: dagarath
   Replace the AUDIO class for RMXP! DerVVulfman 8 15,268 10-15-2010, 06:29 PM
Last Post: yamina-chan



Users browsing this thread: 1 Guest(s)