Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

How to create a java Socket Server

Junior Spellweaver
Joined
Dec 30, 2009
Messages
114
Reaction score
36
I have stated that maplestory development is dead
so i might aswell feed you something to learn
The login/world system from odinms is coded horribly.
It can be done much more efficient, and clean

I will, in this guide, teach you how to create a simple server socket on which you can listen for connections/data

Ok, first thing you need is a main class (assuming you have already created a new project)

i call it main.java

This is where you start your project with:

PHP:
public class main {

    public static void main(String[] args) {
        //nothing yet
    }
}

This way the jar file knows what to execute when being ran

Now, working with stuff in the main function is BAD, so what we do is create a constructor for the main class

PHP:
public class main {

    public static void main(String[] args) {
        new main(); //yay execution :D
    }

    public main() {
        //still nothing yet :(
    }
}

This is how you start most likely every java project you will make from now on.

Anyways, let's get to the server part.

To start a simple server you will need
PHP:
new ServerSocket(-port-);

In this case i will show how to start a server on a random port,
port 5123

PHP:
public class main {

    final static int port = 5123; //hurray for final static integers :)
    private ServerSocket serverSocket = null //o_o what is this?

    public static void main(String[] args) {
        new main(); //yay execution :D
    }

    public main() {
        serverSocket = new ServerSocket(port);
    }
}

Ok, if you're testing this example, you will see that it will not work, for a couple of reasons.

1) You haven't included the correct classes yet
2) ServerSocket operates on IO, so it might throw an exception

Don't worry, it's fixed in the next example

PHP:
import java.io.*;
import java.net.*;
import java.net.Socket;

public class main {

    final static int port = 5123; //hurray for final static integers :)
    private ServerSocket serverSocket = null //o_o what is this?

    public static void main(String[] args) {
        new main(); //yay execution :D
    }

    public main() {
        try {
            serverSocket = new ServerSocket(port);
        } catch (IOException e) {
            System.out.println("Could not listen on port: " + port);
            return;
        }
        System.out.println("Server is listening on port: " + port); //hurray!
    }
}

Okay this is all good and stuff, you have a running server!
But what if someone tries to connect to your server? Nothing will happen
This is why Sockets have a genious feature called accept()
it accepts an incoming connection :) easy rite?

PHP:
Socket s = serverSocket.accept();
(note that this might throw an IOException again)

But, we don't want to accept just 1 connection, we want to accept all incoming connections, after all we're making a server for multiple users. rite? :)
A simple while loop can do this

PHP:
while (serverSocket.isBound()) {
    try {
        Socket s = serverSocket.accept();
        System.out.println("Incoming connection from " + s.getLocalAddress().getHostAddress() + " on port " + s.getPort());
    } catch (IOException e) {
        System.out.println("Incoming connection could not accept");
    }
}

Ok the incoming connection gets handled with this,
but it doesn't do anything yet, which is quite sad :(

So, let's create a thread for each connection now,
that way we can actually do something, and send/receive data. Which is essential
To create a thread, you just need 'new Thread(-function to start the thread with-);

Time to create a new class
i called it 'Client.java' (Which isn't totally true, but eh)

PHP:
import java.net.*;
import java.io.*;

public class Client extends Thread {

    private Socket socket;
    private String socketip;
    private int socketport;

    public Client(Socket socket) { //constructor
	this.socket = socket;
        this.socketip = socket.getInetAddress().getHostAddress();
        this.socketport = socket.getPort();
    }

    @Override //because we override a function from our super class, Thread
    public void run() {
        // do stuff here
    }
}


Ok now remember this?
We can start a thread in it now

PHP:
while (serverSocket.isBound()) {
    try {
        Socket s = serverSocket.accept();
        System.out.println("Incoming connection from " + s.getLocalAddress().getHostAddress() + " on port " + s.getPort());
        Client c = new Client(s); //new thread :)
        c.start(); //the thread starts, meaning it executes the run function
    } catch (IOException e) {
        System.out.println("Incoming connection could not accept");
    }
}


Ok this is what we have now.
main.java:

PHP:
import java.io.*;
import java.net.*;
import java.net.Socket;

public class main {

    final static int port = 5123; //hurray for final static integers :)
    private ServerSocket serverSocket = null //o_o what is this?

    public static void main(String[] args) {
        new main(); //yay execution :D
    }

    public main() {
        try {
            serverSocket = new ServerSocket(port);
        } catch (IOException e) {
            System.out.println("Could not listen on port: " + port);
            return;
        }
        System.out.println("Server is listening on port: " + port); //hurray!

        while (serverSocket.isBound()) {
            try {
                Socket s = serverSocket.accept();
                System.out.println("Incoming connection from " + s.getLocalAddress().getHostAddress() + " on port " + s.getPort());
                Client c = new Client(s); //new thread :)
                c.start(); //the thread starts, meaning it executes the run function
            } catch (IOException e) {
                System.out.println("Incoming connection could not accept");
            }
        }
        // not bound (meaning the corresponding port refuses connection) anymore? let's close it
        try {
            serverSocket.close();
        } catch (IOException e) {
            System.out.println("ServerSocket could not be closed");
            // Should never occur ;]
        }
    }
}

and Client.java:

PHP:
import java.net.*;
import java.io.*;

public class Client extends Thread {

    private Socket socket;
    private String socketip;
    private int socketport;

    public Client(Socket socket) { //constructor
	this.socket = socket;
        this.socketip = socket.getInetAddress().getHostAddress();
        this.socketport = socket.getPort();
    }

    @Override //because we override a function from our super class, Thread
    public void run() {
        // do stuff here
    }
}

Time to make the client actually do something, instead of just listening
I will now explain the 2 major things a 'client' like this should do
1) Listen for incoming data
2) Send data

