I've heard that calling 'socket.close()' automatically closes it's streams.
Would:
public void close() {
try {
socket.close();
}catch(IOException e) { }
}
Have the same effect as:
public void close() {
try {
outputstream.close();
inputstream.close();
socket.close();
}catch(IOException e) { }
}
If your goal was to completely close the socket?
Closing a socket will also close the socket's InputStream and OutputStream:
http://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#close()
Yes, closing the input or output stream or the socket closes both streams and the socket.
However you shouldn't close the socket, you should close the outermost OutputStream or Writer you have wrapped around its output stream, so it gets flushed. Only you can do that. The socket can only close its output stream, not what you've wrapped around it.
You should do this is you have a buffered output stream. This will flush any data which has not been sent yet.
Otherwise, closing the socket will close the streams so it is redundant.
Related
I have a server and a client set up in this way. I can't find the cause of the EOFException, because it happens randomly. It throws the following exception every time a client connects, but I can't figure out the source of it. It always occurs before it reads what the client has sent. The exception always is at this line:
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
Here is the exception:
java.io.EOFException
at java.base/java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2860)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:3355)
at java.base/java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:939)
at java.base/java.io.ObjectInputStream.<init>(ObjectInputStream.java:381)
at com.denesgarda.Socketeer.data.End$3.run(End.java:62)
at com.denesgarda.Socketeer.data.End$3.run(End.java:76)
at com.denesgarda.Socketeer.data.End$3.run(End.java:76)
at com.denesgarda.Socketeer.data.End.listen(End.java:83)
at Server.<init>(Server.java:10)
at SStart.main(SStart.java:5)
Here is my server code:
if(listener == null) this.voidListener();
ServerSocket serverSocket = new ServerSocket(port);
End THIS = this;
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
try {
Socket socket = serverSocket.accept();
socket.setSoTimeout(10000);
Connection connection = new Connection(THIS, new End((((InetSocketAddress) socket.getRemoteSocketAddress()).getAddress()).toString().replace("/","")), port, listener);
try {
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
Object o = objectInputStream.readObject();
if (o.equals("01101100 01101001 01110011 01110100 01100101 01101110 00100000 01110011 01110100 01100001 01110010 01110100")) {
listener.event(new ConnectionEvent(connection));
listener.event(new ConnectionSuccessfulEvent(connection));
}
else {
listener.event(new ReceivedEvent(connection, o));
}
socket.close();
}
catch(EOFException e) {
e.printStackTrace();
}
this.run();
}
catch(Exception e) {
e.printStackTrace();
}
}
};
timerTask.run();
Here is my client code:
if(listener == null) this.voidListener();
Socket socket = new Socket(address, port);
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
send("Message");
public void send(Object object) throws IOException {
Socket socket = new Socket(THAT.getAddress(), this.port);
OutputStream outputStream = socket.getOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(object);
socket.close();
}
What I've Tried
I've tried to fix this issue many times before. I tried to create object output streams. I've switched the order that I initialize the object input stream and object output stream. This is so that the server doesn't get frozen in a deadlock with the client. I have no idea what could be causing this error.
I think I know what is going on here, but I can't be certain because your code is fragmentary, and the symptoms are not well characterized. (The exceptions are unlikely to really be random, for example.)
First there is one indisputable fact. A one side of a connection sees an EOFException because the other side has closed the network connection. That's what that exception means.
In your case, the server gets the exception in the ObjectInputStream constructor because the constructor attempts to read an object stream header that the client side never sends ... on that connection.
Now, the theory. I think I know why. Here is the relevant part of your code (with some bits snipped out for brevity).
Socket socket = new Socket(address, port);
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
[...]
socket.close();
[...]
}
});
send("Message");
public void send(Object object) throws IOException {
Socket socket = new Socket(THAT.getAddress(), this.port);
[...]
}
Notice that there are two sockets! The first one is created and passed to the shutdown hook. The second one is created and used within send and then closed.
I think the problem is the first Socket. When that is created, it establishes a connection to the server. The server code will accept it and then attempt to read. The read will block ... since the client side hasn't written anything to that socket. The client will then call send which opens and uses a different Socket.
Eventually, the client application exits.
When it exits, the shutdown hook closes the first socket. That causes the server side to see the end of stream ... and triggers the EOFException.
So how to fix this?
It rather depends on the "big picture". Is the real client sending a single message to the server, or does it need to reuse the socket to send multiple messages?
Assuming the former, the solution is simple:
Get rid of the code that creates a socket and passes it to a shutdown hook. As you have written it, it serves no useful purpose.
Rewrite the send method to use try with resources; e.g.
public void send(Object object) throws IOException {
try (Socket socket = new Socket(THAT.getAddress(), this.port);
OutputStream os = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os)) {
oos.writeObject(object);
}
}
Note that the above will automatically close the 3 resources in the correct order.
JavaDoc for InputStreamReader doesn't say anything about closing the underlying InputStream:
https://docs.oracle.com/javase/8/docs/api/java/io/InputStreamReader.html#close--
Description copied from class: Reader
Closes the stream and releases any system resources associated with it. Once the stream has been closed, further read(), ready(), mark(), reset(), or skip() invocations will throw an IOException. Closing a previously closed stream has no effect.
Does closing an InputStreamReader also close the underlying InputStream?
UPDATE In:
InputStreamReader istream = new InputStreamReader(conn.getInputStream(), "UTF-8")
istream.close();
Do I need to close conn.getInputStream()?
InputStreamReader implementation direct close call to StreamDecoder which is a native class.
As other answers and comments said, the answer is yes, it does close the InputStream. You can see for yourself with the following code:
InputStream is = new FileInputStream("D:\\a.txt");
Reader r = new InputStreamReader(is);
r.close();
is.read(); // throws exception: stream is closed.
Therefore, if you close the Reader, you don't need to also close the InputStream. However, I guess you are using try-with-resources everywhere (aren't you? ;) ) and the InputStream as well as the Reader will both be closed at the end of the try block. That doesn't matter, because an InputStream can be closed multiple times; it's a no-op if the stream is already closed.
If you want to avoid closing the InputStream, you can write a simple wrapper that does nothing when it is closed:
class UncloseableInputStream extends FilterInputStream {
public UncloseableInputStream(InputStream is) {
super(is);
}
public void close() {
// Do nothing.
}
}
InputStream is = new FileInputStream("D:\\a.txt");
Reader r = new InputStreamReader(new UncloseableInputStream(is));
r.close();
is.read(); // still works despite closing the reader.
It depends on stream implementation. InputStream is just an "interface" in terms of close(). InputStreamReader will not close an interface. It will close the underlying data resource (like file descriptor) if it is. It will do nothing if close is override and empty in an implementation.
In OpenJdk StreamDecoder has a method
void implClose() throws IOException {
if(this.ch != null) {
this.ch.close();
} else {
this.in.close();
}
}
this.in is a InputStream from decoder constructor:
StreamDecoder(InputStream var1, Object var2, CharsetDecoder var3) {
...
if(this.ch == null) {
this.in = var1;
...
}
...
}
Here are examples of closing actions. ByteArrayInputStream:
Closing a ByteArrayInputStream has no effect. The methods in this class can be called after the stream has been closed without generating an IOException.
public void close() throws IOException {
}
FileInputStream differes:
Closes this file input stream and releases any system resources associated with the stream. If this stream has an associated channel then the channel is closed as well. After you closed the underlying instance it doesn't matter which interfaces were using it, it will be closed.
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}
I want to detect a server-sided socket close (closed by socket.setSoTimeout) by sending data from the client Socket OutputStream (socket.getOutputStream().write(42)). If the Socket is closed on the server-side this should cause an Exception. But it only throws an Exception if I send data twice:
private boolean sendTest() {
try {
System.out.print("connection...");
socket.getOutputStream().write(42); //Sending "*"
socket.getOutputStream().write(42); //not working without this line
System.out.println("ok");
return true;
} catch (IOException e) {
System.out.println("error...disconnecting socket");
disconnect();
return false;
}
}
How can you explain this behaviour?
K here's the explanation:
You're sending the first byte to the server. Server gets it, and then closes the socket. Then, on THE NEXT WRITE, you get an IOException, since the socket connection is closed.
OutputStream fos;
OutputStream bos;
OutputStream zos;
try {
fos = new FileOutputStream(anyFile);
bos = new BufferedOutputStream(fos);
zos = new ZipOutputStream(bos);
} finally {
if (zos != null) {
zos.close(); // + exception handling
}
}
Does closing zos automatically closes bos and fos too, or do I need to close them manually?
Yes, it does. Its Javadoc says:
Closes the ZIP output stream as well as the stream being filtered.
Also, the Javadoc for BufferedOutputStream says:
Closes this output stream and releases any system resources associated with the stream.
The close method of FilterOutputStream calls its flush method, and then calls the close method of its underlying output stream.
So when you close your ZipOutputStream, it will close your BufferedOutputStream, which will in turn close your FileOutputStream.
Yes.
ZipOutputStream.close() method is specified by Closeable.close() which:
Closes this stream and releases any system resources associated with
it.
The same applies to BufferedOutputStream.close(), a method inherited from FilterOutputStream.
Closing the wrapper stream automatically closes the inner stream.
So, in your case you only need to close ZipOutputStream. Closing a stream twice does not throw an exception hence closing an inner stream again (although unnecessary) works as well.
Here's what happens when you instantiate a ZipOutputStream
public ZipOutputStream(OutputStream out) {
this.out = out; // BufferedOutputStream reference saved
}
Here's the implementation of ZipOutputStream.close()
public void close() throws IOException {
try {
flush();
} catch (IOException ignored) {
}
out.close(); // BufferedOutputStream being closed
}
Similarly, BufferedOutputStream automatically closes the FileOutputStream through its inherited FilterOutputStream#close() which has been implemented as:
public void close() throws IOException {
try {
flush();
} catch (IOException ignored) {
}
out.close(); // FileOutputStream being closed
}
Yes it does. but strangely when i was running the fortify scan with find bug enabled it catches all these kind of wrapped and unclosed streams as high priority items to be fixed. Not sure why they do so
I am trying to send objects across a socket for a game, but they take a long time to send and can cause the game to hang. I want to use BufferedOutputStreams and BufferedInputStreams to send the data, but my ObjectInputStream won't initialize on the server side when I use the BufferedOutputStream on the client side. The weird thing is that no errors are thrown.
I'm only providing the code involved because it would take a long time to explain what's going on otherwise. Two clients are initialized each game.
/*Server Code*/
ObjectOutputStream toClients;//stream to both players
ObjectInputStream fromClients;//stream from both players
Socket client1;//player one socket
Socket client2;//player two socket
public RunGame(Socket client1, Socket client2)throws IOException//constructor of a new thread
{
this.client1=client1;
this.client2=client2;
}
public void run()//for the thread
{
try{
this.createGame();
/*
rest of code for server when running game
*/
}
catch(IOException e){e.printStackTrace();}
catch(ClassNotFoundException e){e.printStackTrace();}
}
public void createGame()
{
try{
System.out.println("about to create");//this prints out
fromClients=new ObjectInputStream(client1.getInputStream());//first initialization
System.out.println("created");//this doesn't
String s1=(String)fromClients.readObject();
fromClients=new ObjectInputStream(client2.getInputStream());//sets input to player 2
String s2=(String)fromClients.readObject();
}
catch(IOException e){e.printStackTrace();}
catch(ClassNotFoundException e){e.printStackTrace();}
}
/*Client Code*/
Socket sock;//created in the constructor of the thread
ObjectOutputStream toServer;
ObjectInputStream fromServer;
public void run()
{
try{
System.out.println("about to create");//this prints
toServer=new ObjectOutputStream(new BufferedOutputStream(sock.getOutputStream(),8*1024));//bufferedoutputstream is here
toServer.writeObject("String that is to be sent to server");
System.out.println("written");//this also prints
}
catch(IOException e){e.printStackTrace();}
catch(ClassNotFoundException e){e.printStackTrace();}
/*
rest of client code
*/
}
I've been through all of the forums but can't find anything that works, which makes me assume that I'm doing something very novice. Thanks for any help you can give!
You'll need to .flush() your ObjectOutputStream otherwise the BufferedOutputStream won't send its output to the socket.