Reputation: 2562
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
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
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