I'm making a simple chat program using sockets, and I have an ArrayList to store active objected classes with sockets and usernames for each connected client, and inside those classes it checks if the socket is still open, and calls for its self to be joined if it is not.
Server file kick code:
public synchronized void kick(ClientThread client){
try{
output.printLine("kicking " + client.getUsername());
clients.remove(client);
output.printLine("removed " + client.getUsername());
}catch(Exception e){
e.printStackTrace();
}
output.printLine("kicked ");
}
This is what is called by the client object if its socket is closed.
clients being the ArrayList which stores the clients
client being the class object which I want to join, the client object extends Thread
public void run(){
while(true){
try{
Thread.sleep(10);
if(isValid()){
/*bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
if(bufferedReader.ready()){
lastMsg = bufferedReader.readLine();
sendMessage("Hello");
bufferedReader.close();
}*/
}else{
output.printLine(this.getUsername() + " connection closed");
break;
}
}catch(Exception e){
e.printStackTrace();
}
}
server.kick(this);
try {
join();
} catch (InterruptedException e) {
e.printStackTrace();
}
output.printLine("joined " + getUsername());
}
This is the run function from the client object, at the bottom is the code which is run when the socket is not connected, it breaks from the loop and should join its self, however it hangs on joining its self. The client is removed from the ArrayList properly but no matter what i do i cannot get the thread to join.
This cannot work. To join a thread means waiting until it died. If you wait for yourself to die, you will wait forever, because as long as you wait you cannot die.
if the socket is still open, and calls for its self to be joined if it is not.
A thread cannot call for itself to be joined. If a thread wants to quit then it just returns from the run() method. Other threads that are waiting for that thread to die can call thread.join() on it. But as #Vampire pointed out, for a thread to call this.join() will mean that it is waiting for itself to finish but it never will because it is waiting for itself to finish. Joinception indeed.
but no matter what i do i cannot get the thread to join.
I think the question here is what are you trying to achieve. If you want the thread to finish then just return from the run() method. If you are trying to notify other threads that you are finishing then they should do the join-ing.
Related
Following is the code (JAVA) that accepts a client socket connection and assigns a thread to each connection.
ServerSocket m_ServerSocket = new ServerSocket();
while (true) {
java.util.Date today = Calendar.getInstance().getTime();
System.out.println(today+" - Listening to new connections...");
Socket clientSocket = m_ServerSocket.accept();
ClientServiceThread cliThread = new ClientServiceThread( clientSocket);
cliThread.start();
}
Suppose 5 clients are connected, hence 5 threads are running.
client 1: threadId 11
client 2: threadId 12
client 3 :threadId 13
client 4 :threadId 14
client 5 :threadId 15
Suppose one of the clients sends a message "kill-client1" , I to wish end client 1's connection and kill the thread with Id 11, something like this :
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
while (running) {
String clientCommand = in .readLine();
if (clientCommand.equalsIgnoreCase("Kill-client1")) {
// end the connection for client 1 & kill it's corresponding thread 11
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
How can I achieve this ?
Just keep track of all client sockets and/or handling threads.
Map<Integer,Socket> clients=new HashMap<>();
while (true) {
java.util.Date today = Calendar.getInstance().getTime();
System.out.println(today+" - Listening to new connections...");
Socket clientSocket = m_ServerSocket.accept();
clients.put(generateNewClientId(),clientSocket);
ClientServiceThread cliThread = new ClientServiceThread( clientSocket);
cliThread.start();
}
And then if you simply do
{
if (clientCommand.equalsIgnoreCase("Kill")) {
Socket socket=clients.get(idToShutDown);// get required id somehow (from request??)
socket.close();
}
}
This will close given socket resulting in breaking in.readLine() in handling thread thus finishing thread.
If you keep track of threads, you can set "interrupt" flag and probe it in while condition so your handling thread will be able to finish work gracefully.
You could do that by storing your Threads into a thread-safe map (as it will be accessed by several threads concurrently) using the thread id as key
// Map that will contain all my threads
Map<Long, ClientServiceThread> threads = new ConcurrentHashMap<>();
// Add to the constructor the instance of the class that manage the threads
ClientServiceThread cliThread = new ClientServiceThread(this, clientSocket);
// Add my new thread
threads.put(cliThread.getId(), cliThread);
cliThread.start();
Then when a kill is launched
String clientCommand = in.readLine().toLowerCase();
if (clientCommand.startsWith("kill")) {
main.interrupt(Long.valueOf(clientCommand.substring(4).trim()));
}
Then in the main class your method would look like:
public void interrupt(long threadId) {
// Remove the thread from the map
ClientServiceThread cliThread = threads.remove(threadId);
if (cliThread != null) {
// Interrupt the thread
cliThread.interrupt();
}
}
Finally you will need to make your class ClientServiceThread sensitive to interruptions
try {
...
while (!Thread.currentThread().isInterrupted()) {
// My code here
}
} finally {
clientSocket.close();
}
Just terminate the loop:
while (running) {
String clientCommand = in .readLine();
if (clientCommand.equalsIgnoreCase("Kill")) {
running = false;
}
}
or:
while (running) {
String clientCommand = in .readLine();
if (clientCommand.equalsIgnoreCase("Kill")) {
break;
}
}
And don't forget to close the socket in finally block.
To stop the current thread, you close the socket, and return from the run() method:
if (clientCommand.equalsIgnoreCase("Kill")) {
clientSocket.close();
return;
}
EDIT:
To close another thread, you can, for example
share a thread-safe map of clientID-Thread entries between threads. When a new client connects, you store the Thread started for this client in this map
when a Kill-client1 command comes in, you get the Thread corresponging the "client1" key from the map, and call ìnterrupt() on this thread.
in each thread (for example, the client1 thread), at each iteration of the loop, you check what the value of Thread.currentThread().isInterrupted(). If it's true, then you close the connection, remove the thread from the shared map, and return from the run() method.
The key point is that you never kill another thread. You always request a thread to stop by interrupting it, and the thread checks the value of its interrupt flag to decide when and how it must stop.
I got this question from Head First Java by Kathy Sierra and Bert Bates. In the Networking and Threads section of the book, they built a chat client and handled incoming messages by starting a separate thread:
public class IncomingReader implements Runnable {
public void run() {
String message;
try {
while ((message = reader.readLine()) != null) { //reader is a BufferedReader from an InputStreamReader of a Socket
System.out.println("read " + message);
incoming.append(message + "\n"); //incoming is a JTextArea they declared earlier
}
} catch (Exception ex) {ex.printStackTrace();}
}}
And this thread is started only once, after they setup the Swing GUI and the readers and writers.
So my question is, how is this thread able to stay alive and keep listening for incoming messages. Shouldn't it go past the while loop and die when message is null?
BufferedReader will keep on reading the input until it reaches the end. But if there is nothing to read, then it will keep looping or wait until there is input.
BufferedReader readLine() blocks
I've created a client-server connection, something like a chat system. Previously I was using a while loop on the client side, and it was waiting to read a message from the console every time (of course server has a while loop as well to serve forever). But now, I'm trying to first create a connection at the beginning of the session, and then occasionally send a message during the session, so to maintain a permanent and persistent connection.
Currently, without the while loop, the client closes the connection and I don't know how to find a workaround.
Here is the client code:
import java.net.*;
import java.io.*;
public class ControlClientTest {
private Socket socket = null;
// private BufferedReader console = null;
private DataOutputStream streamOut = null;
public static void main(String args[]) throws InterruptedException {
ControlClientTest client = null;
String IP="127.0.0.1";
client = new ControlClientTest(IP, 5555);
}
public ControlClientTest(String serverName, int serverPort) throws InterruptedException {
System.out.println("Establishing connection. Please wait ...");
try {
socket = new Socket(serverName, serverPort);
System.out.println("Connected: " + socket);
start();
} catch (UnknownHostException uhe) {
System.out.println("Host unknown: " + uhe.getMessage());
} catch (IOException ioe) {
System.out.println("Unexpected exception: " + ioe.getMessage());
}
String line = "";
// while (!line.equals(".bye")) {
try {
Thread.sleep(1000);
//TODO get data from input
// line = console.readLine();
line="1";
if(line.equals("1"))
line="1,123";
streamOut.writeUTF(line);
streamOut.flush();
} catch (IOException ioe) {
System.out.println("Sending error: " + ioe.getMessage());
}
// }
}
public void start() throws IOException {
// console = new BufferedReader(new InputStreamReader(System.in));
streamOut = new DataOutputStream(socket.getOutputStream());
}
}
And here is the Server code:
import java.awt.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class ControlServer {
private Socket socket = null;
private ServerSocket server = null;
private DataInputStream streamIn = null;
public static void main(String args[]) {
ControlServer server = null;
server = new ControlServer(5555);
}
public ControlServer(int port) {
try {
System.out
.println("Binding to port " + port + ", please wait ...");
server = new ServerSocket(port);
System.out.println("Server started: " + server);
System.out.println("Waiting for a client ...");
socket = server.accept();
System.out.println("Client accepted: " + socket);
open();
boolean done = false;
while (!done) {
try {
String line = streamIn.readUTF();
// TODO get the data and do something
System.out.println(line);
done = line.equals(".bye");
} catch (IOException ioe) {
done = true;
}
}
close();
} catch (IOException ioe) {
System.out.println(ioe);
}
}
public void open() throws IOException {
streamIn = new DataInputStream(new BufferedInputStream(
socket.getInputStream()));
}
public void close() throws IOException {
if (socket != null)
socket.close();
if (streamIn != null)
streamIn.close();
}
}
I would like to summarize some good practices regarding the stability of TCP/IP connections which I apply on a daily basis.
Good practice 1 : Built-in Keep-Alive
socket.setKeepAlive(true);
It automatically sends a signal after a period of inactivity and checks for a reply. The keep-alive interval is operating system dependent though, and has some shortcomings. But all by all, it could improve the stability of your connection.
Good practice 2 : SoTimeout
Whenver you perform a read (or readUTF in your case), your thread will actually block forever. In my experience this is bad practice for the following reasons: It's difficult to close your application. Just calling socket.close() is dirty.
A clean solution, is a simple read time-out (e.g. 200ms). You can do this with the setSoTimeoutmethod. When the read() method timeouts it will throw a SocketTimeoutException. (which is a subclass of IOException).
socket.setSoTimeout(timeoutInterval);
Here is an example to implement the loop. Please note the shutdown condition. Just set it to true, and your thread will die peacefully.
while (!shutdown)
{
try
{
// some method that calls your read and parses the message.
code = readData();
if (code == null) continue;
}
catch (SocketTimeoutException ste)
{
// A SocketTimeoutExc. is a simple read timeout, just ignore it.
// other IOExceptions will not be stopped here.
}
}
Good practice 3 : Tcp No-Delay
Use the following setting when you are often interfacing small commands that need to be handled quickly.
try
{
socket.setTcpNoDelay(true);
}
catch (SocketException e)
{
}
Good practice 4 : A heartbeat
Actually there are a lot of side scenario's that are not covered yet.
One of them for example are server applications that are designed to only communicate with 1 client at a time. Sometimes they accept connections and even accept messages, but never reply to them.
Another one: sometimes when you lose your connection it actually can take a long time before your OS notices this. Possibly due to the shortcomings described in good practice 3, but also in more complex network situations (e.g. using RS232-To-Ethernet converters, VMware servers, etc) this happens often.
The solution here is to create a thread that sends a message every x seconds and then waits for a reply. (e.g. every 15 seconds). For this you need to create a second thread that just sends a message every 15 seconds. Secondly, you need to expand the code of good practice 2 a little bit.
try
{
code = readData();
if (code == null) continue;
lastRead = System.currentTimeMillis();
// whenever you receive the heart beat reply, just ignore it.
if (MSG_HEARTBEAT.equals(code)) continue;
// todo: handle other messages
}
catch (SocketTimeoutException ste)
{
// in a typical situation the soTimeout is about 200ms
// the heartbeat interval is usually a couple of seconds.
// and the heartbeat timeout interval a couple of seconds more.
if ((heartbeatTimeoutInterval > 0) &&
((System.currentTimeMillis() - lastRead) > heartbeatTimeoutInterval))
{
// no reply to heartbeat received.
// end the loop and perform a reconnect.
break;
}
}
You need to decide if your client or server should send the message. That decision is not so important. But e.g. if your client sends the message, then your client will need an additional thread to send the message. Your server should send a reply when it receives the message. When your client receives the answer, it should just continue (i.e. see code above). And both parties should check: "how long has it been?" in a very similar way.
You could wrap a thread around the connection and have it periodically send a status to keep the line open, say every 30 seconds or whatever. Then, when it actually has data to send it would reset the keep alive to be 30 seconds after the last transmission. The status could be helpful to see if the client is still alive anyway, so at least it can be a useful ping.
Also, you should change your server code, you appear to only handle one connection at the moment. You should loop and when a socket connection comes in spawn a thread to handle the client request and go back to listening. I may be reading to much into what may just be your test code, though.
Make the client socket connection wrapped around a thread. Use a blocking queue to wait for messages. There should only be a single sender queue throughout your application, so use a singleton pattern.
e.g.
QueueSingleton queue = QueueSingleton.getSenderQueue();
Message message = queue.take() // blocks thread
send(message); //send message to server
When you need to send a message to the server, you can use the blocking queue to send the message.
QueueSingleton queue = QueueSingleton.getSenderQueue();
queue.put(message)
The client thread will wake up and process the message.
For maintaining the connection, use a timer task. This is special type of thread that calls a run method repetitively at specified periods. You can use this to post a message, a ping message, every so often.
For processing the received message, you could have another thread, waiting for messages on another blocking queue (receiver queue). The client thread will put the received message on this queue.
I have socket server in Java and other side socket client in PHP
I want to process socket request from PHP in java in same time by multi-threading but java do it one by one , wait to finish first request and the start second one ,
here is my code in JAVA :
while (true) {
try {
clientSocket = serverSocket.accept();
int i = 0;
for (i = 0; i < maxClientsCount; i++) {
if (threads[i] == null) {
(threads[i] = new clientThread(clientSocket, threads)).start();
break;
}
}
if (i == maxClientsCount) {
PrintStream os = new PrintStream(clientSocket.getOutputStream());
os.println("Server too busy. Try later.");
os.close();
clientSocket.close();
}
} catch (IOException e) {
System.out.println(e);
}
}
class clientThread extends Thread {
public clientThread(Socket clientSocket, clientThread[] threads) {
this.clientSocket = clientSocket;
this.threads = threads;
maxClientsCount = threads.length;
}
public void run() {
int maxClientsCount = this.maxClientsCount;
clientThread[] threads = this.threads;
try {
in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
URL aURL = new URL(RecivedURL);
// start out put
System.out.println("host = " + aURL.getHost());
// end out put
the BOLD line is example of my output , but I want to start output of multi started request in same time in same time .. JAvA wait to finish a request in one time for my code ..
I don't see why you'd want more than two threads here.
If you want to process request one by one, you might spawn just one thread that just listens the requests and immediately responds to it by sending a "processing" or a "check back later" message. (call this a listener thread)
if a client is sent a "processing" response the connection is kept alive and another thread is spawned that responds to the client with the actual processed result of request. (call this a processing thread).
You could make the listener thread send a keep alive message to the client in queue or you could ask it to check back after a set period of time with a request. You could make the listener thread more sophisticated by setting up queues to decide when to subsequently respond to clients who were sent "check back later" message
From implementation POV, your main thread could be your listener thread and it could spawn a processing thread when it's time to process a request.
I assume that it's executed so fast that the last request is finished before the next one can be accepted.
For debug purposes try to add:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
into the run method so you can easier check if it's really not running in parallel.
Basically I have a ServerSocket listener , on new incoming connection the program executes a thread to serve it , after the thread finishes , the program doesn't continue
this is the listener
client = listenSocket.accept();
new HandleConnection(client);//HandleConnections extends thread and start
//method is called in the constructor
counter++;
System.out.println("Number of clients served : " + counter);
this is the thread
public HandleConnection(Socket client) {
this.client = client;
this.start();
}
public void run() {
try {
in = new BufferedReader(new InputStreamReader(
client.getInputStream()));
out = new PrintWriter(client.getOutputStream(), true);
handler();
System.out.println("Ending Thread !");
} catch (IOException e) {
//System.out.println("socket closed");
e.printStackTrace();
}
}
the message "Ending Thread !" is executed normally , but the counter++ and the following println statement are never executed
the message "Ending Thread !" is executed normally , but the counter++ and the following println statement are never executed
So if new HandleConnection(client); actually starts a new thread (which you should not do in a constructor, see below), then the counter++ should immediately be executed and the "Number of clients... message printed. Any chance the message is appearing above the "Ending Thread!" message in your logs? Typically it takes some time to start the actual thread so the caller will continue to execute before the run() method is entered.
Other comments about your code:
As #MarkoTopolnik mentions, you need to close the input and output streams in your run() method. finally clauses are a required pattern there.
You should never call Thread.start() in an object constructor because of Thread race condition issues around object construction. See: Why not to start a thread in the constructor? How to terminate?
Instead of extending Thread you should consider implementing Runnable and doing something like:
new Thread(new HandleConnection(client)).start();
Event better than managing the threads yourself would be to use an ExecutorService thread-pool for your client handlers. See this tutorial.
The typical way to do this is to perform something like this:
ServerSocket listener = new ServerSocket(3030); //Create a new socket to listen on
try
{
//While we are running, if a client connects
//accept the connect and increment the client ID
while (true)
{
new udSocketServer(listener.accept()).start();
}
}
finally //Gracefully close
{
listener.close(); //Close socket object
}
You could then call the shared variable 'counter' in the thread constructor. If you need more than this, let me know and I will edit.
But in reality you need a little more code for us to answer.