mattbdean
mattbdean

Reputation: 2562

Java chat server with commands

So I'm making a chat server in Java to kind of move out of depending on Hamachi for hosting and communication in my Minecraft server. It works perfectly, except for one thing: I can't figure out how the life of me how to add commands to the server. My main loop goes as follows:

/*Executed in constructor*/
public void listen(int port) throws IOException {
    //Initialize the ServerSocket
    ss = new ServerSocket(port);
    System.out.println("Listening on " + InetAddress.getLocalHost() + ":" + ss.getLocalPort());

    running = true;

    //Keep accepting connections
    while (running) {
        //Get the incoming connection
        Socket s = ss.accept();
        System.out.println("Connection from: " + getFullIP(s));

        //Create a DataOutputStream for writing data to the other side
        DataOutputStream dataOut = new DataOutputStream(s.getOutputStream());

        //Save this stream so I don't have to make it again
        outputStreams.put(s, dataOut);

        //Create a new thread for this connection
        new ServerThread(this, s);

        if (!running) {
            stop();
        }
        Scanner cmdScanner = new Scanner(System.in);
        String command = cmdScanner.next();
        processCommand(command);
    }
}

The result of this code is that I cannot type a command until a client connects to the server (because of ss.accept()). Until I execute a command, a client cannot connect (cmdScanner.next()). How do I get around this?

Upvotes: 2

Views: 2069

Answers (2)

John
John

Reputation: 3807

I had this same problem when i started in networking. Your Thread is stopping at the ss.accept() and then is not continuing on in the code. You need to implement another Thread that is dedicated to your ServerSocket. Here is an example:

public class Server implements Runnable
{
    ServerSocket server; // the serverSock your clients will connect to
    Thread thread; // the thread for your server
    boolean running; // whether or not the server is running

    public Server(int port)
    {
        running = false; // server is not yet running
        connect(port); // setup server
    }

    public void connect(int port)
    {
        try
        { 
            server = new ServerSocket(port); setup server on port 

            running = true; // server is running
            thread = new Thread(this); // initialize server thread
            thread.start(); // start thread
        } catch(Exception e){e.printStackTrace(); running = false;} // port is in use
    }

    public void disconnect()
    {
        try
        {
            server.close();
        }catch(Exception e){e.printStackTrace();}

        running = false;
        thread = null;
        server = null;
    }

    public void run()
    {
        while(running)
        {
            Socket client = server.accept(); // client connects to server
            // handle the client...
            ClientHandler handler = new ClientHandler(client);
        }
    }

    public class ClientHandler implements Runnable
    {
        Thread clientThread;
        DataOutputStream out;

        public ClientHandler(Socket socket)
        {
            out = new DataOutputStream(socket.getOutputStream());//setup the output stream
            clientThread = new Thread(this); // setup the new thread
            clientThread.start();   // start the thread
        }

        public void run()
        {
            /* this is where you get your input from the console and then
             * send the output to the client
             */
        }
    }
}

This should keep your Main Thread from getting stuck on the server.accept() Hope this helped!

Upvotes: 1

tibo
tibo

Reputation: 5474

I think that your command processor should be in an other thread. IMHO a server should always have a thread which only job is to receive new connection and dispatching it. Processing your input should be part of an other thread.

public class TestThread
{
    public static void main(String[] args)
    {
        new ConnectionDispatcher(8080).start();
        new CommandProcessor().start();
    }
}
class ConnectionDispatcher extends Thread{
    private int port;
    private OutputStream outputStreams;

    ConnectionDispatcher(int port)
    {
        this.port = port;
    }

    @Override
    public void run()
    {
        try
        {
            listen(port);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    public void listen(int port) throws IOException
    {
        //Initialize the ServerSocket
        ss = new ServerSocket(port);
        System.out.println("Listening on " + InetAddress.getLocalHost() + ":" + ss.getLocalPort());

        boolean running = true;

        //Keep accepting connections
        while (running) {
            //Get the incoming connection
            Socket s = ss.accept();
            System.out.println("Connection from: " + getFullIP(s));

            //Create a DataOutputStream for writing data to the other side
            DataOutputStream dataOut = new DataOutputStream(s.getOutputStream());

            //Save this stream so I don't have to make it again
            outputStreams.put(s, dataOut);

            //Create a new thread for this connection
            new ServerThread(this, s);

        }
    }
}

class CommandProcessor extends Thread{
    @Override
    public void run()
    {
        Scanner cmdScanner = new Scanner(System.in);
        String command = cmdScanner.next();
        processCommand(command);
    }
}

Upvotes: 1

Related Questions