Understanding Networking and Socket In Java

Understanding Networking and Socket In Java

Hello techies welcome to my blog post for this week, I will be writing about Networking and Socket in Java, for this post I will be doing more coding in explaining the concept of Networking and Socket.

LEARNING OUTCOMES

After going through this post you should be able to have a basic understanding of:

  • Networking (IP address, ports, nodes, etc.)

  • Sockets basics and connection.

let me give a brief summary about Networking and Socket before writing codes...

What is computer networking?- networking could be said to comprise two or more computers connected together either by cables or WiFi for the sole purpose of sending and receiving data and resources. In essence, a set of computers are sharing data and resources being provided by network nodes.

Types of computer networks

Here are a few types of computer networks:

  1. LAN - which is a Local Area Network that connects computers over close proximity e.g. connecting computers over a dormitory or apartments.

  2. WAN - which is a Wide Area Network that connects networks over a wide area. e.g. region to region or from one continent to the other.

  3. MAN - Metropolitan Area Network which is larger than a LAN but smaller than a WAN, is mostly used by government institutions.

  4. VPN - a Virtual Private Network, just as the name implies is a private network that extends over a public network that allows users to send and receive data across shared networks.

What is a Socket?- socket is simply an endpoint for communication between two programs running on a network the Java socket is used to communicate between client and server through the Socket class which can help receive and respond to messages.

So having given a brief summary of computer networking and socket, let's build a group chat application where more than one client can chat within themselves.

First thing first let's create our Server class

package org.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

// Thee server class is responsible for listening to a client who which to connect

public class Server {
    // create a serversocket object that is responsible for listening to in-coming connection from client
    private ServerSocket ss;
    // create a constructor to set up our server socket

    public Server(ServerSocket ss) {
        this.ss = ss;
    }
    // create a method start server that is responsible for keeping our server running
    public void startServer() {
        // we want to keep our server continuously running
        try {
            while (!ss.isClosed()) {
                // wait for a client to connect using the accept method
                Socket s = ss.accept();
                System.out.println("A new user just connected");
                // Client handler class to handle client
                HandleClients handleClients = new HandleClients(s);

                // create a thread object to spawn new threads
                Thread thread = new Thread(handleClients);
                // use the start method to run the thread
                thread.start();

            }
        } catch (IOException e) {
            closeServer();
        }
    }

    // create a method for handling errors to avoid nested try/catches
    public void closeServer() {
        try {
            if (ss != null) {
                ss.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Next, we create a class that handles our clients

package org.server;

import java.io.*;
import java.net.Socket;
import java.util.ArrayList;

public class HandleClients implements Runnable{
    // create a static array list of every client handler object that we have instantiated
    public static ArrayList<HandleClients> handleClients = new ArrayList<>();
    // use the socket to establish connection between the client and the server
    Socket s;
    // use buffer reader to read data that has been sent from the client
    BufferedReader bufferedReader;
    // use buffer writer to send data back to client
    BufferedWriter bufferedWriter;
    // create a client user to represent each client
    private String user;

    public HandleClients(Socket s) {
        try {
            this.s = s;
            this.bufferedWriter = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            this.bufferedReader = new BufferedReader(new InputStreamReader(s.getInputStream()));
            this.user = bufferedReader.readLine();
            // add the client to the array list so they can be part of the group chat and receive messages
            handleClients.add(this);
            transmitMessage("SERVER: " + user + " " + "has entered the chat");

        } catch (IOException e) {
            closeEverything(s, bufferedReader, bufferedWriter);
        }
    }

    @Override
    // everything here will be run on a separate thread
    public void run() {
        // get a string variable to hold message from client
        String messageFromClient;

        while (s.isConnected()) {
                try {
                    //listen to message from client
                    messageFromClient = bufferedReader.readLine();
                    transmitMessage(messageFromClient);
                } catch (IOException e) {
                    closeEverything(s, bufferedReader, bufferedWriter);
                    break;
                }
        }
    }
    public void transmitMessage(String messageToSend) {
        // loop through our arraylist
        for (HandleClients handleClients : handleClients) {
            try {
                if (!handleClients.user.equals(user)) {
                    handleClients.bufferedWriter.write(messageToSend);
                    handleClients.bufferedWriter.newLine();
                    // use flush to reduce the messages sent
                    handleClients.bufferedWriter.flush();

                }
            } catch (IOException e) {
                closeEverything(s, bufferedReader, bufferedWriter);
            }
        }
    }
    // create method to show user has left the chat
    public void removeHandleClient() {
        handleClients.remove(this);
        transmitMessage("SERVER: " + user + " " + "has left the chat");
    }

    public void closeEverything(Socket s, BufferedReader bufferedReader, BufferedWriter bufferedWriter) {
            removeHandleClient();
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                if (bufferedWriter != null) {
                    bufferedWriter.close();
                }
                if (s != null) {
                    s.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
}
package org;

import org.server.Server;

import java.io.IOException;
import java.net.ServerSocket;

public class ServerMain {

    public static void main(String[] args) throws IOException {
        // create a server socket object with a port number which listens to clients passing information to the port number
        ServerSocket ss = new ServerSocket(8080);
        Server server = new Server(ss);
        // to keep our server running
        server.ss();

    }
}

In the server main class, we are creating a port number of 8080 which is a unique number by which both the server and client agree to communicate with each other.

Here we create the Client class

package org.client;

import java.io.*;
import java.net.Socket;
import java.nio.Buffer;
import java.util.Scanner;

public class Client {
    private Socket s;

    private BufferedReader bufferedReader;

    private BufferedWriter bufferedWriter;

    private String userName;

    // create a constructor to instantiate every property


    public Client(Socket s, String userName) {
        try {
            this.s = s;
            this.bufferedWriter = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            this.bufferedReader = new BufferedReader(new InputStreamReader(s.getInputStream()));
            this.userName = userName;
        } catch (IOException e) {
            closeEverything(s, bufferedReader, bufferedWriter);
        }
    }

    public void sendMessage() {
        try {
            bufferedWriter.write(userName);
            bufferedWriter.newLine();
            bufferedWriter.flush();

            Scanner scanner = new Scanner(System.in);

            while (s.isConnected()) {
                String messageToSend = scanner.nextLine();
                bufferedWriter.write(userName + ":" + " " + messageToSend);
                bufferedWriter.newLine();
                bufferedWriter.flush();
            }
        } catch (IOException e) {
            closeEverything(s, bufferedReader, bufferedWriter);
        }
    }

    // create a method for listening from message from the server
    public void listenForMessage() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                String messageFromGroupChat;

                while (s.isConnected()) {
                    try {
                        messageFromGroupChat = bufferedReader.readLine();
                        System.out.println(messageFromGroupChat);
                    } catch (IOException e) {
                        closeEverything(s, bufferedReader, bufferedWriter);
                    }
                }
            }
        }).start();
    }

    public void closeEverything(Socket s, BufferedReader bufferedReader, BufferedWriter bufferedWriter) {
        try {
            if (bufferedReader != null) {
                bufferedReader.close();
            }
            if (bufferedWriter != null) {
                bufferedWriter.close();
            }
            if (s != null) {
                s.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    public static void main(String[] args) throws IOException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("Enter your username for the group chat: ");
        String userName = scanner.nextLine();
        Socket s = new Socket("localhost", 8080);
        Client client = new Client(s, userName);
        client.listenForMessage();
        client.sendMessage();
    }
}

This ends our group chat application where each client in the chat could chat within themselves.

Here is it techies, until my next post never stops learning. quoting from Sir Authur C. Clarke "Any sufficiently advanced technology is equivalent to magic.”