The first one is actually quite simple, but to do so, i will provide a datareader class first. If you developed OdinMS, this should look familiar

DataReader.java:

PHP:
import java.io.IOException;
import java.io.InputStream;

public class DataReader {
    private Client c;
    private InputStream is;

    public DataReader(Client c, InputStream is) {
        this.c = c;
        this.is = is;
    }

    public int readByte() {
        try {
            int data = ((int)is.read());
            return data;
        } catch (IOException e) {
            System.out.println(e.getMessage());
            return -1;
        }
    }

    public boolean readBoolean() {
        return readByte() == 1;
    }

    public short readShort() {
        int data1, data2;
        data1 = readByte();
        data2 = readByte();
        return (short) ((data2 << 8) + data1); // 0000000100000011
    }

    public char readChar() {
        return (char) readShort();
    }

    public int readInt() {
        int data1, data2, data3, data4;
        data1 = readByte();
        data2 = readByte();
        data3 = readByte();
        data4 = readByte();
        return (data4 << 24) + (data3 << 16) + (data2 << 8) + data1;
    }

    public long readLong() {
        long data1 = readByte();
        long data2 = readByte();
        long data3 = readByte();
        long data4 = readByte();
        long data5 = readByte();
        long data6 = readByte();
        long data7 = readByte();
        long data8 = readByte();
        return (data8 << 56) + (data7 << 48) + (data6 << 40) + (data5 << 32) + (data4 << 24) + (data3 << 16) + (data2 << 8) + data1;
    }

    public String readAsciiString(int n) {
        char ret[] = new char[n];
        for (int x = 0; x < n; x++) {
            ret[x] = (char) readByte();
        }
        return String.valueOf(ret);
    }

    public byte[] read(int num) {
        byte[] ret = new byte[num];
        for (int x = 0; x < num; x++) {
            ret[x] = (byte)readByte();
        }
        return ret;
    }

    public void skip(int num) {
        for (int x = 0; x < num; x++) {
            readByte();
        }
    }

    public long available() {
        try {
            return is.available();
        } catch (IOException e) {
            return -1;
        }
    }

    @Override // java.lang.Object.toString() not really needed, but okay....
    public String toString() {
        return is.toString();
    }

    public Client getClient() {
        return c;
    }
}

Okay, we can read data now, lets call the class in Client.java

PHP:
import java.net.*;
import java.io.*;

public class Client extends Thread {

    private Socket socket;
    private String socketip;
    private int socketport;
    private OutputStream out;
    private InputStream in;
    private boolean cont; // continue, or stop

    public Client(Socket socket) { //constructor
        this.socket = socket;
        this.socketip = socket.getInetAddress().getHostAddress();
        this.socketport = socket.getPort();
        this.cont = true;
    }

