Search code examples
javamultithreadingsocketsserversocketdistributed-system

Can a client program have a server socket to communicate to other client programs?


I am trying to implement a multithreaded socket program that simulates five computer and a controller communicating with each other via sockets. The controller has a server socket that accepts incoming sockets (from computers). Once it reaches the max capacity of the system (let's say five), then it will send out a start message to those computers using threads that was created when accepting incoming sockets.

When each computer receives the Start message from the controller, I want to be able for each computer to communicate with other computers (without relying on controller (relaying messages from computer to controller to computer). What I thought would work is having each computer instantiate a server socket so that it can accept incoming sockets from computers. And also instantiate another client socket so that other server sockets from different computers can accept it.

I know this may sound pretty confusing, but basically I want to use a server socket on each client program (computer) so that it can listen to other clients (computer) without relying on the controller.

Is this possible? Can I instantiate each client program (computer) a server socket so that it can listen to other computers? Does it need a different IP address and/or port number from the controller's server socket? Do I need to instantiate x amount of sockets for x amount of computers?

Maybe my Java code can make sense of this.

Controller.java

    package timetableexchange;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class Controller {

final int MAX_SYSTEMS = 2;

static ArrayList<ServerConnection> conns = new ArrayList<ServerConnection>();   // connections to computer
static int finishedCount = 0;                                                   // number of finished computers

ServerSocket ss;            // server socket

public static void main(String[] args) throws IOException {
    // Instantiate controller
    new Controller(8000);
}

public Controller(int port) throws IOException {
    // Instantiate server socket
    ss = new ServerSocket(8000);
    int i = 0;
    // Listen and accept clients (1 for testing)
    while (i < MAX_SYSTEMS) {
        Socket s = ss.accept();
        // add to list
        ServerConnection conn = new ServerConnection(i++, s);
        conns.add(conn);
    }
    // start server connection thread
    for (i = 0; i < conns.size(); ++i) {
        conns.get(i).start();
    }
    ss.close();
}

// Thread for communicating between controller and computer
private class ServerConnection extends Thread {

    Socket socket;
    BufferedReader in;
    PrintWriter out;
    int identifier;

    // constructor
    public ServerConnection(int i, Socket s) throws IOException {
        this.identifier = i;
        this.socket = s;
        this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        this.out = new PrintWriter(socket.getOutputStream(), true);
        System.out.println("Client Connected");
    }

    @Override
    public void run() {
        System.out.println("ServerConnection started");
        // send ID to computers
        sendAll(identifier + "");
        // send Start message to computers
        sendAll("Start");
        // Check if a computer sent back a Finish message
        // If all computers are finished, then send out Tear Down message.
        while (true) {
            try {
                String clientInput = in.readLine();
                if (clientInput.equals("Finish")) {
                    finishedCount += 1;
                    if (finishedCount == conns.size()) {
                        sendAll("Tear Down");
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }
        }
    }

    private void sendAll(String text) {
        for (int i = 0; i < conns.size(); ++i) {
            ServerConnection conn = conns.get(i);
            conn.out.println(text);
        }
    }
}

}

Computer.java

package timetableexchange;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Vector;

public class Computer {

final int MAX_SYSTEMS = 2;

int identifier;                                         // Computer ID
int eventCount;                                         // Number of Generated Events
ArrayList<Socket> sockets = new ArrayList<Socket>();    // List of (client) sockets
Vector<Integer> timestamp = new Vector<Integer>();      // Time-stamp vector

Socket socketToServer;                                  // Socket to Connect to Controller
BufferedReader inputFromServer;                         // Input Stream from Controller
PrintWriter outputToServer;                             // Output Stream to Controller
String textFromServer;                                  // String sent from Controller

ServerSocket ss;                                        // Server Socket to communicate with other clients (computers)
Socket socketToClient;                                  // Socket to Connect to Computer
BufferedReader inputFromClient;                         // Input Stream from Computer
PrintWriter outputToClient;                             // Output Stream to Computer

public static void main(String[] args) throws IOException {
    // Instantiate Computer
    new Computer("127.0.0.1", 8000);
}

// Constructor
public Computer(String hostname, int port) throws IOException {
    // Instantiate Socket (to Controller) and Streams (to Controller)
    socketToServer = new Socket(hostname, port);
    inputFromServer = new BufferedReader(new InputStreamReader(socketToServer.getInputStream()));
    outputToServer = new PrintWriter(socketToServer.getOutputStream(), true);

    // Check if Controller sent the computer its ID
    while (true) {
        try {
            textFromServer = inputFromServer.readLine();
            // set identifier
            identifier = Integer.parseInt(textFromServer);
            System.out.println(identifier);
            break;  // break loop
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
    }

    // Check if Controller sent the start message
    while (true) {
        textFromServer = inputFromServer.readLine();
        if (textFromServer.equals("Start"))
            System.out.println("Start message received");
            break;  // break loop
    }

    // Instantiate Server Socket (for Clients)
    ss = new ServerSocket(port + identifier + 1);

    // Instantiate Client Socket for Other Clients to Hear
    socketToClient = new Socket();
    inputFromClient = new BufferedReader(new InputStreamReader(socketToClient.getInputStream()));
    outputToClient = new PrintWriter(socketToClient.getOutputStream());

    // listen to server socket and add accepted socket to list  
    for (int i = 0; i < MAX_SYSTEMS - 1; ++i) {
        Socket s = ss.accept();
        System.out.println("Client accepted");
        sockets.add(s);
    }

    Thread readEvent = new Thread(new Runnable() {
        @Override
        public void run() {
            /**
             * Read from input stream
             * Read the vector inside the input stream
             * Compare vectors and choose the largest integer (synchronized)
             * Add 1 to the corresponding socket. (synchronized)
             */
        }
    });

    Thread writeEvent = new Thread(new Runnable() {
        @Override
        public void run() {
            /**
             * Generate random number between 0 and 4.
             * If zero, then add 1 to its own socket in vector.
             * Else, send vector to random socket via output stream
             */
        }
    });

    readEvent.start();
    writeEvent.start();
}

}

I appreciate the help!


Solution

  • In short:

    Is this possible?

    Yes - why not?

    Can I instantiate each client program (computer) a server socket so that it can listen to other computers?

    Yes - you can do whatever you want or need

    Does it need a different IP address and/or port number from the controller's server socket?

    IP address belongs to "physical computer"/hetwork interface and it does not matter to what you are trying to do - all can run on one computer and all can run on the same IP address (e.g. 127.0.0.1). You have to have dedicated ports for each Server socket you are about to open, and your client sockets must know IP and port numbers to communicate with. for client socket you do not need to care about neither IP nor port number.

    Do I need to instantiate x amount of sockets for x amount of computers?

    Question does very little sense ro me - it is your design decision how many Server sockets you need to instantiate - one Server socket for one port, that's it.