Get up to 80 % extra points for free! More info:

Lesson 8 - Java Server - Communication Protocol

Today we're going to design a protocol that the client and server will use to communicate. So far we have been sending text messages, but unknowingly we used to send a complete object, not just text. We were able to send text because the String class can be serialized and sent over the network.

Sending Objects

Java has the ability to send entire objects over the network. We'll use this feature to implement our communication protocol. We use ObjectInputStream and ObjectOutputStream classes to send and receive objects. All objects to be sent must contain the serialVersionUID constant. This is a unique number according to which objects will be rebuilt on the other side of the line. Usually the IDE has the option to generate this number. In addition, all of these objects must implement the Serializable interface. This is only a markup interface, so it doesn't require any methods to be implemented. It's information to JVM that such objects can be serialized and sent over the network.

Communication Protocol

All the classes we're going to create will be in the share module. This is to make them accessible for both client and server modules. In the share module, in the src/main/java/ folder, create a package that represents the whole project, in my case it's: cz.stechy.chat. In this package, create a net.message package to hold all classes for the client-server communication. In this package, we'll create an IMessage interface to represent the message itself. We'll let the interface be inherited from Serializable so that we don't have to implement it in concrete classes and be sure that the class can be sent through ObjectOutputStream.

public interface IMessage extends Serializable {
    String getType();
    Object getData();

    default boolean isSuccess() {
        return true;
    }
}

The interface contains three methods:

  • getType() - returns the message type; each type will by represented by one class
  • getData() - returns the data that the message carries
  • isSuccess() - Whether the requested action performed correctly or failed

We'll create a simple implementation of the IMessage interface to be able to send text messages again:

public class TextMessage implements IMessage {
    public static final String MESSAGE_TYPE = "text";
    private final String data;

    public TextMessage(String data) {
        this.data = data;
    }

    @Override
    public String getType() {
        return "text";
    }

    @Override
    public Object getData() {
        return data;
    }
}

Protocol Implementation

Since we've defined the base class that we'll send over the network, we need to replace the code where we send or receive Object data to the IMessage data type.

The interfaces where we have to change the data type are:

  • IClient
    • void sendMessageAsync(IMessage message);
    • void sendMessage(IMessage message) throws IOException;
  • IWriterThread
    • void sendMessage(ObjectOutputStream writer, IMessage message);

Also modify the implementation of these methods in the corresponding classes according to the interfaces.

In the Client class it's necessary to update the message receiving:

IMessage received;
while ((received = (IMessage) reader.readObject()) != null) {}

Now we no longer accept the Object class, but the IMessage interface. The type casting is appropriate here, because our protocol is based on the idea that all the objects we send will have a common interface - IMessage.

In the ClientDispatcher class we have to modify the message sending using the TextMessage class:

client.sendMessage(new TextMessage("count: " + count));

Functionality Test

Finally, let's see if our work has been successful so far and test whether the server is able to communicate with the client.

In the client module we'll create the corresponding package again and a SimpleClient class in it. The class will have only a main() method to establish a connection to the server, send data, wait for a response, and end the connection:

public class SimpleClient {
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket("localhost", 15378);
        Thread.sleep(1000);
        ObjectOutputStream writer = new ObjectOutputStream(socket.getOutputStream());
        writer.writeObject(new TextMessage("Hello from client."));
        writer.flush();
        ObjectInputStream reader = new ObjectInputStream(socket.getInputStream());
        System.out.println(((IMessage) reader.readObject()).getData().toString());
        socket.close();
    }
}

Start the server first and then the client. The result should be a "Hello from client" message.

That would be all for today's shorter lesson.

Next time, in Java Server - Event bus, we'll implement a simple event bus.


 

Previous article
Java Server - Writing Thread
All articles in this section
Server for Client Applications in Java
Skip article
(not recommended)
Java Server - Event bus
Article has been written for you by Petr Štechmüller
Avatar
User rating:
1 votes
Activities