Download code here
This is the third post in the series which I am writing about network programming in a few different languages and frameworks. In this post I will be creating the base send and receive you would expect to see from the basic client server model. I have left the send parameter as a byte array as in future posts I will be creating different handlers for different types of messages being sent. In up coming posts I want to make a client which can be server agnostic and simply rely on the sub net to pulse for accepting clients. For now though, I have created a simple, working example of a client server environment.
Earlier posts I have done in this series can be found below:
- Part 1 : Socket Programming with C#, JAVA, C++ and Action Script 3.0 – Establishing a base connection and communication with C# Server and AS3
- Part 2 : Socket Programming With C#, JAVA, C++ and Action Script 3.0 – WCF : Establishing a call-back for use in a client server environment
In the first post in the series I did touch slightly on establishing a socket connection with Action Script 3 so this post will bring a third language to the table being Java. In the second post, I was still using C# but together with the Windows Communication Foundation and the NetTcpBinding.
For this example also, I have put together another simple implementation of the Model View Presenter for the user interface. I wanted the view and the model to be ignorant of any implementing classes. Both emit events and both are known to the presenter.
NetBeans
The environment I have used to dev this example is NetBeans IDE which I have to say I really like. On a day to day basis I work with Visual Studio, which I also feel is a great IDE but I would seriously have to sit down and have a good think to decide which I preferred. One of the tools which I have used is the UML plugin, which after I had prototyped, built, went back to the drawing board, repeated and built again, I used to reverse engineer the project and provide a nice UML Class Diagram with. Below is the classes which are responsible for the network communication and underneath that, the diagram displaying the user interface code.
The Network Communication Classes

The User Interfaces Classes

