Search code examples
javamultithreadingthreadpoolrunnableserversocket

Making a basic Java file server multi-threaded


I've got a server which sends to its client the contents of a text file.

The 'server' package has a 'Main' (takes in port no. from cmd line args and parses it), 'Server' and a 'FileHandler' class and I think I've got them in a way (using a threadpool) so that the server is able to serve concurrently to two clients.

Now I'm trying to build a CLI with options to start & stop the server. I'm looking to implement 2 threads, where one thread will listen for the input and another for the 'accept()' call.

My attempt at it so far has been to create a new class 'Commander.java' and take in an AtomicBoolean in the constructor and then store it in the object to use as a flag for stopping the server thread.

I want the thread that is listening for the 'accept()' call to periodically check if a request has been made to stop - how can I do this with my 'Commander' class?

Including some code snippets (a.k.a. my attempt so far) for your better understanding:

class Server implements Runnable 
{
Socket sock;
ExecutorService executor;
private int port ;

public Server(int p) {
    port = p ;
    executor = Executors.newFixedThreadPool(2);
}

public void startServer() {
ServerSocket s = new ServerSocket(port);
...
while (true)
{
    Socket temp = s.accept();
    sock = temp;
    executor.execute(new FileHandler(sock));
    // serveFile(temp) ;
}

public void run() {
    startServer();
}
}

public class Main {

public static void main(String[] args) {

    while(true) {
        System.out.println("Main menu:\n" +
                       " 1 - Start server\n"+
                       " 2 - Stop Server\n"+
                       " 0 - Exit");
        int in = Integer.parseInt(scanner.nextLine());

        switch(in) {
            case 1: 
                // start server
                System.out.println("Starting server...");
                Thread th1 = new Thread(new Server(port));
                th1.start();
                System.out.println("Case continuity...");
                // server.startServer() ;
                break;
            case 2:
                // stop server
                System.out.println("Server stopped.\n");
                break;
            case 0:
                // exit
                System.exit(0);
                break;
            }
        }
     }
 }

class FileHandler implements Runnable {

Socket socket;

public FileHandler(Socket socket) {
    this.socket = socket;
}

private void serveFile() {
 ...code for serving file...
}


public void run() {
    serveFile();
}
}

public class Commander implements Runnable
{

 private AtomicBoolean bool;

 public Commander(AtomicBoolean bool) {
    this.bool = new AtomicBoolean(bool);
 }

 public boolean value() {
    return bool.get();
 }

Solution

  • Based on @Kayaman Answer:

    A- At your Server class:

    1- let ServerSocket be a class member scope:

    ServerSocket s = new ServerSocket(port);
    

    2- add a method shutdown():

    public void shutdown(){
        try{
            s.close();
        }catch(Exception e){
            e.printStacktrace();
        }
    }
    

    3- add try/catch to handle socket close (do a clean shutdown):

    while (true)
    {
        try{
            Socket temp = s.accept();
            sock = temp;
            executor.execute(new FileHandler(sock));
            // serveFile(temp) ;
        }catch(SocketException ex){
            doAcleanShutdown();
        }
    }
    

    B- In your Main class:

    1- let Server instance be class member scope

    Server myServer = new Server(port);
    

    2- In switch (case 1:) use myServer instance

    case 1: 
        // start server
        System.out.println("Starting server...");
        Thread th1 = new Thread(myServer);
        th1.start();
        System.out.println("Case continuity...");
        // server.startServer() ;
        break;
    

    3- to stop the server, case 2:

    case 2:
        // stop server
        myServer.shutdown();
        System.out.println("Server stopped.\n");
        break;