1

I'm trying to create a custom game server protocol in Ruby but i'm failing to understand how i can/should do a couple things:

Q->1#

Server sends an array to client using TCPServer/TCPSocket. but i can't use JSON as the transfer needs to be binary.. How can i convert a ruby array into binary which can then be transformed back into an array in client side?

This is my server:

#!/usr/bin/env ruby

require 'socket'

server = TCPServer.new 5020

loop do
    Thread.start(server.accept) { |c|
        print "new Client connected" 
        a = ["Hello, there"]

        payload_with_header = CustomProtocolModule.constructMethod(a) # what method do i use to convert a (array -> binary representation?  don't really understand .unpack, .pack, what template would i use if i did use String#Unpack? will String#Unpack work for what i need?
        client.write payload_with_header
        client.close
    }
end

(Above is my first question)

Q->2#

Next since i know i need to use some sort of termination to check the end of message or a way to determine if the client/server has received the full message could i set the first two bytes of the payload to contain the size of the message? How would i do this server-side & client-side? The receiving party would have to loop TCPSocket.recv ? until it receives the first two bytes (the header), then read up the size the first two bytes contains? Something like this is what i had in mind:

| Payload Header  (2 bytes) | array (contains cmd, message etc) |

If someone could help guide me in the right direction and/or provide pseudo code that can help. It would be greatly appreciated. Specifically i'm interested in how to loop for header, then read the payload back into an array and constructing the payload header.

Thanks!

1 Answer 1

1
payload_with_header = CustomProtocolModule.constructMethod(a) 

You could serialize with

payload = Marshal.dump(a) 

Then you can use

[payload.length].pack('l>') # to create a big endian signed long integer size for the packet

On the other side you can read an integer from the socket, then read the binary and deserialize with

array= Marshal.load(read_binary)

This will work for almost every data structure. Proc instances are an exception.

Ruby also supports remote objects and procedure calls so you can have interprocess communication, even between different ruby implementations (JRuby and MRI for instance)

Sign up to request clarification or add additional context in comments.

12 Comments

Thanks for telling me about Marshal, just tested in irb, pretty good. However the question isn't solved yet. Still need help for the payload header/network packet question
Can you specify endianess with Array#Pack? Can't find info about that on ruby-doc
oh, right! all integers are native endian. You can specify big endian with > and little endian with <
Marshal.dump uses native endian..?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.