The Event Model in Java
Slightly different in its implementation from C# the Java Event Model relies on the creation of interfaces which define events that a subscriber of events has to implement if it wants to be notified by the object which raises such events. The way it would raise any event is simply looping through the subscribers and invoking the method on it, which it can safely do so as it will identify the subscribers by its contract/interface.
For example, in the network communication classes above, I have a Receiver object and this can raise two types of events being:
- When it receives data
- When it loses the connection due to the remote connection being closed.
So with this in mind I need to create an interface which will provide me with this assurance.
public interface IReceiverEventListener extends EventListener {
void onDataReceived(byte[] data);
void onConnectionLost();
}
Another note which I should bring up here is that I implement this interface on both the subscriber and the class which emits the event. I could have created a separate interface I suppose call IReceiverEventInvoker – but the difference is that the class which raises the events will use the above methods to loop through its subscribers and invoke the method on them, the subscribers will use the above method to actually handle the event. To the class which raises the event, this method is like a proxy to all the other subscriber events. Here is how the implementation of the onDataReceieved method looks like on the class which raises the events.
public void onDataReceived(byte[] data) {
for(IReceiverEventListener listener : _listeners.getListeners(IReceiverEventListener.class)){
listener.onDataReceived(data);
}
}
Blocking and Looping
Although in my first post with the C# example, I have not used any while loops, and instead gone with the asynchronous programming model, under the covers, it will be doing that very thing, as you have to maintain a connection to an endpoint in order to communicate with it. In this code on both the server and the client code I have used a while loop to continually listen for connecting clients and also for the client to continually listen for incoming data from the server.
The blocking comes from the the call to the read method on the InputStream. While there is data to read the while loop allows the process to continue until it has read all of the incoming data, and when finished the while loop again allows the read method to be called and block until it is ready to read again.
The following is the Receiver class which I have created as I need the receiving of data on a client to be done on a separate thread, so I can handle other functions like sending data without worrying about blocking or waiting for each other.
public class Receiver implements Runnable, IReceiverEventListener {
private Socket _socket;
private BufferedInputStream _inputStream;
private ByteOutputStream _stream;
private EventListenerList _listeners;
public Receiver(Socket socket) throws IOException{
_socket = socket;
_inputStream = new BufferedInputStream(_socket.getInputStream());
_listeners = new EventListenerList();
}
public void run() {
while(true){
try {
byte[] buffer = new byte[1024];
int read = 0;
read = _inputStream.read(buffer, 0, 1024);
_stream = new ByteOutputStream();
if(read == -1){
onConnectionLost();
}else if(read < 1024){
_stream.write(buffer, 0, read);
onDataReceived(_stream.toByteArray());
}else{
_stream.write(buffer, 0, read);
}
} catch (IOException ex) {
Logger.getLogger(Receiver.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void onDataReceived(byte[] data) {
for(IReceiverEventListener listener : _listeners.getListeners(IReceiverEventListener.class)){
listener.onDataReceived(data);
}
}
public void onConnectionLost() {
for(IReceiverEventListener listener : _listeners.getListeners(IReceiverEventListener.class)){
listener.onConnectionLost();
}
}
public void addEventListener(IReceiverEventListener listener){
_listeners.add(IReceiverEventListener.class,listener);
}
public void removeEventListener(IReceiverEventListener listener){
_listeners.remove(IReceiverEventListener.class,listener);
}
}In the above code, specifically inside the while loop, there are three outcomes which I am interested in:
- If the connection has ended between the client and server
- If the final piece of the data is being read
- If the data read is part of the entire transmission
As I collect the data I write it to an output stream so at the end of the transmission I can then trigger events with the entire data received. I have made a buffer of 1024 in length, just for the purposes of example. There is a balance to be had on the amount of data to be sent and the bandwidth available to send it on.
The implementing class of this receiver is the Client class, which when started will kick off the Receiver in a separate thread, first having added itself to its listeners, so it can act of data being received or the connection being lost. This class has two uses, the first being that it will be used by clients to connect to a server and the second is that when the server accepts a connection it will create an instance of this class on a separate thread to represent the client and enable communication between it and the client.
public class Client implements Runnable, IReceiverEventListener, IClientEventListener {
private String _ip;
private int _port;
private Socket _connection;
private Receiver _receiver;
private EventListenerList _listeners;
private String _name = "Server Client";
public void set_Name(String value)
{
_name = value;
}
public String get_Name(){
return _name;
}
public Client(Socket connection) {
this(connection.getInetAddress().getHostAddress(),
connection.getPort());
_connection = connection;
}
public Client(String ip, int port) {
_ip = ip;
_port = port;
_listeners = new EventListenerList();
}
public void run() {
try {
System.out.println("Client started");
if (_connection == null || !_connection.isConnected()) {
_connection = new Socket();
_connection.connect(new InetSocketAddress(_ip, _port));
}
_receiver = new Receiver(_connection);
_receiver.addEventListener(this);
new Thread(_receiver).start();
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void onDataReceived(byte[] data) {
onClientDataReceived(data);
}
public void onConnectionLost() {
onClientDisconnected(this);
}
public void addEventListener(IClientEventListener listener){
_listeners.add(IClientEventListener.class,listener);
}
public void removeEventListener(IClientEventListener listener){
_listeners.add(IClientEventListener.class,listener);
}
public void onClientDataReceived(byte[] data) {
for(IClientEventListener listener : _listeners.getListeners(IClientEventListener.class)){
listener.onClientDataReceived(data);
}
}
public void onClientDisconnected(Client client) {
for(IClientEventListener listener : _listeners.getListeners(IClientEventListener.class)){
listener.onClientDisconnected(client);
}
}
public void Send(byte[] data){
try {
_connection.getOutputStream().write(data, 0, data.length);
_connection.getOutputStream().flush();
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
The entire code set can be downloaded from the link above. At present all this application can do is receive connections and data from clients and transmit that data to all other connected clients.
The server code shown below, is what handles the client connection and also the distribution of the message to the other connected clients. This is very early stages, so there are many more things I want to add to this, but I thought I would get a nice example of a client server application up for both my own benefit and hopefully so it can help any one else out there.
public class Server implements IClientEventListener, Runnable {
private ServerSocket _socket;
private ArrayList<Client> _clients;
private int _port;
public Server(){
_clients = new ArrayList<Client>();
}
public void listen(int port) throws IOException{
_port = port;
new Thread(this).start();
}
public void onClientDataReceived(byte[] data) {
for(Client client : _clients){
client.Send(data);
}
}
public void onClientDisconnected(Client client) {
System.out.println("Client disconnected");
}
public void run() {
try {
System.out.println("Listening");
_socket = new ServerSocket();
_socket.bind(new InetSocketAddress(_port));
while (true) {
Socket clientSocket = _socket.accept();
Client newClient = new Client(clientSocket);
newClient.addEventListener(this);
_clients.add(newClient);
new Thread(newClient).start();
}
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Finally for the purposes of this demo I wanted a simple interface for the chat client and similar to popular IM programs now, I simply need a text area to type into, a text area to display messages and a button to send. Like I have said above though I wanted the view to be ignorant of anything outside of it, so the interfaces to the presenter and the view are shown below.
public interface IChatClientPresenter {
void setView(IChatClientView view);
void handleChatSent();
void handleChatReceived(byte[] data);
}
The actual view interface.
public interface IChatClientView{
void addChat(String text, String from);
void addChatListener(IChatEventListener listener);
void removeChatListener(IChatEventListener listener);
String getChatText();
void clearChatText();
}
The listener interface for the client.
public interface IChatEventListener extends EventListener {
void onChatSent();
}
Extensibility and Transport
To take this to the next level I want to be able to add attributed data to the data sent, in a way wrapping the data into custom containers and chunking the transmission. If we think about extensibility and passing information around to multiple types of clients, we could immediately think of web services. So along this line I want to use SOAP as the container and send these. This will allow me to create custom message classes and extend each with different handlers and confidently send these across the wire and may be create handlers for the messages which the receiving client will resolve upon de-serialization. If the message cannot be de-serialized then it can simply fall through to a default handler.
So to the next post in the series and hopefully in a few more maybe a client working on a similar basis for the android platform.
Cheers for now,
Andrew