Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Separate network thread?

Hi all,
I'm writing a game with multiplayer and networking, and I was wondering what is the best way to receive messages sent from a server.
Currently I'm using the main thread for the game, and creating another thread for a network loop which blocks with #gets() and interprets the results, but this seems to react very slowly to new information sent from the server and the multiplayer aspect is very laggy; because the game I'm making is effectively a MOBA, this is unacceptable and game-breaking. Is there a better way of doing this? I know non-blocking IO would probably be better already, but I don't understand how non-blocking IO works, so if anyone could enlighten me as to how that works, that'd be much appreciated also.
 
Well the Max standard size to read a whole UDP packet is around 500bytes, it's best to read only as much as you think you need to stay kind to the OS, does nothing for you or your buffers
 
I've confirmed the incoming port on a greeting packet from the client on the server side, but I can't seem to be able to get a response from the client from a server message (it doesn't appear to be receiving it).

On the client side, I have two UDPSockets: One which is #connected to the serverip:serverport and one which is is bound to localhost:serverport to listen for incoming messages. Is this how I should be doing it? I couldn't find any useful information on UDP Servers in Ruby outside of EventMachine, and I don't want to have to rely on that.
 
Ruby:
  def udp_network_loop

    @udp_socket = UDPSocket.new

    @udp_socket.bind('localhost',@current_port+1)

    loop do

      message = @udp_socket.recvfrom(50)

      interpret_message(message)

    end

    @udp_socket = nil

  end

  def send_udp(msg)

    @udp_socket.send(msg,0,@current_ip,@current_port+1)

  end
Having it like this, with only one socket, doesn't even send messages to the server anymore. I don't think I'm meant to be able to send from a binded socket. :|:

EDIT: This lets me send, but still no receive:
Ruby:
  def udp_network_loop

    @udp_socket = UDPSocket.new

    @udp_socket.connect(@current_ip,@current_port+1)

    @udp_server = UDPSocket.new

    @udp_server.bind('localhost',@current_port+1)

    loop do

      message = @udp_server.recvfrom(50)

      interpret_message(message)

    end

    @udp_socket = nil

  end

  

  def send_udp(msg)

    @udp_socket.send(msg,0)

  end

 
 
That doesn't look right. Looks like Ruby added a fake "connect" to UDP so it feels a bit more TCP like, I disagree with that.

This is the kind of thing you'd need for a simple 2-way communication:
Ruby:
# Client Process

SendTest( "127.0.0.1", 27000 )

 

def SendTest( serverIP, serverPort )

    udpSocket = UDPSocket.new

    udpSocket.bind( "127.0.0.1", 0 ) # bind on any port

 

    udpSocket.send( "TestTestTest", 0, serverIP, serverPort ) # Send TestTestTest to server

    

    mesg, addr = udpSocket.recvfrom( 500 ) # wait for a reply of 500 bytes

    puts mesg # Should say ReplyReplyReply

end

 

# Server Process

ListenTest( 27000 )

 

def ListenTest( listenPort )

    udpSocket = UDPSocket.new

    udpSocket.bind( "127.0.0.1", listenPort ) # bind on a specific port

 

    mesg, addr = udpSocket.recvfrom( 500 ) # wait for a message of 500 bytes

    

    puts mesg # Should say TestTestTest

    

    udpSocket.send( "ReplyReplyReply", 0, addr[3], addr[1] ) # addr contains [PROTOCOL, PORT FROM, HOST NAME, IP ADDRESS]

    # so we reply to IP ADDRESS via the port they sent from (PORT FROM)

end
Un-tested code, it probably doesn't even compile

Also, both of these functions would be called once because you shouldn't be constantly creating new sockets like that!
 
Xilef":mr0zjqrj said:
That doesn't look right. Looks like Ruby added a fake "connect" to UDP so it feels a bit more TCP like, I disagree with that.
Yeah, but from what I can tell, it's just shorthand so that if you're sending to the one address, you don't need to re-type it. Oddly though, if I bind a socket and attempt to #connect afterwards, it raises an error, so perhaps I can't send to a binded port at all, and #send quietly ignores the error.

EDIT: I think I'll fiddle with it for a bit longer, I'll update later.
EDIT2: Alright, it crashes because the server binds to localhost:4546, and then the client attempts to make its own listener on its own localhost:4546, so that's why there's crashes. Any way around this, other than to run the server on a different PC?
Xilef":mr0zjqrj said:
Also, both of these functions would be called once because you shouldn't be constantly creating new sockets like that!
Yeah, I figured as much.
 
Hey, sorry I never saw.

You can't have two programs bound to the same port on the same device, it's simply not possible as the port is used for identifying the program by the operating system.

You are safe to bind the client listen port to any random port (Port zero) and use the packet sender data on the server's end to find out what port they need to reply to. Only the server needs to bind to an open port.

It is considered healthier and much, much safer to let the client bind to any port it wants, a lot of the delay behind IPv6 being rolled out is due to applications not updating and it's those same applications that make incorrect assumptions about what port a client will be bound to (There are hacks in your routers to modify network packets that have certain ports, presuming that they are meant for this old applications).
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top