Multithreaded Chat Server/Client
I feel I may have horribly screwed this one up, and I'm again looking for some insight in to my mistakes. I'm supposed to write a multi-threaded chat server/client program that the server accepts requests and (messages) and sends them to the appropriate clients. The problem I'm having currently is that my client threads won't seem to stay connected. They do connect to begin with, then immediate disconnect and an error is thrown. Here's my code:
ChatClientThread Class:
Code:
package chatroom;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
/**
*
*/
public class ChatClientThread extends Thread
{
private Socket socket;
private ChatClient client;
private Scanner in;
public ChatClientThread(ChatClient c, Socket s)
{
client = c;
socket = s;
open();
start();
}
public void open()
{
try
{
in = new Scanner(socket.getInputStream());
}
catch (IOException ex)
{
System.out.println("Error Getting Input Stream: " + ex);
ex.printStackTrace();
}
}
public void close()
{
if (in != null) in.close();
}
public void run()
{
while(true)
{
client.handle(in.nextLine());
}
}
}
ChatClient Class:
Code:
package chatroom;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
*
*/
public class ChatClient implements Runnable
{
private Socket socket;
private Thread thread;
private Scanner in;
private PrintWriter output;
private ChatClientThread client;
public ChatClient(String hostname, int port)
{
try
{
System.out.println("Connecting, please wait...");
socket = new Socket(hostname, port);
System.out.println("Connected: " + socket);
}
catch (UnknownHostException ex)
{
System.out.println("Unknown Host: " + ex.getMessage());
ex.printStackTrace();
}
catch (IOException ex)
{
System.out.println("I/O Exception: " + ex.getMessage());
ex.printStackTrace();
}
}
public void run()
{
while(thread != null)
{
output.println(in.nextLine());
}
}
public void handle(String msg)
{
if(msg.equals(".exit"))
{
System.out.println("Exiting. Press RETURN.");
stop();
System.exit(0);
}
}
public void start() throws IOException
{
in = new Scanner(System.in);
output = new PrintWriter(socket.getOutputStream(), true);
if(thread == null)
{
client = new ChatClientThread(this, socket);
thread = new Thread(this);
thread.start();
}
}
public void stop()
{
try
{
if (thread != null) thread = null;
if (in != null) in.close();
if (output != null) output.close();
if (socket != null) socket.close();
}
catch (IOException ex)
{
System.out.println("Error in closing");
ex.printStackTrace();
}
}
public static void main(String args[])
{
ChatClient client = new ChatClient("localhost", 5678);
}
}
ChatServerThread Class:
Code:
package chatroom;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
/**
*
*/
public class ChatServerThread extends Thread
{
private ChatServer server;
private Socket socket;
private int ID = -1;
private Scanner input;
private PrintWriter output;
public ChatServerThread(ChatServer serv, Socket sock)
{
super();
server = serv;
socket = sock;
ID = socket.getPort();
}
public void send(String msg) {output.println(msg);}
public int getID() {return ID;}
public void run()
{
System.out.println("server Thread " + ID + " is running");
String msg = null;
while((msg = input.nextLine()) != null)
server.handle(ID, msg);
}
public void open() throws IOException
{
input = new Scanner(socket.getInputStream());
output = new PrintWriter(socket.getOutputStream());
}
public void close() throws IOException
{
if (socket != null) socket.close();
if (input != null) input.close();
if (output != null) output.close();
}
}
ChatServer Class:
Code:
package chatroom;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
*
*/
public class ChatServer implements Runnable
{
private ChatServerThread clients[] = new ChatServerThread[50];
private ServerSocket server;
private Thread thread;
private int clientCount = 0;
public ChatServer(int port)
{
try
{
System.out.println("Connecting to port " + port + ".");
server = new ServerSocket(port);
System.out.println("Server Started: " + server);
start();
}
catch (IOException ex)
{
System.out.println("Unable to connect to port " + port + ex.getMessage());
ex.printStackTrace();
}
}
public void start()
{
if (thread == null)
{
thread = new Thread(this);
thread.start();
}
}
public void stop()
{
if (thread != null)
thread = null;
}
public void run()
{
while(thread != null)
{
try
{
System.out.println("Waiting to client");
addThread(server.accept());
}
catch (IOException ex)
{
System.out.println("Server accept error: " + ex);
ex.printStackTrace();
stop();
}
}
}
private int findClient(int ID)
{
for(int i = 0; i < clientCount; i++)
if(clients[i].getID() == ID)
return i;
return -1;
}
public synchronized void handle(int ID, String input)
{
if (input.equals(".exit"))
{
clients[findClient(ID)].send(".exit");
}
else
for(int i = 0; i < clientCount; i++)
clients[i].send(ID + ": " + input);
}
public synchronized void remove(int ID)
{
int pos = findClient(ID);
if(pos >= 0)
{
ChatServerThread toDie = clients[pos];
System.out.println("Removing Client Thread " + ID + " at " + pos);
if(pos < clientCount - 1)
{
for(int i = pos + 1; i < clientCount; i++)
clients[i-1] = clients[i];
clientCount--;
}
try
{
toDie.close();
}
catch(IOException ex)
{
System.out.println("Error Closing Thread: " + ex);
ex.printStackTrace();
toDie.stop();
}
}
}
private void addThread(Socket socket)
{
if(clientCount < clients.length)
{
System.out.println("Client Accepted: " + socket);
clients[clientCount] = new ChatServerThread(this, socket);
try
{
clients[clientCount].open();
clients[clientCount].start();
clientCount++;
}
catch(IOException ex)
{
System.out.println("Error Opening Thread: " + ex);
ex.printStackTrace();
}
}
else
System.out.println("Client Refused: maximum of " + clients.length + " reached");
}
public static void main(String args[])
{
ChatServer server = new ChatServer(5678);
}
}
The Error I get is:
Code:
/*Correctly Echoed Commands Here*/
Connecting to port 5678.
Server Started: ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=5678]
Waiting to client
Client Accepted: Socket[addr=/127.0.0.1,port=46956,localport=5678]
Waiting to client
server Thread 46956 is running
/*Error is Here*/
Exception in thread "Thread-1" java.util.NoSuchElementException: No line found
at java.util.Scanner.nextLine(Scanner.java:1516)
at chatroom.ChatServerThread.run(ChatServerThread.java:36)
The ChatServer class will continue to run and accept clients, so I'm pretty sure I got that right. What I seem to have screwed up, based on the error messages is to make the client lay in wait for the user to type something as a message. Instead of laying in wait, it simply exits based on (I think) the above error. I'm just not sure how to fix it.
Any suggestions and/or pointers would be greatly appreciated, as always.
Thanks!
Re: Multithreaded Chat Server/Client
Read the API docs for the methods you are using. The Scanners nextLine() method throws a NoSuchElementException if there is no line available.
You can't just blindly call nextLine() in the hope of there being data, but if you read the docs you will see there is a hasNextLine() method which returns true if there is a line of data.
Re: Multithreaded Chat Server/Client
Dear Sir: In ChatServerThread, you need to flush the output buffer. Ex:
output = new PrintWriter(socket.getOutputStream(),true); // autoflush = true
You can verify that you are receiving data by putting a System.out.println in your send() method.
If you run ChatServer and open a telnet session from a command line window:
C:\>telnet localhost 5678, you can test your input / output streams. You can put a message like this in the open() method: output.println("Enter Exit to escape"); This ought to show up in the telnet session at its start.
I don't know about the other two programs. Good luck.