36933

Try-with-resources closes sockets of spawned childs

Question:

I want to write a simple server that listens on a port and spawns new threads for handling new connections. I attempted to use <a href="http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html" rel="nofollow">try-with-resources</a> for accepting new connections but failed because sockets in child threads seem to be closed immediately and I don't understand why.

Here are 2 simplified examples.<br /> a) The working example of the server (without try-with-resources):

package MyTest; import java.io.BufferedReader; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class MyServerA implements Runnable { private int port; private ServerSocket serverSocket; public MyServerA(Integer port) { this.port = port; } @Override public void run() { try { serverSocket = new ServerSocket(port); } catch(IOException ioe) { System.err.println("error opening socket. " + ioe.getStackTrace()); } while (true) { Socket clientSocket = null; try { clientSocket = serverSocket.accept(); ClientServiceThread cliThread = new ClientServiceThread(clientSocket); cliThread.start(); } catch (IOException e) { e.printStackTrace(); } } } class ClientServiceThread extends Thread { private Socket s; boolean goOn = true; ClientServiceThread(Socket s) { this.s = s; } public void run() { BufferedReader in = null; PrintWriter out = null; try { in = new BufferedReader(new InputStreamReader(this.s.getInputStream())); out = new PrintWriter(new OutputStreamWriter(this.s.getOutputStream())); while (goOn) { final String req = in.readLine(); if (req != null) { System.out.println("got: " + req); out.println("you said: " + req); out.flush(); if (req.contains("bye")) { System.out.println("closing thread"); goOn = false; } } } s.close(); } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { MyServerA a = new MyServerA(30000); a.run(); } }

b) Exactly the same, but with try-with-resources (doesn't work):

package MyTest; import java.io.BufferedReader; public class MyServerB implements Runnable { private int port; private ServerSocket serverSocket; public MyServerB(Integer port) { this.port = port; } @Override public void run() { try { serverSocket = new ServerSocket(port); } catch(IOException ioe) { System.err.println("error opening socket. " + ioe.getStackTrace()); } while (true) { try (Socket clientSocket = serverSocket.accept();) { ClientServiceThread cliThread = new ClientServiceThread(clientSocket); cliThread.start(); } catch (IOException e) { e.printStackTrace(); } } } class ClientServiceThread extends Thread { private Socket s; boolean goOn = true; ClientServiceThread(Socket s) { this.s = s; } public void run() { BufferedReader in = null; PrintWriter out = null; try { in = new BufferedReader(new InputStreamReader(this.s.getInputStream())); out = new PrintWriter(new OutputStreamWriter(this.s.getOutputStream())); while (goOn) { final String req = in.readLine(); if (req != null) { System.out.println("got: " + req); out.println("you said: " + req); out.flush(); if (req.contains("bye")) { System.out.println("closing thread"); goOn = false; } } } s.close(); } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { MyServerB b = new MyServerB(30000); b.run(); } }

The example in a) works like expected. The example in b) accepts a connection but closes it immediately. Can someone explain to me why and tell me how I do this properly?

Answer1:

The structure

try (resource = ...) { }

is equivalent to

resource = null; try { resource = ...; } finally { if (resource != null) { resource.close(); } }

That's it. It is just a syntactic sugar, just shorter way to write the same. So, when you put statement Socket clientSocket = serverSocket.accept(); into try-with-resource block you actually close it once you leave the block.

This structure is good when processing of stream is done synchronously, i.e. when you open stream, read or write and close it.

In your case you get the stream and process it in separate thread and therefore cannot close it immediately. Client should decide to close the stream itself. For example when user press button "disconnect" or when server sends special application level command "close connection" or if IOException is thrown.

Recommend

  • Socket closed exception
  • Using Java Websocket API Implementation without a Web-Server
  • Close listening ServerSocket
  • NumberFormatException in Java for a string that is a number
  • Python Socket - Multiple Clients
  • Does an Android Device have to be rooted in order to telnet to it?
  • Recive different type of objects on the same TCP socket
  • java.net.Socket > outputStream > BufferedOutputStream flush() confirmation
  • How to send an std::vector of unsigned char over an UDP socket using boost asio?
  • VerifyInputWhenFocusTarget property has no effect
  • How to read data from socket connection - android
  • Cannot send user message with Spring Websocket
  • Implementing java gui login using multithreading
  • Error in making a socket connection
  • Regarding starting the threads on a condition
  • Z3: Convert between FP and BitVector?
  • Date Conversion from yyyy-mm-dd to dd-mm-yyyy
  • NHibernate Validation Localization with S#arp Architecture
  • how to do an event when i swipe from fragment to the other
  • Update CALayer sublayers immediately
  • JFileChooser in front of fullscreen Swing application
  • Counter field in MS Access, how to generate?
  • Javascript + PHP Encryption with pidCrypt
  • Convert array of 8 bytes to signed long in C++
  • SVN: Merging two branches together
  • Hibernate gives error error as “Access to DialectResolutionInfo cannot be null when 'hibernate.
  • How get height of the a view with gone visibility and height defined as wrap_content in xml?
  • FormattedException instead of throw new Exception(string.Format(…)) in .NET
  • How to CLICK on IE download dialog box i.e.(Open, Save, Save As…)
  • Getting Messege Twice Using IMvxMessenger
  • Exception on Android 4.0 `android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode)`
  • Can Visual Studio XAML designer handle font family names with spaces as a resource?
  • unknown Exception android
  • EntityFramework adding new object to nested object collection
  • Checking variable from a different class in C#
  • Sorting a 2D array using the second column C++
  • How can i traverse a binary tree from right to left in java?
  • failed to connect to specific WiFi in android programmatically
  • java string with new operator and a literal
  • How can I use threading to 'tick' a timer to be accessed by other threads?