So I'm writing two ServerSockets. One that listens for HTTP requests on port 8085 and saves the byte input into a static LinkedList, and a second that listens on port 8086 and returns all the results in the static LinkedList.
The issue is that when saving the data from ServerSocket:8085 to the LinkedList, the thread hangs and I'm not sure why.
This is the main Listener class:
import java.net.ServerSocket;
import java.nio.charset.Charset;
import java.util.*;
public class Listener {
public static LinkedList<byte[]> Calls = new LinkedList<>();
public static void main(String[] args) {
Thread callback = new Thread(new ThreadListener());
callback.start();
while (true) {
try (var listener = new ServerSocket(8086)) {
System.out.println("Listening on 8086...");
try (var client = listener.accept()) {
StringBuffer response = new StringBuffer();
response.append("HTTP/1.1 200 OK\r\n\r\n");
Iterator<byte[]> iterator = Calls.iterator();
while (iterator.hasNext()) {
response.append(new String(iterator.next(), Charset.forName("UTF-8")) + "\r\n");
iterator.remove();
}
client.getOutputStream().write(response.toString().getBytes("UTF-8"));
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
This is the ThreadListener class:
import java.io.IOException;
import java.net.ServerSocket;
import java.util.Date;
public class ThreadListener implements Runnable {
#Override
public void run() {
while (true) {
try (var listener = new ServerSocket(8085)) {
System.out.println("Listening on 8085...");
try (var socket = listener.accept()) {
if (!socket.getInetAddress().getHostAddress().equals("127.0.0.1")) {
System.out.println("Not localhost");
} else {
System.out.println("Its us!");
}
Listener.Calls.add(socket.getInputStream().readAllBytes());
System.out.println("Result collected");
Date today = new Date();
String httpResponse = "HTTP/1.1 200 OK\r\n\r\n" + today;
socket.getOutputStream().write(httpResponse.getBytes("UTF-8"));
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
As for my test, I tried calling 127.0.0.1:8085, and I get an ERR_CONNECTION_RESET, and all I have in the console is the following:
Listening on 8085...
Listening on 8086...
Its us!
Process finished with exit code -1 (I killed the app after 2 mins)
The fact that the "Its us!" message got printed, but the "Results collected!" right after the LinkedList.add didn't is what leads me to assume the LinkedList.add is the one hanging the thread.
Regards
EDIT: No one is calling to 8085 (or 8086), I'm doing it manually on my browser. I solved the Syncronization issue by creating a method to call instead of calling the LinkedList.add directly:
public static synchronized void addElementsToList(byte[] bytes) {
Calls.add(bytes);
}
This does work, but calling the 8085 socket gives the connection reset every time.
Your test mechanism of using a browser to create the request is probably also not helping here, as the InputStream.readAllBytes()
blocks until all remaining bytes have been read and end of stream is detected, or an exception is thrown. This method does not close the input stream.
From the documentation. Specifically, the browser is keeping the connection open, because it's expecting some response. Your server is trying to read everything from the connection until the connection is closed. Catch 22 (aka deadlock).
Try making the connection to localhost:8085 using telnet and closing the connection from the client end.
telnet 127.0.0.1 8085
^D
where ^D is literally the [CTRL] and [D] keys (eg: logout)
A LinkedList is not synchornized, as highlighted in the documentation.
You can either handle synchronisation manually, use a synchronised list, or a concurrent list. Probably some other methods too, but for now, just keep it simple.
public static LinkedList<byte[]> Calls = Collections.synchronizedList(new LinkedList<>());
// or
public static LinkedList<byte[]> Calls = new CopyOnWriteArrayList<>();
Related
I'm programming in Java and i'm making a socket connection between server and several clients (using threads).
In the client side i made an opened Socket that connects to the server in a respective port and i send several objects, then the client disconnects.
In the server side i made a ServerSocket (where the client connects) and i use the accept() method to get the Socket, i don't want the socket to close so i keep it opened until i want (using a method for example), then i create an stream (ObjectInputStream) and read every object sent from the client, but i don't want it to close too. To continue the understanding of my problem here is the class i made:
import java.io.*;
import java.net.*;
public class ServerConnection implements Runnable{
private Socket connection;
public ServerConnection(Socket c){
connection = c;
}
#Override
public void run() {
// I used String i this example, but the real code use a Object sending system that i created
// because i needed to send different objects in one object (this ones implements Serializable).
String msg;
try {
ObjectInputStream inStream = new ObjectInputStream(connection.getInputStream());
do{
inStream.
msg = ((String)inStream.readObject());
System.out.println(msg);
}
while(!msg.equals("FINISH CONNECTION"));
} catch (IOException ex) {
System.err.println("run() - (io): "+ex.getMessage());
try {
connection.close();
} catch (IOException ex1) {
System.err.println("run() - (io/io): "+ex.getMessage());
}
} catch (ClassNotFoundException ex) {
System.err.println("run() - (classNF): "+ex.getMessage());
}
}
// The main method was created to make tests
// I'll use objects of this class to every client connection
public static void main(String[] args){
try {
ServerSocket server = new ServerSocket(8010);
Socket connection = server.accept();
ServerConnection svConnection = new ServerConnection(connection);
Thread theThread = new Thread(svConnection);
theThread .start();
} catch (IOException ex) {
System.err.println(ex.getMessage());
}
}
}
This can receive the Strings i sent from the client, but the do-while isn't able to catch exceptions, the IOException is throwed when the Stream has no more Strings, so i want to prevent the throwing of that exception when the stream doesn't have more Strings to read, i tried to use recursive try-catch but i know that is not recommended. So there is another solution to this?
(Every answer is welcome. Thanks)
(EDIT)
For those one who needs the client code, so here it is:
import java.io.*;
import java.net.*;
public class ClientConnnection{
// There is a method that i don't make yet
public static void main(String[] args){
try {
Socket socketToServer = new Socket("localhost",8010);
ObjectOutputStream outStream = new ObjectOutputStream(socketToServer.getOutputStream());
outStream.writeObject(new Message("Hello :D"));
outStream.writeObject(new Message("How r u?"));
outStream.writeObject(new Message("Other message"));
outStream.flush();
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
I'm writing a client/server pair of applications. The server runs multiple threads that collect data and adds it to a BlockingQueue. The socket code loops over the queue and sends whatever data it finds to the client. The data is a string and I append a line separator so that the client can read it using BufferedReader.readLine().
My problem is that instead of readLine() returning on each line that's available it waits until the entire buffer is full before spitting out all the complete lines in the buffer. With the default 8K buffer this means I get data via the client in 8K chunks, which is highly undesirable. I've attached MRE code that represents this. I have confirmed via logging in my actual application that the BufferedWriter is writing the data as soon as it's available from the queue, but to be honest I don't know if the delay is coming after this on the sending side, or is truly on the reading side. If you run the MRE you'll see that the data is displayed approximately 170 lines at a time by the client.
I've searched online for this phenomenon for a couple of days and the one snippet that I could find of a similar issue suggests that maybe it's something to do with the underlying InputStreamReader and/or StreamDecoder, but that is starting to get beyond my expertise. (See this link)
So my question is whether I'm implementing the BufferedReader correctly and how can I resolve the issue I'm seeing so that I get each incoming line without unnecessary delays.
package serverTest;
import java.util.concurrent.BlockingQueue;
public class ServerTest {
public static void main(String[] args) {
int port = 54321;
ServerSocketComms server = new ServerSocketComms(port);
BlockingQueue<String> queue = server.getQueue();
new Thread(server).start();
ClientSocketComms client = new ClientSocketComms("localhost", port);
new Thread(client).start();
for(int i = 0; i < 1000; i++) { // should give about 10 seconds of output
try {
queue.put("" + i + " - All work and no play makes Jack a dull boy");
// Slow things down enough to show what's happening
Thread.sleep(10);
// 48 characters should fill the 8K buffer in approximately 2 seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package serverTest;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class ServerSocketComms implements Runnable {
private final BlockingQueue<String> queue = new LinkedBlockingQueue<>();
private final int port;
public ServerSocketComms(int port) {
this.port = port;
}
#Override
public void run() {
// Open server socket and wait for connection
try {
ServerSocket serverSocket = new ServerSocket(port);
Socket socket = serverSocket.accept();
// Continually loop over blocking data queue until stopped
BufferedWriter dataOut = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
while(socket.isConnected()) {
dataOut.write(queue.take());
dataOut.newLine(); // delimit strings with a line separator
}
// Loop never exits because client socket never completes because of BufferedReader issue
// so sockets never close and application never terminates
socket.close();
serverSocket.close();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
public BlockingQueue<String> getQueue() {
// Return a reference to the sending queue to be populated by other threads
return this.queue;
}
}
package serverTest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class ClientSocketComms implements Runnable {
private final String server;
private final int port;
public ClientSocketComms(String server, int port) {
this.server = server;
this.port = port;
}
#Override
public void run() {
// Open socket to server and wait for incoming data
try {
Socket socket = new Socket(server, port);
BufferedReader dataIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// Continually loop over incoming data until stopped
String data;
while((data = dataIn.readLine()) != null) {
// Should print out every line as it's received,
// but instead waits until buffer is full
// (outputs about 170 lines at a time)
System.out.println(data);
}
// Close socket and thread will die
// (but loop never ends because buffer doesn't get completely refilled)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Your server is using a BufferedWriter:
BufferedWriter dataOut = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
This one does the buffering that you do not like. It seems the default buffer size is the 8k that you are seeing although that is not documented in the API and could change. Try flushing the buffer using dataOut.flush() if at some point in time you want to ensure everything stored in the buffer so far is sent out to the client immediately. Have a look at the BufferedWriter API for details.
BTW, I have not checked whether there are any other problems in your code. But the above is definitely one.
In my main thread I have a while(listening) loop which calls accept() on my ServerSocket object, then starts a new client thread and adds it to a Collection when a new client is accepted.
I also have an Admin thread which I want to use to issue commands, like 'exit', which will cause all the client threads to be shut down, shut itself down, and shut down the main thread, by turning listening to false.
However, the accept() call in the while(listening) loop blocks, and there doesn't seem to be any way to interrupt it, so the while condition cannot be checked again and the program cannot exit!
Is there a better way to do this? Or some way to interrupt the blocking method?
You can call close() from another thread, and the accept() call will throw a SocketException.
Set timeout on accept(), then the call will timeout the blocking after specified time:
http://docs.oracle.com/javase/7/docs/api/java/net/SocketOptions.html#SO_TIMEOUT
Set a timeout on blocking Socket operations:
ServerSocket.accept();
SocketInputStream.read();
DatagramSocket.receive();
The option must be set prior to entering a blocking operation to take effect. If the timeout expires and the operation would continue to block, java.io.InterruptedIOException is raised. The Socket is not closed in this case.
Is calling close() on the ServerSocket an option?
http://java.sun.com/j2se/6/docs/api/java/net/ServerSocket.html#close%28%29
Closes this socket. Any thread currently blocked in accept() will throw a SocketException.
You can just create "void" socket for break serversocket.accept()
Server side
private static final byte END_WAITING = 66;
private static final byte CONNECT_REQUEST = 1;
while (true) {
Socket clientSock = serverSocket.accept();
int code = clientSock.getInputStream().read();
if (code == END_WAITING
/*&& clientSock.getInetAddress().getHostAddress().equals(myIp)*/) {
// End waiting clients code detected
break;
} else if (code == CONNECT_REQUEST) { // other action
// ...
}
}
Method for break server cycle
void acceptClients() {
try {
Socket s = new Socket(myIp, PORT);
s.getOutputStream().write(END_WAITING);
s.getOutputStream().flush();
s.close();
} catch (IOException e) {
}
}
The reason ServerSocket.close() throws an exception
is because you have an outputstream or an inputstream
attached to that socket.
You can avoid this exception safely by first closing the input and output streams.
Then try closing the ServerSocket.
Here is an example:
void closeServer() throws IOException {
try {
if (outputstream != null)
outputstream.close();
if (inputstream != null)
inputstream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
if (!serversock.isClosed())
serversock.close();
}
}
You can call this method to close any socket from anywhere without getting an exception.
Use serverSocket.setSoTimeout(timeoutInMillis).
OK, I got this working in a way that addresses the OP's question more directly.
Keep reading past the short answer for a Thread example of how I use this.
Short answer:
ServerSocket myServer;
Socket clientSocket;
try {
myServer = new ServerSocket(port)
myServer.setSoTimeout(2000);
//YOU MUST DO THIS ANYTIME TO ASSIGN new ServerSocket() to myServer‼!
clientSocket = myServer.accept();
//In this case, after 2 seconds the below interruption will be thrown
}
catch (java.io.InterruptedIOException e) {
/* This is where you handle the timeout. THIS WILL NOT stop
the running of your code unless you issue a break; so you
can do whatever you need to do here to handle whatever you
want to happen when the timeout occurs.
*/
}
Real world example:
In this example, I have a ServerSocket waiting for a connection inside a Thread. When I close the app, I want to shut down the thread (more specifically, the socket) in a clean manner before I let the app close, so I use the .setSoTimeout() on the ServerSocket then I use the interrupt that is thrown after the timeout to check and see if the parent is trying to shut down the thread. If so, then I set close the socket, then set a flag indicating that the thread is done, then I break out of the Threads loop which returns a null.
package MyServer;
import javafx.concurrent.Task;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import javafx.concurrent.Task;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
public class Server {
public Server (int port) {this.port = port;}
private boolean threadDone = false;
private boolean threadInterrupted = false;
private boolean threadRunning = false;
private ServerSocket myServer = null;
private Socket clientSocket = null;
private Thread serverThread = null;;
private int port;
private static final int SO_TIMEOUT = 5000; //5 seconds
public void startServer() {
if (!threadRunning) {
serverThread = new Thread(thisServerTask);
serverThread.setDaemon(true);
serverThread.start();
}
}
public void stopServer() {
if (threadRunning) {
threadInterrupted = true;
while (!threadDone) {
//We are just waiting for the timeout to exception happen
}
if (threadDone) {threadRunning = false;}
}
}
public boolean isRunning() {return threadRunning;}
private Task<Void> thisServerTask = new Task <Void>() {
#Override public Void call() throws InterruptedException {
threadRunning = true;
try {
myServer = new ServerSocket(port);
myServer.setSoTimeout(SO_TIMEOUT);
clientSocket = new Socket();
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
try {
clientSocket = myServer.accept();
}
catch (java.io.InterruptedIOException e) {
if (threadInterrupted) {
try { clientSocket.close(); } //This is the clean exit I'm after.
catch (IOException e1) { e1.printStackTrace(); }
threadDone = true;
break;
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
};
}
Then, in my Controller class ... (I will only show relevant code, massage it into your own code as needed)
public class Controller {
Server server = null;
private static final int port = 10000;
private void stopTheServer() {
server.stopServer();
while (server.isRunning() {
//We just wait for the server service to stop.
}
}
#FXML private void initialize() {
Platform.runLater(()-> {
server = new Server(port);
server.startServer();
Stage stage = (Stage) serverStatusLabel.getScene().getWindow();
stage.setOnCloseRequest(event->stopTheServer());
});
}
}
I hope this helps someone down the road.
Another thing you can try which is cleaner, is to check a flag in the accept loop, and then when your admin thread wants to kill the thread blocking on the accept, set the flag (make it thread safe) and then make a client socket connection to the listening socket.
The accept will stop blocking and return the new socket.
You can work out some simple protocol thing telling the listening thread to exit the thread cleanly.
And then close the socket on the client side.
No exceptions, much cleaner.
You can simply pass the timeout limit (milli seconds) as a parameter while calling accept function.
eg serverSocket.accept(1000);
automatically close the request after 1 sec
In my main thread I have a while(listening) loop which calls accept() on my ServerSocket object, then starts a new client thread and adds it to a Collection when a new client is accepted.
I also have an Admin thread which I want to use to issue commands, like 'exit', which will cause all the client threads to be shut down, shut itself down, and shut down the main thread, by turning listening to false.
However, the accept() call in the while(listening) loop blocks, and there doesn't seem to be any way to interrupt it, so the while condition cannot be checked again and the program cannot exit!
Is there a better way to do this? Or some way to interrupt the blocking method?
You can call close() from another thread, and the accept() call will throw a SocketException.
Set timeout on accept(), then the call will timeout the blocking after specified time:
http://docs.oracle.com/javase/7/docs/api/java/net/SocketOptions.html#SO_TIMEOUT
Set a timeout on blocking Socket operations:
ServerSocket.accept();
SocketInputStream.read();
DatagramSocket.receive();
The option must be set prior to entering a blocking operation to take effect. If the timeout expires and the operation would continue to block, java.io.InterruptedIOException is raised. The Socket is not closed in this case.
Is calling close() on the ServerSocket an option?
http://java.sun.com/j2se/6/docs/api/java/net/ServerSocket.html#close%28%29
Closes this socket. Any thread currently blocked in accept() will throw a SocketException.
You can just create "void" socket for break serversocket.accept()
Server side
private static final byte END_WAITING = 66;
private static final byte CONNECT_REQUEST = 1;
while (true) {
Socket clientSock = serverSocket.accept();
int code = clientSock.getInputStream().read();
if (code == END_WAITING
/*&& clientSock.getInetAddress().getHostAddress().equals(myIp)*/) {
// End waiting clients code detected
break;
} else if (code == CONNECT_REQUEST) { // other action
// ...
}
}
Method for break server cycle
void acceptClients() {
try {
Socket s = new Socket(myIp, PORT);
s.getOutputStream().write(END_WAITING);
s.getOutputStream().flush();
s.close();
} catch (IOException e) {
}
}
The reason ServerSocket.close() throws an exception
is because you have an outputstream or an inputstream
attached to that socket.
You can avoid this exception safely by first closing the input and output streams.
Then try closing the ServerSocket.
Here is an example:
void closeServer() throws IOException {
try {
if (outputstream != null)
outputstream.close();
if (inputstream != null)
inputstream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
if (!serversock.isClosed())
serversock.close();
}
}
You can call this method to close any socket from anywhere without getting an exception.
Use serverSocket.setSoTimeout(timeoutInMillis).
OK, I got this working in a way that addresses the OP's question more directly.
Keep reading past the short answer for a Thread example of how I use this.
Short answer:
ServerSocket myServer;
Socket clientSocket;
try {
myServer = new ServerSocket(port)
myServer.setSoTimeout(2000);
//YOU MUST DO THIS ANYTIME TO ASSIGN new ServerSocket() to myServer‼!
clientSocket = myServer.accept();
//In this case, after 2 seconds the below interruption will be thrown
}
catch (java.io.InterruptedIOException e) {
/* This is where you handle the timeout. THIS WILL NOT stop
the running of your code unless you issue a break; so you
can do whatever you need to do here to handle whatever you
want to happen when the timeout occurs.
*/
}
Real world example:
In this example, I have a ServerSocket waiting for a connection inside a Thread. When I close the app, I want to shut down the thread (more specifically, the socket) in a clean manner before I let the app close, so I use the .setSoTimeout() on the ServerSocket then I use the interrupt that is thrown after the timeout to check and see if the parent is trying to shut down the thread. If so, then I set close the socket, then set a flag indicating that the thread is done, then I break out of the Threads loop which returns a null.
package MyServer;
import javafx.concurrent.Task;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import javafx.concurrent.Task;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
public class Server {
public Server (int port) {this.port = port;}
private boolean threadDone = false;
private boolean threadInterrupted = false;
private boolean threadRunning = false;
private ServerSocket myServer = null;
private Socket clientSocket = null;
private Thread serverThread = null;;
private int port;
private static final int SO_TIMEOUT = 5000; //5 seconds
public void startServer() {
if (!threadRunning) {
serverThread = new Thread(thisServerTask);
serverThread.setDaemon(true);
serverThread.start();
}
}
public void stopServer() {
if (threadRunning) {
threadInterrupted = true;
while (!threadDone) {
//We are just waiting for the timeout to exception happen
}
if (threadDone) {threadRunning = false;}
}
}
public boolean isRunning() {return threadRunning;}
private Task<Void> thisServerTask = new Task <Void>() {
#Override public Void call() throws InterruptedException {
threadRunning = true;
try {
myServer = new ServerSocket(port);
myServer.setSoTimeout(SO_TIMEOUT);
clientSocket = new Socket();
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
try {
clientSocket = myServer.accept();
}
catch (java.io.InterruptedIOException e) {
if (threadInterrupted) {
try { clientSocket.close(); } //This is the clean exit I'm after.
catch (IOException e1) { e1.printStackTrace(); }
threadDone = true;
break;
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
};
}
Then, in my Controller class ... (I will only show relevant code, massage it into your own code as needed)
public class Controller {
Server server = null;
private static final int port = 10000;
private void stopTheServer() {
server.stopServer();
while (server.isRunning() {
//We just wait for the server service to stop.
}
}
#FXML private void initialize() {
Platform.runLater(()-> {
server = new Server(port);
server.startServer();
Stage stage = (Stage) serverStatusLabel.getScene().getWindow();
stage.setOnCloseRequest(event->stopTheServer());
});
}
}
I hope this helps someone down the road.
Another thing you can try which is cleaner, is to check a flag in the accept loop, and then when your admin thread wants to kill the thread blocking on the accept, set the flag (make it thread safe) and then make a client socket connection to the listening socket.
The accept will stop blocking and return the new socket.
You can work out some simple protocol thing telling the listening thread to exit the thread cleanly.
And then close the socket on the client side.
No exceptions, much cleaner.
You can simply pass the timeout limit (milli seconds) as a parameter while calling accept function.
eg serverSocket.accept(1000);
automatically close the request after 1 sec
Hi could somebody help me with this code because I was trying with If statement but is no working. I am not asking to write for me code just point me at something.
The main problem is that every time somebody connect, new thread is made but when he turn off his chat box the tread stays on and is not working as should be. I mean some body make 10 connections himself and nobody else can chat.
import java.net.*;
import java.io.*;
public class myServer {
static ServerSocket server;
static Socket client;
static DataInputStream in;
static DataOutputStream out;
static clientThread t[] = new clientThread[10];
public static void main(String[] args) throws IOException {
System.out.println("Starting Server");
server = new ServerSocket(7555);
System.out.println("Started Server");
while (true) {
client = server.accept();
System.out.println("CONNECTION");
out = new DataOutputStream(client.getOutputStream());
out.writeUTF("Welcome to the chat room");
for (int i = 0; i <= 9; i++) {
if (t[i] == null) {
(t[i] = new clientThread(client, t)).start();
break;
}
}
}
}
}
class clientThread extends Thread {
DataInputStream in;
DataOutputStream out;
static String msg;
Socket client = null;
clientThread t[];
public clientThread(Socket client, clientThread[] t) {
this.client = client;
this.t = t;
}
public void run() {
try {
in = new DataInputStream(client.getInputStream());
out = new DataOutputStream(client.getOutputStream());
boolean tru = true;
while (tru) {
msg = in.readUTF();
System.out.println(msg);
for (int i = 0; i <= 9; i++)
if (t[i] != null) {
t[i].out.writeUTF(msg);
System.out.println(t[i]);
}
}
} catch (IOException e) {
}
}
}
Your problem is not that the thread stays on, but rather that you have no mechanism for marking your client threads as finished. Even though the thread has exited, t[i] will not become null. It will still refer to an instance of a thread--just a "dead" thread.
Here's are two ways to fix it:
Just before your thread exits, mark t[i] = null (where i is the index of the current thread). Note that you'll need to store the value of i in each thread.
Modify clientThread and add private int threadIndex; as a member variable.
Modify clientThread's constructor and add threadIndex as a parameter.
public clientThread(Socket client, clientThread[] t, int threadIndex)
{
this.threadIndex=threadIndex;
//...
}
Right before the closing brace of run, add
synchronized(t){t[this.threadIndex]=null;}
Use an Executor and submit your clientThreads to it. Java's Executors will handle cleaning up threads for you.
Why are you creating 10 threads for only one socket connection? I think you'd want to create a single ClientThread per incoming connection to the chat server. Then add that single ClientThread to a List of active chats. When the chat client terminates the session, then remove the entry from that List. You don't need to pass the Thread instance, or the array of ClientThreads to the constructor of ClientThread because that is itself. Simply pass the Socket instance to ClientThread, and a reference to the ChatServer. If you are trying to create a chat room. Then allow the server to handle sending a message to everyone else:
public class ChatServer {
List<ClientThread> activeParticipants;
public void say( ClientThread author, String message ) {
for( ClientThread current : activeParticipants ) {
if( current != author ) {
current.send( message ); // this method will send a message to that client
}
}
}
}
You'll either need to use two threads, or use InputStream.available() method to check to see if some input is on either System.in or your socket's input stream. That will allow you to read messages coming in as well as allowing a user to type a message at the same time. Blocking on read() method would mean you couldn't see messages until you enter some data or receive data.
Also move the welcome message into the ClientThread so you don't call Socket.getOutputStream() twice using two different DataOutputStreams.
You call method client.getOutputStream() twice, building each time a DataOutputStream. Try to welcome the user directly in the ClientThread.