Wednesday, March 15, 2017

Java Sockets - Let's build a chat application

Overview of the chat application

What is a socket? 


IP Address + Port number. In Java, socket implements the client socket interface.

How to create a socket in java ? 


Socket socket = new Socket(String serverAddress, String serverPort);


What is a "ServerSocket" in java ? 


ServerSocket sets up a listener to a particular port from which you can accept any number of Socket connections. It implements the ServerSocket interface in java.


How to create a ServerSocket in java ? 


ServerSocket serverSocket = new ServerSocket(Port);

What's the connection between the socket and the server socket ? 


As I have mentioned about, in the client side, you can create a socket with a server ip address and a server port. Once you have created a socket, you can use that socket to transmit and receive  data. In java we use 2 methods to send and retrieve data.
  1. socket.getInputStream() -- Used to retrieve data sent from server
  2. socket.getIOutputStream() -- Used to send data to the server
Next, well look at how the server accepts  the incoming connection requests from clients.
  • listener.accept() -- Listens for a connection to be made to this socket and accepts it.
In simple words, socket is from client side and serversocket is from server side.

Now that we have a basic understanding of what socket and a server socket means. Let's look at how we are going to capture the input and output streams coming through the socket / server socket.

We have plenty of options for this. 

To read Inputs:-
  1. BufferedReader and InputStreamReader - Used to read Strings
  2. DataInputStream - A data input stream lets an application read primitive Java data types from an underlying input stream in a machine-independent way. An application uses a data output stream to write data that can later be read by a data input stream(According to javadoc).
  3. ObjectInputStream - Used to read an incoming object.
To write Outputs:-
  1. PrintWriter - Prints formatted representations of objects to a text-output stream. This class implements all of the print methods found in PrintStream. It does not contain methods for writing raw bytes, for which a program should use unencoded byte streams. (Javadoc)
  2. DataOutputStream - A data output stream lets an application write primitive Java data types to an output stream in a portable way. An application can then use a data input stream to read the data back in. (JavaDoc)
  3. ObjectOutputStream - An ObjectOutputStream writes primitive data types and graphs of Java objects to an OutputStream(JavaDoc).
Basically what we do at client end.

Socket socket = new socket("127.0.0.1", 9000);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getIOutputStream(),true);

At the Server end

ServerSocket serverSocket = new ServerSocket(9000);
serverSocket.accept(); 
//Do something when accepted

Now that we have the client and the server end. How to we actually write data and retrieve data. Let's use a PrintWriter to write data and BufferedReader to read the data.

Reading from the input stream:-
  • String message = in.readLine();
Writing Something into the stream
  • out.println("Your message here");

Where to go from here ? 


Well, there's a long way to go. In a client server application, if you're using the mediator architectural pattern, the client shouldn't  know about the existence of other clients but server should know about all the clients hence server acts as the mediator for all the messages.

Example Scenario :
  1. User connects to the server.
  2. The server accepts the connection serverSocket.accept();
  3. Then the server will send out.println("send_me_your_name");
  4. Then client reads this from String message = in.readline();
  5. Then if(message == "send_me_your_name"){ //send your name}
  6. Server must have a way of storing data, this can be a simple hash map to a database. The server checks whether the name already exists in the data storage and if not, the server will store the name and a newly created unique printwriter in the map. so that you can ask for the print writer of a particular user to output a private message to him.
  7. The server outputs out.println("connection_accepted")
  8. Then client can now message server.
  9. This goes on and on.

This way the client must have a set of protocols and the server must have a set of protocols to handle the messages between the clients.

To create a chat application. You'll need a basic understanding of the threads. Because we need to have a unique thread for each client which connects to the server. 

Some screenshots of the chat application I made for the SLIIT's 3rd year 1st semester distributed Systems lab 1. GitHub Repo
Client App

Server App

Understand the concept well. Then you'll be able to think and write your own client server applications.

To be continued...

13 comments: