Alright! I've figured out how to do this in an efficient way to where the clients can connect and begin transmission to the server program quickly. For all of those who want to try out making an MMORPG, this is actually an easy way to start. Before going through my tutorial, please learn the basics of JAVA or you might get lost (however, you can at least try it out anyway but realize you may become a little lost).
I bet you wanna make the kinds of MMO games she plays all the time right?

Or maybe you just wanna special server and client system for something in particular? Well in JAVA it's much easier than even I thought! Pull up a chair and fire up your programming environment~
There are two JAVA objects in the API that are interesting to us. The ServerSocket and the Socket object. One to accept socket connections from the client and the other to connect to the server. Does it sound too simple? It's is! In fact, you'll run into problems with synchronization way more often than connecting the clients. Let's connect a simple client to a simple server! Compile both programs and run them as two different instances of a program.
import java.net.ServerSocket;
import java.net.Socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class ServerTest
{
private static ServerSocket serverSocket;
private static Socket clientSocket;
private static BufferedReader bufferedReader;
private static String inputLine;
public static void main(String[] args)
{
// Wait for client to connect on 63400
try
{
serverSocket = new ServerSocket(63400);
clientSocket = serverSocket.accept();
// Create a reader
bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// Get the client message
while((inputLine = bufferedReader.readLine()) != null)
System.out.println(inputLine);
}
catch(IOException e)
{
System.out.println(e);
}
}
}
and the client...
import java.net.Socket;
import java.io.PrintWriter;
public class ClientTest
{
private static Socket socket;
private static PrintWriter printWriter;
public static void main(String[] args)
{
try
{
socket = new Socket("localhost",63400);
printWriter = new PrintWriter(socket.getOutputStream(),true);
printWriter.println("Hello Socket");
printWriter.println("EYYYYYAAAAAAAA!!!!");
}
catch(Exception e)
{
System.out.println(e);
}
}
}
Run the server... It looks like it's frozen but it's waiting for a socket from the client to connect. Run the client and it will finish. Take a look at the server program's console... There's your messages followed by an exception generated from the socket from the client disconnecting.
getInputStream() and getOutputStream() will hold the execution there until the client has established an output stream where the server establishes an input stream. Any sort of input or output stream can be created (like an ObjectInputStream). So you can send and receive data in any way you wish doing this. Whatever way is most comfortable to you (or the way you think is easiest to learn) is fine for now.
The parts of interest are the following lines:
socket = new Socket("localhost",63400);
serverSocket = new ServerSocket(63400);
To connect, the target is the local host on the same machine. It could be an IP address for a server if you want to connect over the internet. If you're on a LAN then you can try this on two separate machines. Use the IP of the machine running the server instead of "localhost" to try it out. Also, depending on your network structure, you may be able to do this over the internet with some other user.
But...
How do you connect multiple clients? I mean it is a server, it's got to serve multiple clients! What good is an MMORPG or a chat room with just you in there? You might want to have a loop accepting socket connections and save them in a list to track all the clients... But you'll encounter a problem! For sending, receiving, accepting, and connecting things, they all WAIT until the operation is complete! If you've got someone with a slow connection it will sit there and wait for them to complete the transaction or fail!
Think for a moment. You've got multiple people who want service and some are slower than others, but you gotta satisfy everyone. That is where you multitask! You need parallel operations for ALL clients. And... Thread will do just that for you!
Here's a cutout from my own server program.
import java.net.ServerSocket;
import java.net.Socket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.io.IOException;
import java.util.ArrayList;
/**
* This handles all of the Umbra clients in the room.
* It accepts new connections and adds them to the room.
* It is a runnable thread and when the start method is called, it will accept clients.
*/
public class UmbraRoom extends Thread
{
private static final int UMBRA_PORT = 30480;
private static final int ROOM_THROTTLE = 200;
private ServerSocket serverSocket;
private InetAddress hostAddress;
private Socket socket;
private ArrayList<UmbraUser> users = new ArrayList<UmbraUser>();
/**
* Creates a new Umbra room for clients to connect to.
*/
public UmbraRoom()
{
// Attempt to get the host address
try
{
hostAddress = InetAddress.getLocalHost();
}
catch(UnknownHostException e)
{
System.out.println("Could not get the host address.");
return;
}
// Announce the host address
System.out.println("Server host address is: "+hostAddress);
// Attempt to create server socket
try
{
serverSocket = new ServerSocket(UMBRA_PORT,0,hostAddress);
}
catch(IOException e)
{
System.out.println("Could not open server socket.");
return;
}
// Announce the socket creation
System.out.println("Socket "+serverSocket+" created.");
}
/**
* Starts the client accepting process.
*/
public void run()
{
// Announce the starting of the process
System.out.println("Room has been started.");
// Enter the main loop
while(true)
{
// Remove all disconnected clients
for(int i = 0;i < users.size();i++)
{
// Check connection, remove on dead
if(!users.get(i).isConnected())
{
System.out.println(users.get(i)+" removed due to lack of connection.");
users.remove(i);
}
}
// Get a client trying to connect
try
{
socket = serverSocket.accept();
}
catch(IOException e)
{
System.out.println("Could not get a client.");
}
// Client has connected
System.out.println("Client "+socket+" has connected.");
// Add user to list
users.add(new UmbraUser(socket));
// Sleep
try
{
Thread.sleep(ROOM_THROTTLE);
}
catch(InterruptedException e)
{
System.out.println("Room has been interrupted.");
}
}
}
}
import java.net.Socket;
import java.io.IOException;
import java.io.ObjectInputStream;
/**
* This object handles the execution for a single user.
*/
public class UmbraUser
{
private static final int USER_THROTTLE = 200;
private Socket socket;
private boolean connected;
private Inport inport;
/**
* Handles all incoming data from this user.
*/
private class Inport extends Thread
{
private ObjectInputStream in;
public void run()
{
// Open the InputStream
try
{
in = new ObjectInputStream(socket.getInputStream());
}
catch(IOException e)
{
System.out.println("Could not get input stream from "+toString());
return;
}
// Announce
System.out.println(socket+" has connected input.");
// Enter process loop
while(true)
{
// Sleep
try
{
Thread.sleep(USER_THROTTLE);
}
catch(Exception e)
{
System.out.println(toString()+" has input interrupted.");
}
}
}
}
/**
* Creates a new Umbra Client User with the socket from the newly connected client.
*
* @param newSocket The socket from the connected client.
*/
public UmbraUser(Socket newSocket)
{
// Set properties
socket = newSocket;
connected = true;
// Get input
inport = new Inport();
inport.start();
}
/**
* Gets the connection status of this user.
*
* @return If this user is still connected.
*/
public boolean isConnected()
{
return connected;
}
/**
* Purges this user from connection.
*/
public void purge()
{
// Close everything
try
{
connected = false;
socket.close();
}
catch(IOException e)
{
System.out.println("Could not purge "+socket+".");
}
}
/**
* Returns the String representation of this user.
*
* @return A string representation.
*/
public String toString()
{
return new String(socket.toString());
}
}
This will accept Socket connections from a client. It also tries to establish an InputStream with the client. Look closely, notice how I start some threads for every client. The rest of the clients won't be effected when a different client is slow, it won't wait for it. Study carefully on how dead clients are closed and removed and how the threads quit on failure. Now, I purposefully left the threads to run even when the client is removed, but you can see where the connection can fail and where you should make the thread quit (using return is easy).
Lots of exceptions can occur for various reasons, it's important to do what is needed in their case. Try writing a client to connect to this server and connect lots of them. Then make the server remove them when they disconnect.
From here on out, I shouldn't tell you how to establish a stream pair going the other way (from server to client) or what the server and client should do to messages being received. This is because... It varies from what you need! Right in the thread process where you see the InputStream, you can read objects and act upon them, or with the OutputStream you can send objects. It's all up to you now, just be sure to use Threads or your program will sit there and wait, which isn't what you want!
OK, OK, you're losing your attention because you really want to make an MMORPG right?

You can't hide it from me! I'll make a Tutorial for that later when I have time so stick around. I'll get a little deeper in making a networked game with a server (which doesn't really need a and a client (which uses a video panel and everything).
While you wait, I suggest you practice just making the server echo Strings from the client and to periodically send Strings back to the client. If you can do this for multiple clients without errors or having the client or server freeze up and wait, then you're all set for my next tutorial
Some images from Lucky Star (Kyoto Animation)








MultiQuote








|