Monkey Netty: Server-Client communication system for JME using Netty.IO

Hello,
For my Outside Engine I built a server-client communication system using Netty.IO for JME. Upon request, I have stripped it out of the Outside Engine, and created a standalone project for it.
You can find the source here: GitHub - tlf30/monkey-netty: A implementation of a server-client communication system for jMonkeyEngine using Netty.IO that utilizes both TCP and UDP communication.
You many notice that some things are structured odd, this is because this code came from the OutsideEngine, and had a supporting system underneath it that I had to strip out. I have tested this standalone system using the test I provided in the repo, but if you find any bugs please let me know so I can correct them. By adapting this for use without the Outside Engine I had to change some of the key network logic, so there may be bugs that I did not catch.

@oxplay2 this is the netty.io implementation we were talking about over PM.

Please let me know if you have any questions, and feel free to use this in your projects.

11 Likes

Thanks, first i will need investigate it more, didnt knew UDP require so much code when using Netty.

i have many questions like why need udp salted hash(instead Netty SSL code), why own connection limits were implemented,

also Like everywhere is ObjectEncoder and ObjectDecoder - default Netty classes
but in Client, in UDP only, there is DatagramPacketObjectDecoder. I understand it had reason that i need time to investigate to understand all.

i will need decide if just use this repo and contribute or pull only some changes into what i have now.(you probably anyway use OutsideEngine one i belive)

In any case you help me a lot, thanks! :slight_smile:

1 Like

Hello @oxplay2, yes, your are absolutely correct, there were reasons behind all of those questions. Here we go:

  • The UDP code is for allowing each client to have its own UDP connection. Netty does not really have a method for doing individual connections to clients for UDP, so I pieced on together.
  • I did not use the netty connection limits because in Outside we log which connections we reject and why, and I also do not reject connections for administrators. In order to add custom rules for when we reject due to connection limits I added my own limiter logic, which had to get modified when removing it from Outside.
  • The UDP salted hash is just for a key when establishing the connection. The key is sent to the client over tcp and the client to establish the udp connection must provide the correct key. This was for the server to know which UDP connection to relate to which tcp connection. Nothing to do with SSL/encryption. It could have also been implemented as a random number, it was a hash to prevent collisions, but it is only relevant for a very short time frame.
  • For the DatagramPacketObjectDecoder it is due to how Netty UDP client works. It receives an envelope, and the default ObjectDecoder does not understand the envelope, so instead of trying to decode the object in the envelope, it tries to decode the envelop itself and crashes. Server side does not have this issue because it is using my implementation of the UDP server which just deals with normal objects like the Netty TCP server does.

Although netty supports bandwidth monitoring and limiting, along with SSL, in this repo these features are not present. They are on my issue board for things to implement in outside, but I have not gotten to them yet. From what I have read it would be easy to do.

Feel free to submit issues or pull requests. I will update this as I update the implementation in Outside, just like my PhysicsSync repo which is also a modified version of code from Outside.

EDIT: Also checkout this netty issue on the matter, I have several good links posted there for reference that I used in my design. Feature Request: udp server with netty: create a channel for each remote address · Issue #344 · netty/netty · GitHub

1 Like

Thanks for explain. That tell much. Sounds like perfect solution for now.
looks like we would really need follow netty github issue you provided. (it would change much and is reason of it all)

can i have one simple request?

Could you remove:
image

and add “.gitignore” like:

.idea/
.shelf/
/.gradle/
/.gradle/*
/.nb-gradle/
/.nb-gradle/*
/build/*
/build/**/
.nb-*
.class
nbproject/private/

bin/
libs/
build/
.gradle
.gradletasknamecache

or some “clever one” that will “not track” all local workspace trash :wink: (could use similar to jmonkeyengine/.gitignore at master · jMonkeyEngine/jmonkeyengine · GitHub)
thanks!

2 Likes

Yes, I will add a gitignore, i forgot!

1 Like

This now has a store page (with a terrible picture): https://store.jmonkeyengine.org/929c156b-3b0e-42c7-8474-f6c58ed8a1d5

1 Like

yes, will need replace picture later, hehe.(current one is hypnotic!) Maybe i will try prepare something later.

