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.
Related
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.
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
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.
I'm creating a simple http server. I have a master thread that waits in a loop for a connection to be accepted. Once a connection is accepted, I create a new worker thread to handle the connection, passing the accepted socket as an argument. Once a connection is accepted, a new thread is created for it, however the master thread will loop again, create another socket with the same connection and create another duplicated thread.
Master thread waiting for connections.
public void run(){
while(Tester.serverStatus != "quit"){
try {
Socket clientSocket = serverSocket.accept();
new Thread(new Worker(clientSocket)).start();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
this.stop();
} catch (IOException e) {
e.printStackTrace();
}
return;
}
public void stop() throws IOException{
serverSocket.close();
return;
}
Worker thread pseudocode
public void run(){
InputStream input = clientSocket.getInputStream();
//read from stream, validate request and setup the response in a byte array
input.close();
DataOutputStream output = new DataOutputStream(clientSocket.getOutputStream());
output.write(responseByteArray);
output.flush();
output.close();
clientSocket.close();
return;
}
Any ideas as to why the accept() method isn't being blocked after the first connection is accepted? It just keeps on creating duplicate Worker threads with the same Socket.
Thanks
What you describe is not possible.
You undoubtedly have some static variables somewhere that should be instance members of Worker, such as the input and/or output streams, and/or the socket itself.