FAQ 5d
Updated: 1/19/00

>>>>>> How do I use a Socket Server?
====================================

Socket Servers communicate with their clients using the Berkely Sockets API.
These API's have been adopted by both WinSock (Windows Sockets) and Java.  

I'm going to tell you in a general way how sockets work.  I will describe it from 
the Server viewpoint, then the Client viewpoint.  Then I'll show you sample code 
that does exactly what I described.  Here we go:

The Client will create a Socket object.  It then contacts the Server.  Once contact 
is established, the Socket can recieve messages from the Server and send messages 
to the Server.  Once the Client is finished (or the connection is somehow broken), 
the Socket is disconnected and discarded.

The Server will create a ServerSocket object.  The ServerSocket will wait for a Client 
to contact the Server.  It then creates a Socket object that is connected to the Client.  
This Socket is placed into a list of Sockets.  Each Socket object will listen for 
messages from its Client, and can be used to send messages to its Client.  Once the 
Client is finished (or the connection is somehow broken), this Socket is disconnected 
and discarded.


:::::: Client Code Example
==========================

Look at this file for an example Client: ClientSession.java

When you create a ClientSession object you need to know the host and port.

host is a string indicating the network address of the Socket Server.  This can 
be either a domain name (like "www.fiends.com") or an IP address (like "209.125.223.66").
Applets in a browser can get their server name with this line:
server = getCodeBase().getHost();

port is an integer value in the range 0 to 65535.  Numbers below 1024 are reserved for 
use by the system.  The Socket Server will be listening for messages sent to a specific 
port number.  You have to pick this number when designing your applications (it can 
be any number you like).

The ClientSession class extends Thread (see FAQ_3f).  This lets the class continuously check 
for incoming messages.  This has to be done since reading messages blocks processing.  
This means that the program will get stuck at the read() function until a message 
arrives from the Server.

Notice that I send an integer 'size' value before each message.  When you are reading messages 
from a DataInputStream, it looks like one giant string.  You need some way to break this string 
into useful messages.  I like to insert 'size' values so that I can read my messages based on 
their length.


:::::: Server Code Example
==========================

Look at this file for an example Server: ServerSession.java

This example has two classes, NetServer and ServerSession.  NetServer is a thread that 
waits for any Client contact.  ServerSession holds a Socket object and is in contact with 
one specific Client.

When you create a NetServer object you need to know the port.

port is an integer value in the range 0 to 65535.  Numbers below 1024 are reserved for 
use by the system.  The Socket Server will be listening for messages sent to a specific 
port number.  You have to pick this number when designing your applications (it can be 
any number you like).

The NetServer class extends Thread (see FAQ_3f).  This lets it continuously check for new 
Client connections.  This has to be done since the accept() function will block 
processing.  This means that the program will get stuck here until a Client connects.

Notice that the ServerSession class extends Thread (see FAQ_3f).  It does this for the exact 
same reasons that ClientSession extends Thread (see above).

You will see that I put all newly created sessions into a list (Vector).  You HAVE TO DO THIS.
In JAVA, objects only exist as long as some other object holds its pointer.  If I did not put 
the sessions into the list, then they would vanish just as soon as the 'session' variable was 
given a new value.


:::::: Message Handling
=======================

Your Session thread will read a message then respond to it (the respond() function).
Since the Session thread operates independently from your operations thread,
responding directly inside the Session thread might cause problems.  

If your Session thread happens to edit a variable just as the operations thread is 
updating the game, then the operations thread might become confused.  This can ruin 
your game state.

To avoid this I recommend that you save your Session messages into a list.  
Then the operations thread can read the messages from the list.
This way it can respond to the messages itself, preventing problems.

Here is an example of saving the messages into a list (Vector):

// changes to 'ClientSession' or 'ServerSession'
class Session extends Thread {
	void respond(byte buf[]){
		GameApplet.pushMessageQueue(buf);
	}
}


// 'GameApplet' code file
import java.applet.*;
import java.util.*;

class GameApplet extends Thread {

	static Vector messageQueue;

	GameApplet(){
		messageList = new Vector();
	}

	public void run(){
		while (true){
			updateGameState();
			repaint();
			handleMessageQueue();
		}
	}

	static pushMessageQueue(byte buf[]){messageQueue.addElement(buf);}

	void handleMessageQueue(){
	byte[] buf;

		while (true) {
			buf = messageQueue.firstElement();
			if (buf==null) break;
			messageQueue.removeElement(buf);
			handleMessage(buf);
		}
	}
}



:::::: static value
===================

static will share a value with all instances of the class.  That means you can 
access that shared function or variable using the class name.

In our example, we access the pushMessageQueue() function using the class name GameApplet.
This can only work because the messageQueue is also static (shared by the entire class).