@tlf30 i suppose we can use their logo(since it seems to be official logo Logo design offer · Issue #7850 · netty/netty · GitHub), but not sure if can use mixed one, anyway i prepared something that merge both JME and Netty logos:

hope its fine.

4 Likes

Oh, I like that! Good Job!
The store requires 1280x720, can you resize it, or should I stretch it?

moment, will provide 1280x720

1 Like

later i will push xcf(editable version - GIMP) into repo.

here is 1280x720

3 Likes

Awesome, thank you! I have submitted the changes to the store page.

1 Like

Approval of the change is delayed pending resolution of issue 9.

2 Likes

Necro!
Anyway, I’ve been looking at this recently, and I’ve found the appstate-based architecture and the message cachine and SSL features quite intriging. However, I’m not seeing anything as far as RPC and RMI go. Is this something you might pursue in the future? Granted, Spider Monkey’s RPC and RMI documentation is incredibly sparse, but they are useful once you find the right examples.

@tlf30 will explain better.

Im not RMI/RPC definition specialist, for me its just like lower api is RPC while Netty object send protocol itself is like RMI. Netty by default work only over TCP protocol.

But will explain some points that maybe something will help you:

  • Generally Monkey-Netty is just Wrapper for Netty, so it used ready2use solutions from there while adding UDP/etc features.
  • Netty uses JNI but it also can use direct java NIO depending if system support JNI solutions. (its ofc faster to use JNI ones) so its not like it always uses the same way. (for example in Linux systems it can use JNI, while API is still the same)
  • Netty itself is pipeline based, where each side client/server work on specific procedural message order-based-processors processing.
  • Default Netty do not require overhead in connection initializing, while in Monkey-Netty due to UDP need to manage connection via TCP protocol first.(to initialize UDP hash)
  • Data processing is based on first bytes (message type of object to deserialize)
  • Tho Netty itself allow for direct byte sending, Monkey-Netty work based on Object (MessageInterface) way. (based on Netty ObjectEcho example)
  • You need to provide predefined Messages that Client/Server work on, while Messages(objects) have versioning itself, it still require update on both sides.
  • Netty work based on non-blocked master/worker thread system, so here Message(object in MN) is passed as parameter and allow non-blocking processing in worker thread (when Java thread queue allows).
  • Lets say we send HelloWorld object that return “HelloWorld” string, MN use Netty pipeline to encode message on sender side and decode it on receiver side. At the end of pipeline(ofc both client/server) there are User API processor that allwo user to interact with ready-processed message, so you just got Object here to use. Its also executed within worker state to allow non-blocking execution.
  • Client/Server do not have shared memory, the only thing they share is UDP hash.
  • Server have no memory
  • Client have message memory, just to allow request send message before connection is initialized.
  • SSL feature is directly used via Netty SSL feature (TCP ofc)

default TCP is enhanced version from Netty wiki:
https://netty.io/wiki/
Monkey-netty uses “Binary protocols → ObjectEcho”

while UDP is custom design.

3 Likes

That was a fantastic explication @oxplay2.

At this point in time Monkey-Netty does not support RMI, many developers stray away from RMI due to security concerns, it can be said that it is much safer to have complete control over what code it being executed server and client side by receiving messages and processing them. With that said, many modern libraries that support RMI have great security mechanism built in to overcome such security concerns.

Right now I do not have any plans to add RMI, but I also am not using RMI in any of my projects so I just have not considered it yet. Feel free to open an issue on the github repo for adding RMI.

Until I get around to adding it our of the box, a simple way to accomplish RMI would be to create a RMI message, then have a message listener that could process it. For example (disclaimer, I’m writing this code on the fly, may not be syntactically correct)

public class RmiRequestMessage implements NetworkMessage {

    public String className;
    public String functionName;
    public Object[] arguments;
    public long callId;

    public String getName() {
        return "rmi-message";
    }
}
public class RmiResponseMessage implements NetworkMessage {

    public Object returnObject;
    public long callId;

    public String getName() {
        return "rmi-message";
    }
}

Then your message listener can receive the RmiRequestMessage message, using reflection run the correct function, then send a RmiResponseMessage back to the other side with what was returned from the call. The callId is important as on the other side you will need to wait for a message with the correct callId to know you have the correct response, you will just need to create unique callIds for each request.

Feel free to play with this idea, there are many ways one could implement RMI. If you get a working system in place, feel free to open a PR and we can talk about getting it added as a supported feature.

2 Likes