-
Notifications
You must be signed in to change notification settings - Fork 5
Server Setup
The Monkey-Netty server was build on Netty.IO. The server is designed as an jMonkeyEngine AppState, and is fully self contained. The server will create both a TCP and UDP server on their own threads to listen for connections from the clients. It has features built in for things like SSL, connection limits/blocking, and listeners. The server will manage all the client connections for you, while giving you the flexibility to use those clients as you wish in your code.
To get a simple NettyServer
running, you will create the server, and attach it to your jMonkeyEngine server app.
public class JmeTestServer extends SimpleApplication {
@Override
public void simpleInitApp() {
NettyServer server = new NettyServer("test", 10000);
stateManager.attach(server);
}
public static void main(String[] args) {
JmeTestServer server = new JmeTestServer();
server.start(JmeContext.Type.Headless);
}
}
In this example, we are creating a server with the service name test
and listening on port 10,000. This server is now ready to accept connections, although we are not currently doing much with those connections.
To utilize the functionality of the server and gain access to the clients, the server has listeners. Currently two types of listeners are supported: ConnectionListener
and MessageListener
You can have as many of each listener as you would like, and can register or unregister them at any time.
The ConnectionListener
will listener for clients to connect and disconnect. To add a connection listener, simply register one with the server:
public class JmeTestServer extends SimpleApplication {
@Override
public void simpleInitApp() {
NettyServer server = new NettyServer("test", 10000);
server.registerListener(new ConnectionListener() {
@Override
public void onConnect(NetworkClient client) {
System.out.println("Client connected: " + client.getAddress());
}
@Override
public void onDisconnect(NetworkClient client) {
System.out.println("Client disconnected: " + client.getAddress());
}
});
stateManager.attach(server);
}
public static void main(String[] args) {
JmeTestServer server = new JmeTestServer();
server.start(JmeContext.Type.Headless);
}
}
You can now see that you have access to the NetworkClient
that has connected to the server. The NetworkClient
is your connection to each client session, and will allow you to access information about the client, send messages to the client, and add custom message logic to each client.
There are times when you want to perform a certain action when the server receives a message, in fact, this is perhaps the purpose of having a network server. The MessageListener
will listen for messages from the client, and notify you what message was received, and by which client. This is where most of your network logic will live.
We can simply register a MessageListener
with the server:
public class JmeTestServer extends SimpleApplication {
@Override
public void simpleInitApp() {
NettyServer server = new NettyServer("test", 10000);
server.registerListener(new MessageListener() {
@Override
public void onMessage(NetworkMessage msg, NetworkServer server, NetworkClient client) {
System.out.println("Got message " + msg.getName() + " from client " + client.getAddress());
System.out.println(msg.toString());
client.send(msg);
}
@Override
public Class<? extends NetworkMessage>[] getSupportedMessages() {
return new Class[] {TestUDPMessage.class, TestTCPMessage.class};
}
});
stateManager.attach(server);
}
public static void main(String[] args) {
JmeTestServer server = new JmeTestServer();
server.start(JmeContext.Type.Headless);
}
}
In this example, we created a listener that will listen for a message, print the message name and the address of the client that sent it to us, then sends the message back to the client. You will notice that the listener has the function getSupportedMessages()
, this acts as a filter for what type of messages the listener will receive.
The server also has some other built in features that are useful for simple apps.
You may want to prevent incoming connections until you app is ready. In which case, you can enable connection blocking at any time to prevent incoming connections.
public class JmeTestServer extends SimpleApplication {
@Override
public void simpleInitApp() {
NettyServer server = new NettyServer("test", 10000);
server.setBlocking(true);
stateManager.attach(server);
... some app init logic
server.setBlocking(false);
}
public static void main(String[] args) {
JmeTestServer server = new JmeTestServer();
server.start(JmeContext.Type.Headless);
}
}
Most servers will want to limit the number of clients that can connect to the server. In which case, we can set the connection limit.
public class JmeTestServer extends SimpleApplication {
@Override
public void simpleInitApp() {
NettyServer server = new NettyServer("test", 10000);
server.setMaxConnections(20);
stateManager.attach(server);
}
public static void main(String[] args) {
JmeTestServer server = new JmeTestServer();
server.start(JmeContext.Type.Headless);
}
}
Here we set the max number of clients to 20.
You can check the number of connections on the server and implement custom limiting/blocking logic.
public class JmeTestServer extends SimpleApplication {
@Override
public void simpleInitApp() {
NettyServer server = new NettyServer("test", 10000);
server.setMaxConnections(20);
server.registerListener(new ConnectionListener() {
@Override
public void onConnect(NetworkClient client) {
//Reserve 5 connections for internal network
if (server.getConnections() >= (server.getMaxConnections() - 5) && !client.getAddress().startsWith("192.168")) {
client.disconnect();
return;
}
System.out.println("Client connected: " + client.getAddress());
}
@Override
public void onDisconnect(NetworkClient client) {
System.out.println("Client disconnected: " + client.getAddress());
}
});
stateManager.attach(server);
}
public static void main(String[] args) {
JmeTestServer server = new JmeTestServer();
server.start(JmeContext.Type.Headless);
}
}
Here we set the max number of connections to 20, but in our connection listener we check the number of connections, and if the connections are larger than five less than the max, we only allow connections from our local network.
The server contains an internal logger for debugging. You can enable and disable it.
public class JmeTestServer extends SimpleApplication {
@Override
public void simpleInitApp() {
NettyServer server = new NettyServer("test", 10000);
server.setLogLevel(LogLevel.DEBUG);
stateManager.attach(server);
}
public static void main(String[] args) {
JmeTestServer server = new JmeTestServer();
server.start(JmeContext.Type.Headless);
}
}
The server also supports SSL on the TCP channel. This allows for sending sensitive information such as users' username and password. You can use self signed certificates that are auto generated by the server, or specify a specific certificate for the server to use.
Here is a simple self signed example:
public class JmeTestServer extends SimpleApplication {
@Override
public void simpleInitApp() {
NettyServer server = new NettyServer("test", true, 10000);
stateManager.attach(server);
}
public static void main(String[] args) {
JmeTestServer server = new JmeTestServer();
server.start(JmeContext.Type.Headless);
}
}
Here you will notice an additional parameter set to true
in the NettyServer
constructor. This enables SSL, and if set to false SSL will be disabled. SSL can only be enabled or disabled during the creation of the server. You can check the SSL status by using server.isSsl()
, as the server will fallback to non-ssl if it fails to load a certificate.
The server has two more ssl constructors:
public NettyServer(String service, boolean ssl, File cert, File key, int port)
private NettyServer(String service, boolean ssl, boolean selfGenCert, File cert, File key, int port)
You can use these to pass a certificate to the server, and specify if it should fallback to a self generated certificate.
If using SSL, you will need to tell the client using the client's constructor:
NettyClient client = new NettyClient("test", true, 10000, "localhost");
The client also contains a constructor to disable self signed certificates:
public NettyClient(String service, boolean ssl, boolean sslSelfSigned, int port, String server)