    @Override //because we override a function from our super class, Thread
    public void run() {
        try {
            out = socket.getOutputStream(); // send data through the outputstream
            in = socket.getInputStream(); // read data through the inputstream

            short header;
            DataReader dr = new DataReader(this, in); // initialise the datareader class
            while (cont) {
                try {
                    header = dr.readShort();

                    System.out.println("Received data from " + socketip + " on port " + socketport + ", header: " + data + ", length: " + dr.available());
                    // now you can do stuff here :)
                } catch (Exception e) {//just to make sure
                    cont = false;
                    System.out.println(e.getMessage());
                }
            }
            try {
                out.close();
                in.close();
                socket.close();
            } catch (IOException e) {
                //nothing, closing anyways
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

There you have it, when a connection opens, it automatically starts to listen for data
i made it read a short, because most of the times a header is a short value. You can ofcourse change this to read something else.

Now onto sending data.
You don't want to send useless data, that's for sure
In this example, i have made a client (not distributing the source of that)
and everytime the client sends the header 22 (16 in hex), the server should send a packet back saying hello, with the header 5.
confusing?
let's go to Client.java and we will see


PHP:
import java.net.*;
import java.io.*;

public class Client extends Thread {

    private Socket socket;
    private String socketip;
    private int socketport;
    private OutputStream out;
    private InputStream in;
    private boolean cont; // continue, or stop

    public Client(Socket socket) { //constructor
        this.socket = socket;
        this.socketip = socket.getInetAddress().getHostAddress();
        this.socketport = socket.getPort();
        this.cont = true;
    }

    @Override //because we override a function from our super class, Thread
    public void run() {
        try {
            out = socket.getOutputStream(); // send data through the outputstream
            in = socket.getInputStream(); // read data through the inputstream

            short header;
            DataReader dr = new DataReader(this, in); // initialise the datareader class
            while (cont) {
                try {
                    header = dr.readShort();

                    System.out.println("Received data from " + socketip + " on port " + socketport + ", header: " + data + ", length: " + dr.available());
                    
                    if (header == 22) // 0x16
                        sendHello();
                } catch (Exception e) {//just to make sure
                    cont = false;
                    System.out.println(e.getMessage());
                }
            }
            try {
                out.close();
                in.close();
                socket.close();
            } catch (IOException e) {
                //nothing, closing anyways
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendHello() {//probably most ugly function ever, well up to you to create something better, i won't spoonfeed you with that ;]
        byte[] packet = new byte[9];//size of hello packet
        packet[0] = 5;
        packet[1] = 0;
        packet[2] = 5;// length of the 'hello' string
        packet[3] = 0;// short is always 2 bytes
        packet[4] = "h".getBytes()[0]; // VERY hacky way, up to you to find something better, i did ;]
        packet[5] = "e".getBytes()[0];
        packet[6] = "l".getBytes()[0];
        packet[7] = "l".getBytes()[0];
        packet[8] = "o".getBytes()[0];
        // ok let's send the packet
        try {
            out.write(packet);// lol easy right? ;D
        } catch (IOException e) {
            System.out.println("Lol duck? " + e.getMessage());
        }
    }
}

As you can see some things are very ugly,
but it's up to you to fix it, since i already know how ;]

Good luck with it, and thanks for reading!
 
Last edited:
Junior Spellweaver
Joined
Dec 30, 2009
Messages
114
Reaction score
36
And guess why i'm taking that purpose away <_<
 
Joined
Aug 10, 2008
Messages
858
Reaction score
516
It actually doesn't matter which library you use, the end functionality is pretty much the same. For mina we have IoAcceptor as the server socket and IoSession as the Socket.

This is a decent tutorial, but I would prefer having the Socket be thrown into a thread once the connection is made to manage the session.

Also the check for if it's bound in the while loop is completely useless because the Server Socket will always remain in tact as long as it isn't tampered with or set to shut down.

You do know that you can do something like this instead:

Code:
import java.net.ServerSocket;
import java.net.Socket;

public class Main {

	private static ServerSocket ss = null;
	private static final int port = 9090;

	public static void main(String[] args) {
            try {
                ss = new ServerSocket(port);
		System.out.println("Connected on port: " + port);
		while(true) {
                    new Thread(new ManageThread(ss.accept())).start();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
	}

	private static class ManageThread implements Runnable {

		private Socket s;
		
		public ManageThread(Socket s) {
                    this.s = s;
		}

                public void run() {
                    System.out.println("Connected with peer: " + s.getInetAddress().toString().replace('/', ' '));
                    // Add IO algorithms here.
                }

	}


}
 
Junior Spellweaver
Joined
Dec 30, 2009
Messages
114
Reaction score
36
That's what i've done, but i haven't finished the tutorial yet
i will finish it now
 
Joined
Aug 10, 2008
Messages
858
Reaction score
516
That's what i've done, but i haven't finished the tutorial yet
i will finish it now

Actually you just created a whole new object just to handle a couple lines of code which is pretty much a waste of time and a couple bytes of memory lost. Since you decided to create the object you do not need to have the port as a static variable anymore since it's being referenced from a non-static context.
 
Last edited:
Junior Spellweaver
Joined
Dec 30, 2009
Messages
114
Reaction score
36
Actually you just created a whole new object just to handle a couple lines of code which is pretty much a waste of time and a couple bytes of memory lost. Since you decided to create the object you do not need to have the port as a static variable anymore since it's being referenced from a non-static context.

I use this way myself too,
and because i call the port from other classes too, it's static
but you are absolutely right, it doesn't have to be static.
It's just the way i did it.

Also the tutorial still isn't finished
 
Junior Spellweaver
Joined
Dec 30, 2009
Messages
114
Reaction score
36
The port can only be used for one Server Socket.

So? That has nothing to do with this
Look, i'm not telling what i use the port for,
just assume that i do use it for something else

want me to edit my guide, just for you? ...
 
Experienced Elementalist
Joined
Mar 28, 2009
Messages
239
Reaction score
38
It takes away the purpose of using MINA xD.

What on earth are you talking about.
That's like saying the collection/map classes take away the purpose of using trove or javolution.
 
Last edited:
Junior Spellweaver
Joined
Jul 6, 2008
Messages
104
Reaction score
15
You do know by using this method and further expanding it, you can make it operate just like Mina-core? If you have ever decompiled mina-core, and took a look at one of their files like in the NIO socket folder, it will display the usages of ServerSockets. Mina-Core is just basically an easier way to operate the sockets. So therefore, by replacing mina-core with server sockets in private servers, it could lead to bigger uses or it could just make it like the usual mina-core lol.

Note: Any more of the tutorial? xD. Like, when in each thread you will implant a DataOutputStream and a DataInputStream so that you can send/recieve?
 
Last edited:
Experienced Elementalist
Joined
Mar 28, 2009
Messages
239
Reaction score
38
You do know by using this method and further expanding it, you can make it operate just like Mina-core? If you have ever decompiled mina-core, and took a look at one of their files like in the NIO socket folder, it will display the usages of ServerSockets. Mina-Core is just basically an easier way to operate the sockets. So therefore, by replacing mina-core with server sockets in private servers, it could lead to bigger uses or it could just make it like the usual mina-core lol.

That's what I'm trying to say, this doesn't defeat the purpose of using MINA. MINA just provides users with a simpler way of using NIO library.
 
Junior Spellweaver
Joined
Dec 30, 2009
Messages
114
Reaction score
36
I don't understand how you could say that mina could possibly use less resources then a simple serversocket
if mina is based on serversocket, and does the same, then the basic function could impossible use more data/resources/memory or W/E then mina itself
idc what you say, i will finish this tutorial (i'm lazy.) and i will use serversockets, instead of mina.

This is to teach people to actually do something instead of just including a library, and call pre-compiled functions
 
Experienced Elementalist
Joined
Mar 28, 2009
Messages
239
Reaction score
38
I don't understand how you could say that mina could possibly use less resources then a simple serversocket
if mina is based on serversocket, and does the same, then the basic function could impossible use more data/resources/memory or W/E then mina itself
idc what you say, i will finish this tutorial (i'm lazy.) and i will use serversockets, instead of mina.

This is to teach people to actually do something instead of just including a library, and call pre-compiled functions

Woops, I only read the first couple of sentences. You're right. It cannot use less memory etc. But it does however pool it's worker/thread objects to allow quicker access (If I remember correctly).
 
Junior Spellweaver
Joined
Dec 30, 2009
Messages
114
Reaction score
36
Okay okay, so you ask me to create a thread pool too, just for some data?
no thanks, it's fine this way, and i don't want it to be more expensive


Btw...
I finished the guide :)
 
Last edited:
Joined
Aug 10, 2008
Messages
858
Reaction score
516
Why make a whole new class for managing I/O of data?

Use DataInputStream and DataOutputStream instead of using a new class, since all you do for that is provide them with the OutputStream and InputStream that comes from the Socket as the parameter. Saves you time and space in the whole project.
 
Junior Spellweaver
Joined
Dec 30, 2009
Messages
114
Reaction score
36
Why make a whole new class for managing I/O of data?

Use DataInputStream and DataOutputStream instead of using a new class, since all you do for that is provide them with the OutputStream and InputStream that comes from the Socket as the parameter. Saves you time and space in the whole project.

I did this for 2 reasons
firstly, all odinms developers are familiar with slea (slea.readByte(), slea.readInt()) which is why i chose to return the old methods of doing something 'you know.
and secondly, does it really matter that much to use a datainputstream, to do something, while i can also provide a class which actually explains how something works.
It really doesn't matter that much now, does it?

Horribly coded.

Hahaha ok why don't you show us a better coded example of the serversocket class?
 
Junior Spellweaver
Joined
Dec 30, 2009
Messages
114
Reaction score
36
Ok, then tell me what's sloppy about it, other then the things i have stated myself.
 
Junior Spellweaver
Joined
Jun 12, 2009
Messages
116
Reaction score
1
what's the point of this o_o; in my opinion, useless. idc if u think otherwise, just my opinion.
 
Back
Top