Sorry for question, but I'm totally noob in Java. What is the best practice to execute ServerSocket.close() when caught IOException from ServerSocket? According to docs, ServerSocket.close() throws IOException and compiler asks us to catch it. What is the proper way to close connection on IOException?
try {
server = new ServerSocket(this.getServerPort());
while(true) {
socket = server.accept();
new Handler( socket );
}
} catch (IOException e) {
if (server != null && !server.isClosed()) {
server.close(); //compiler do not allow me to do because I should catch IOExceoption from this method also...
}
}
Thank you!
That's ugly in Java. I hate it, but this is the way you should do it: Wrapping it into another try-catch:
try {
server = new ServerSocket(this.getServerPort());
while(true) {
socket = server.accept();
new Handler( socket );
}
} catch (IOException e) {
if (server != null && !server.isClosed()) {
try {
server.close();
} catch (IOException e)
{
e.printStackTrace(System.err);
}
}
}
If you are going to close the ServerSocket outside of the try{}catch{} anyways, you may as well put it in a finally{}
try {
server = new ServerSocket(this.getServerPort());
while(true) {
socket = server.accept();
new Handler( socket );
}
} catch (IOException e) {
// Do whatever you need to do here, like maybe deal with "socket"?
}
finally {
try {
server.close();
} catch(Exception e) {
// If you really want to know why you can't close the ServerSocket, like whether it's null or not
}
}
In Java SE 7 or later you can use try-with-resources statement, ServerSocket implements java.io.Closeable, so you don't need to explicitly #close() the socket when used in this way.
try (ServerSocket server = new ServerSocket(this.getServerPort())) {
while(true) {
socket = server.accept();
new Handler( socket );
}
} catch (IOException e) {
// It's already closed, just print the exception
System.out.println(e);
}
You can close the resources in the finally block,
http://download.oracle.com/javase/tutorial/essential/exceptions/finally.html
} finally {
try {
socket.close();
} catch(IOException e) {
e.printStackTrace();
}
}
Related
I have web service written on JAVA (version 1.8) which connects HSM and sends/receives data via socket. My application is deployed on Apache Tomcat/8.5.14 on linux.
Although I'm closing socket connection properly I have
java.net.SocketException: Too many open files
and here is myclass
public class myClass implements AutoCloseable {
Socket socket;
DataInputStream in;
DataOutputStream out;
public myClass(String ip, int port) throws Exception {
try {
socket = new Socket(ip, port);
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
} catch (IOException e) {
throw new Exception("Connecting to HSM failed" + e);
}
}
public String sendCommandToHsm(String command) throws IOException {
out.writeUTF(command);
out.flush();
return in.readUTF();
}
#Override
public void close() {
if (socket != null && !socket.isClosed()) {
try {
socket.close();
} catch (IOException e) {
lgg.info("Closing of socket failed", e);
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
lgg.info("Closing of inputStream failed", e);
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
lgg.info("Closing of outputStream failed", e);
}
}
}
}
Here is using of my class
try (MyClass myClass = new MyClass(ip, port);) {
myClass.sendCommandToHsm("my command");
}
I increased maximum open files limit on server from default value(1024) to 8192 and few times later the same Exception occurred again.
I'm thinking about creating Socket Connection Pool, is it good idea?
Can you suggest any other solutions?
Although I'm closing socket connection properly ...
It looks like you are, but I think there are a couple of problems. (I don't know that these are the cause of your leak, but the first one is a plausible explanation.)
Problem 1.
public myClass(String ip, int port) throws Exception {
try {
socket = new Socket(ip, port);
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
} catch (IOException e) {
throw new Exception("Connecting to HSM failed" + e);
}
}
If an exception is thrown during setup of the streams, then the socket will be leaked.
Problem 2.
public void close() {
if (socket != null && !socket.isClosed()) {
try {
socket.close();
} catch (IOException e) {
lgg.info("Closing of socket failed", e);
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
lgg.info("Closing of inputStream failed", e);
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
lgg.info("Closing of outputStream failed", e);
}
}
}
You are closing in the wrong order. You should1 close in and out before closing socket. In particular, if out has buffered data, then closing out will attempt to flush ... which will fail if you have closed socket already.
Also if socket.close() or in.close() fails for some other reason than an IOException, then the subsequent closes will be skipped. So you should use a finally here.
Also the isClosed() call is redundant. Calling close() on a resource that is already closed should do nothing. This is part of the contract of close().
Finally, calling close() on a socket should2 automatically close the low-level file descriptors beneath in and out. So it is arguably best to just do this:
public void close() {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
lgg.info("Closing of socket failed", e);
}
}
}
If this doesn't fix your leaks, I suggest that you use netstat and lsof to try to find out if the leakage is open files or open sockets.
I'm thinking about creating Socket Connection Pool, is it good idea?
Yes ... if you can find an existing (well designed and tested) library that meets your requirements. Implementing a reliable pool from scratch is not trivial.
But note:
An incorrectly implemented (or used) pool can leak file descriptors.
The server-side needs to be able to cope with a series of requests / replied on the same connection.
If you have too many simultaneous open connections to different places, then the pool needs a way to close some of them ...
1 - It is debatable whether you should close out before in. On the one hand, closing out flushes outstanding data to the server. On the other hand, by the time that myClass.close() has been called there won't be anything reading the server's response. And besides, the sendCommandToHsm method flushes ... so there shouldn't be any outstanding data.
2 - The javadoc for Socket.close() says: "Closing this socket will also close the socket's InputStream and OutputStream."
I made a simple app works with socket to transfer data between client and server over local network,
Server java codes:
try {
serverSocket = new ServerSocket(8888);
System.out.println("Listening :8888");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (true) {
try {
socket = serverSocket.accept();
dataInputStream = new DataInputStream(socket.getInputStream());
dataOutputStream = new DataOutputStream(
socket.getOutputStream());
System.out.println("ip: " + socket.getInetAddress());
String message = dataInputStream.readUTF();
// System.out.println("message: " + dataInputStream.readUTF());
try {
JSONObject jObj = new JSONObject(message);
String flag = jObj.getString("flag");
if (flag.equals("request")) {
String request = jObj.getString("request");
if (request.equals("getGroup"))
dataOutputStream.writeUTF(getGroup());
else if (request.equals("getFood")) {
String groupID = jObj.getString("groupID");
dataOutputStream.writeUTF(getFood(groupID));
}
}
} catch (JSONException | IOException e) {
e.printStackTrace();
}
// dataOutputStream.writeUTF("Hello!");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (dataInputStream != null) {
try {
dataInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (dataOutputStream != null) {
try {
dataOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
and android client codes:
class Load extends AsyncTask<String, String, String> {
String response;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
protected String doInBackground(String... args) {
Socket socket = null;
DataOutputStream dataOutputStream = null;
DataInputStream dataInputStream = null;
try {
socket = new Socket("192.168.1.106", 8888);
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataInputStream = new DataInputStream(socket.getInputStream());
dataOutputStream.writeUTF(utils.getGroup());
response = dataInputStream.readUTF();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (dataOutputStream != null) {
try {
dataOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (dataInputStream != null) {
try {
dataInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
protected void onPostExecute(String file_url) {
showGroup(response);
}
}
How many clients this can handle?
Is there a better solution?
How many clients this can handle?
Basically your code is an iterative server. There’s one big loop, and in each pass through the loop a single connection is completely processed.
A: So in this sense it can handle only one client at a time.
If you want to suport more than one client at a time your server should service multiple clients simultaneously through the use of threads (one thread per each client connection).
The basic flow of logic in such a server is this:
while (true) {
accept a connection;
create a thread to deal with the client;
}
Please refer to the following tutorial for a full explanation and even some code example.
Is there a better solution?
In the Android side, as pointed out in my comment based in the answer here. Using AsyncTask for HTTP communications can have some drawbacks like:
You cannot cancel a request during execution.
The patterns of using AsyncTask also commonly leak a reference to an Activity...
A: A library like OkHttp can apply as a more robust alternative.
How do you make a client which is able to send a server multiple messages at anytime, and therefore a server listening for a message all the time.
Right now I have wrote some code which only allows me to send a message once. I thought this was due to me closing the input/output streams and the sockets. So I have been playing around for a while now and I can't seem to do it!
Client:
public class Client {
private Socket socket;
private OutputStream os;
public Client() {}
public void connectToServer(String host, int port) {
try {
socket = new Socket(host, port);
} catch (IOException e) {
e.printStackTrace();
}
sendMessage();
}
public void sendMessage() {
try {
os = socket.getOutputStream();
String string = "Anthony";
byte[] b = string.getBytes(Charset.forName("UTF-8"));
os.write(b);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void STOP() {
stopOutput();
stopServer();
}
public void stopServer() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stopOutput() {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Server:
public class ConnectionHandler implements Runnable {
private Socket clientSocket;
private BufferedReader in;
public ConnectionHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
String clientAddress = clientSocket.getInetAddress().toString()
.substring(1);
System.out.println("Connected to " + clientAddress);
try {
in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
while (true) {
try {
ArrayList<String> data = new ArrayList<String>();
String inputLine;
while ((inputLine = in.readLine()) != null) {
data.add(inputLine);
}
if (data.size() > 0) {
System.out.println(data.toString());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void STOP() {
stopInput();
stopConnection();
}
public void stopInput() {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stopConnection() {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
At the moment on the client side, I send a message as soon as the socket is opened but after when I call the send function from another class it does not send...
How should I do this? Or what am I doing wrong?
Thanks in advance.
p.s. I am guessing client-server is the same as server-client, so if I know how to do one way I can easily switch it around... right?
Turns outs it was a simple error.
I as writing (sending-client) as an OutputStream however I was then reading (receiving-server) as BufferedReader! ha
So quick tip for anyone, make sure you receive messages the same way you send them!
Thanks for everyone who tried helping.
Your server is accepting data all the time, so you just have to save the OutputStream of you Client somewhere and write data to it every now and then. But do not close it, because then you close the Client socket, too.
After you have done that, you would need to change something else, because now your call of in.readLine() blocks your server, because it waits for the client to send something. To prevent that, you could try to add sending a String like "close" to the server when you want to close your client, something like that:
public void STOP() {
os.write("close".getBytes(Charset.forName("UTF-8")));
stopOutput();
stopServer();
}
and change the code in your server to
try {
ArrayList<String> data = new ArrayList<String>();
String inputLine;
while (!(inputLine = in.readLine()).equals("close")) {
data.add(inputLine);
}
if (data.size() > 0) {
System.out.println(data.toString());
}
} catch (IOException e) {
e.printStackTrace();
}
i have this code to do chatting
but it did not work , but somebody told me that i should use byte array and a string but i did not understand i hope you can help me to fix this problem , this code belongs to the server...
public void run() {
try {
ServerSocket= new ServerSocket(44444);//inside there is the port mumber which will be gain later from firstscreen
ClientSocket= ServerSocket.accept();
OUT= new ObjectOutputStream(ClientSocket.getOutputStream());
IN=new ObjectInputStream(ClientSocket.getInputStream());
while (true){
Object input =IN.readObject();
textArea.setText(textArea.getText()+"Client:"+(String)input+"\n");//update the textarea
}//loop end
}catch (IOException e){
//joptionpane
e.printStackTrace();
} catch (ClassNotFoundException e) {
//joptionpane
e.printStackTrace();
}
}//end of try
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("Send")|| e.getSource() instanceof JTextField){
try {
if(textField.getText().isEmpty()) {
OUT.writeObject(textField.getText());
textArea.setText(textArea.getText()+"Assistant:"+textField.getText()+"\n");}
}
catch (IOException c){
c.printStackTrace();
}
}
I hope you understand that you are only letting just a SINGLE client connect to the server, since there cannot happen any other serverSocket.accept()
First, you are only sending the information if the textfield text is empty at if(textField.getText().isEmpty()) which is quite a nonsense, otherwise there is no call to send through socket any data.
Apart from this, I do not see the code for the actionPerformed block, which I assume you have coded it before with a JButton or so and implementing the jbutton.addActionListener()
Also, I hope ClientSocket is a class of your own, because a client is represented as a Socket, not ClientSocket.
On the other hand, I would suggest the following API writeUTF and forget about needing to cast the string into bytes or otherways, with the help of DataInput and DataOutputStreams.
The code would be left as:
public void run() {
try {
ServerSocket serverSocket= new ServerSocket(44444);//inside there is the port mumber which will be gain later from firstscreen
Socket clientSocket= serverSocket.accept();
DataOutputStream OUT = new DataOutputStream(clientSocket.getOutputStream());
DataInputStream IN = new DataInputStream(clientSocket.getInputStream());
while (true){
String input = IN.readUTF();
textArea.append(input+"\n"); //update the textarea
}//loop end
}catch (IOException e){
//joptionpane
e.printStackTrace();
} catch (ClassNotFoundException e) {
//joptionpane
e.printStackTrace();
}
}//end of try
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("Send")|| e.getSource() instanceof JTextField) {
try {
if(!textField.getText().isEmpty()) { //Do not forget to include the ! (NOT)
OUT.writeUTF(textField.getText());
textArea.setText(textArea.getText()+"Assistant:"+textField.getText()+"\n");
}
}
catch (IOException c){
c.printStackTrace();
}
}
}
I hope to have been able to have helped you.
I'm taking over an existing JAVA project which containing the following code:
class ConnectionHandler extends Thread {
private Socket socket;
public ConnectionHandler(Socket s) {
this.socket = s;
}
private void doSthForRequest(ObjectInputStream in, ObjectOutputStream out) throws Exception {
// Do something and write output to out:
// out.writeObject(someOutput);
}
public void run() {
ObjectOutputStream out = null;
ObjectInputStream in = null;
try {
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
while (true) {
out.reset();
doSthForRequest(in, out);
}
} catch (Exception ex) {
if (out != null && !socket.isOutputShutdown()) {
try {
out.writeObject(ex);
out.flush();
} catch (Exception ex2) {}
}
} finally {
if (out != null) {
try {
out.reset(); // any reason for this?
} catch (Exception ee) {}
}
if (out != null) {
try {
out.close();
} catch (Exception ee) {}
}
try {
socket.close();
} catch (Exception e) {}
}
socket = null;
}
}
There are ConnectionHandler threads which serving request and producing output on a socket. And my question is:
Does the reset() call still make any sense if there is a close() call immediately after it?
The original author just leaves one line comment // clear outputstream cache which makes me confused...
Appreciate your help!
No. reset() sends a tag over the wire that tells the peer to clear its handle table. As you're about to close the stream anyway, the reset operation has no meaning, and it's an extra network operation to go wrong. Just close it.
As for other problems:
Construct the ObjectOutputStream before the ObjectInputStream. Otherwise a deadlock can occur.
Use the try-with-resources syntax here. It will simplify the code a lot.