I'm trying to create a multi threaded server to which multiple clients can connect and can be served. However, I'm not sure on how to properly free up my resources should the need arise.
My server runs an input thread (waiting for user inputs) and a procressing thread (handles connections and users). I open up a ServerSocket in the server class and pass it to my processing thread. It looks like this:
public class ClientConnector implements Runnable {
private ServerSocket serverSocket;
public ClientConnector(ServerSocket serverSocket) {
this.serverSocket = serverSocket;
}
#Override
public void run() {
ExecutorService tcpExecutor = Executors.newCachedThreadPool();
while (!serverSocket.isClosed()) {
Socket clientSocket = null;
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("could not accept connection");
}
if (clientSocket != null) {
tcpExecutor.execute(new ClientHandler(clientSocket);
}
}
}
}
If I want to exit, I just run this method in my server class to close the ServerSocket:
public void exit() {
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Which should cause the next serverSocket.accept() call to throw an exception, and the loop stops since the socket is closed.
My question is - does closing a ServerSocket implicitly close ClientSockets that were created using it? Or should I make sure to close every single open ClientSocket by hand? If so, is there an easy way to do so instead of saving every single connection made to the server somewhere?
does closing a ServerSocket implicitly close ClientSockets that were created using it?
No, it has no effect on them.
Or should I make sure to close every single open ClientSocket by hand?
Yes, and you should be doing that anyway, in every handler thread.
If so, is there an easy way to do so instead of saving every single connection made to the server somewhere?
Just impose a read timeout and close each socket that times out. This is a normal part of any server. You don't have to collect the sockets or take any special measures about them for shutdown.
Let the client handler thread, closes the client socket on the end of processing.
Related
So my program has clients that are entering tasks and they can see each other tasks but i want the server to close when all the clients are shutdown by a command and i don't want to look for more clients after the last one closes.
What i have tried is counting the number of clients that entered and when there is none, the problem is that the server tries to accept new clients and does't check the condition can any one help me?
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(4242);
while (acceptNewClients) {
Socket clientSocket = serverSocket.accept();
countClient++;
System.out.println(countClient);
ThreadedServer clientThread = new ThreadedServer(clientSocket);
new Thread(clientThread).start();
if (countClient == 0) {
flipAcceptNewClients();
}
}
}catch (IOException e) {
e.printStackTrace();
}
If you want to shut down the server, call System.exit(0); to do so.
interrupting the thread that is blocking on serverSocket.accept() may or may not work; depends on the OS and JVM, hence, that's not a great way to do this.
I'm trying to create a multi threaded server to which multiple clients can connect and can be served. However, I'm not sure on how to properly free up my resources should the need arise.
My server runs an input thread (waiting for user inputs) and a procressing thread (handles connections and users). I open up a ServerSocket in the server class and pass it to my processing thread. It looks like this:
public class ClientConnector implements Runnable {
private ServerSocket serverSocket;
public ClientConnector(ServerSocket serverSocket) {
this.serverSocket = serverSocket;
}
#Override
public void run() {
ExecutorService tcpExecutor = Executors.newCachedThreadPool();
while (!serverSocket.isClosed()) {
Socket clientSocket = null;
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("could not accept connection");
}
if (clientSocket != null) {
tcpExecutor.execute(new ClientHandler(clientSocket);
}
}
}
}
If I want to exit, I just run this method in my server class to close the ServerSocket:
public void exit() {
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Which should cause the next serverSocket.accept() call to throw an exception, and the loop stops since the socket is closed.
My question is - does closing a ServerSocket implicitly close ClientSockets that were created using it? Or should I make sure to close every single open ClientSocket by hand? If so, is there an easy way to do so instead of saving every single connection made to the server somewhere?
does closing a ServerSocket implicitly close ClientSockets that were created using it?
No, it has no effect on them.
Or should I make sure to close every single open ClientSocket by hand?
Yes, and you should be doing that anyway, in every handler thread.
If so, is there an easy way to do so instead of saving every single connection made to the server somewhere?
Just impose a read timeout and close each socket that times out. This is a normal part of any server. You don't have to collect the sockets or take any special measures about them for shutdown.
Let the client handler thread, closes the client socket on the end of processing.
This question already has an answer here:
Proper way to close an AutoCloseable
(1 answer)
Closed 3 years ago.
This is a simple TCP server. How can i close the socket when the program is terminated?
I have using try/finally and try to close the socket. But it doesn't run the finally block when I exit the program.
Anyone can have idea on how to close the socket in a proper way?
try {
socket = new ServerSocket(port);
System.out.println("Server is starting on port " + port + " ...");
}catch (IOException e){
System.out.println("Error on socket creation!");
}
Socket connectionSocket = null;
try{
while(true){
try{
connectionSocket = socket.accept();
Thread t = new Thread(new ClientConnection(connectionSocket));
t.start();
}catch (IOException e) {
System.out.println("Error on accept socket!");
}
}
}finally{
this.socket.close();
System.out.println("The server is shut down!");
}
After creating your ServerSocket, you could add a ShutdownHook to close it on JVM termination, something like this:
Runtime.getRuntime().addShutdownHook(new Thread(){public void run(){
try {
socket.close();
System.out.println("The server is shut down!");
} catch (IOException e) { /* failed */ }
}});
Invoking ServerSocket#close will terminate the blocking ServerSocket.accept call, causing it to throw a SocketException. However, note that your current handling of IOException in the while loop means you will then re-enter the while loop to attempt accept on a closed socket. The JVM will still terminate, but it's a bit untidy.
Shutdown hooks do not run if you terminate a console application in Eclipse (on Windows at least). But they do run if you CTRL-C Java in a normal console. For them to run, you need the JVM to be terminated normally, e.g. SIGINT or SIGTERM rather than SIGKILL (kill -9).
A simple program which you can execute in Eclipse or a console will demonstrate this.
public class Test implements Runnable {
public static void main(String[] args) throws InterruptedException {
final Test test = new Test();
Runtime.getRuntime().addShutdownHook(new Thread(){public void run(){
test.shutdown();
}});
Thread t = new Thread(test);
t.start();
}
public void run() {
synchronized(this) {
try {
System.err.println("running");
wait();
} catch (InterruptedException e) {}
}
}
public void shutdown() {
System.err.println("shutdown");
}
}
No need in your particular case, the operating system will close all the TCP sockets for you when the program exits.
From javadoc :
The Java runtime automatically closes the input and output streams,
the client socket, and the server socket because they have been
created in the try-with-resources statement.
Also
The finalize() method is called by the Java virtual machine (JVM)
before the program exits to give the program a chance to clean up and
release resources. Multi-threaded programs should close all Files and
Sockets they use before exiting so they do not face resource
starvation. The call to server.close() in the finalize() method closes
the Socket connection used by each thread in this program.
protected void finalize(){
//Objects created in run method are finalized when
//program terminates and thread exits
try{
server.close();
} catch (IOException e) {
System.out.println("Could not close socket");
System.exit(-1);
}
}
Howcome the finally is not run? Probably the while(true) should be replaced with something like
while (!shutdownRequested)
alternatively you can create a shutdown hook that handles the socket close
Well, how do you "exit" the program? finally will be executed if an exception will be thrown or if the try block finishes its execution in a "normal" way but I think that might be "hard" because of your while(true).
To close the socket you should use socket.close() and I would recommend you not to rely on the destroy function.
I'm reading a book "java networking 4th edition" and in the 9th chapter about server sockets while explaining multithreaded server where each client is handled with the single thread it said the following:
Example 9-3 deliberately does not use try-with-resources for the client sockets accepted by the server
socket. This is because the client socket escapes from the try block into a separate thread.
If you used try-with-resources, the main thread would close the socket as soon as it got
to the end of the while loop, likely before the spawned thread had finished using it.
Here is the Example 9-3
import java.net.*;
import java.io.*;
import java.util.Date;
public class MultithreadedDaytimeServer {
public final static int PORT = 13;
public static void main(String[] args) {
try (ServerSocket server = new ServerSocket(PORT)) {
while (true) {
try {
Socket connection = server.accept();
Thread task = new DaytimeThread(connection);
task.start();
} catch (IOException ex) {}
}
} catch (IOException ex) {
System.err.println("Couldn't start server");
}
}
private static class DaytimeThread extends Thread {
private Socket connection;
DaytimeThread(Socket connection) {
this.connection = connection;
}
#Override
public void run() {
try {
Writer out = new OutputStreamWriter(connection.getOutputStream());
Date now = new Date();
out.write(now.toString() +"\r\n");
out.flush();
} catch (IOException ex) {
System.err.println(ex);
} finally {
try {
connection.close();
} catch (IOException e) {
// ignore;
}
}
}
}
}
I don't really understand why is this happening, why would main thread want to close the socket from the other thread, is it because socket object was created in the main thread and reference was supplied in thread constructor?
What the book is saying is that they chose to do this
try {
Socket connection = server.accept();
Thread task = new DaytimeThread(connection);
task.start();
} catch (IOException ex) {}
instead of
try(Socket connection = server.accept()) {
Thread task = new DaytimeThread(connection);
task.start();
} catch (IOException ex) {}
because when use a try-with-resources block, it closes whatever you put in the parentheses try(...) immediately after it is done. But you do not want this to happen. The connection socket is meant to stay open because it is going to be used in the DaytimeThread that was started.
The main thread doesn't want to close the resource because the spawned thread executes asynchronously.
Within the try, task.start() begins execution of the thread, but it does not wait for it to finish. Therefore, it is possible (even likely) that the main method will reach the end of its try before DaytimeThread.run() finishes.
If the main method's try was a try-with-resources, the connection would be closed at this time. Then, as the DaytimeThread continues to do its work in another thread, it would attempt to use that connection after it is closed.
But to answer your actual question:
why would main thread want to close the socket from the other thread
It's not a socket from another thread. Actually, the main method is accepting the socket connection and then giving it to the DaytimeThread.
Typically, an entity responsible for obtaining a close-able resource should also be responsible for closing it. The simple way to accomplish this is with a try-with-resources. However, this principle cannot be applied with this design because a thread may need the resource after the main thread is done with it.
In my Server application I'm trying to handle the Server which is using ServerSocket like,
Start the server and wait for connection.
Stop the server which is connected with a client.
Stop the server which is waiting for a client.
I can able to start the server and make it to wait for client inside a thread using
socket = serverSocket.accept();
What I want to do is I want manually close the socket which is waiting for connection, I have tried using,
if (thread != null) {
thread.stop();
thread = null;
}
if (socket != null) {
try {
socket.close();
socket = null;
}
catch (IOException e) {
e.printStackTrace();
}
}
After executing the above code even though the socket becomes null, when I try to connect from client to server, the connection gets established, so my question is how to interrupt the serversocket which listening for connection over here,
socket = serverSocket.accept();
I think a common way of handling this is make the accept() call time out in a loop.
So something like:
ServerSocket server = new ServerSocket();
server.setSoTimeout(1000); // 1 second, could change to whatever you like
while (running) { // running would be a member variable
try {
server.accept(); // handle the connection here
}
catch (SocketTimeoutException e) {
// You don't really need to handle this
}
}
Then, when you wanted to shut down your server, just have your code set 'running' to false and it will shut down.
I hope this makes sense!
Just close the ServerSocket, and catch the resulting SocketClosedException.
And get rid of the thread.stop(). For why, see the Javadoc.