In the context of Java, I create a new thread to read network input when open a GUI window, and when i close the window, i want to release the socket resource and terminate the thread immediately. Now i am using setSoTimeout method, but i don't want to wait the timeout exception. Could anybody give some suggestion? Thanks!
There are (potentially) three ways to do this:
Calling Socket.close() on the socket will close the associated InputStream and OutputStream objects, and cause any threads blocked in Socket or (associated) stream operations to be unblocked. According to the javadoc, operations on the socket itself will throw a SocketException.
Calling Thread.interrupt() will (under some circumstances that are not specified) interrupt a blocking I/O operation, causing it to throw an InterruptedIOException.
Note the caveat. Apparently the "interrupt()" approach doesn't work on "most" modern Java platforms. (If someone else had the time and inclination, they could possible investigate the circumstances in which this approach works. However, the mere fact that the behavior is platform specific should be sufficient to say that you should only use it if you only need your application to work on a specific platform. At which point you can easily "try it" for yourself.)
A possible third way to do this is to call Socket.shutdownInput() and/or Socket.shutdownOutput(). The javadocs don't say explicitly what happens with read and/or write operations that are currently blocked, but it is not unreasonable to think that they will unblock and throw an exception. However, when the javadoc doesn't say what happens, the behavior should be assumed to be platform specific.
I know this question is old but as nobody seems to have solved the "mystery" of Thread.interrupt() on "modern platforms" I did some research.
This is tested on Java 8 on Windows7 (64-bit) (but it will possibly be true for other platforms as well).
Calling Thread.interrupt() does not throw an InterruptedIOException
What happens is that the InputStream.read() method returns with -1 and Thread.interrupted()-flag is set.
So the following could be considered a 'corrected' read() throwing InterruptedIOException:
static final int read(Socket socket, byte[] inData)
throws SocketTimeoutException, // if setSoTimeout() was set and read timed out
InterruptedIOException, // if thread interrupted
IOException // other erors
{
InputStream in = socket.getInputStream();
int readBytes = in.read( inData, 0, inData.length);
if ( Thread.interrupted() )
{
throw new InterruptedIOException( "Thread interrupted during socket read");
}
return readBytes;
}
Related
I have a very peculiar problem. In android I am using FileInputStream to read from the serial (ttySx/COM) port. I am using this to decide which of the known devices is connected (if any at all). What I basically do is:
Are you device 1? No...
Are you device 2? No...
Are you device 3? Yes...
Great lets do some stuff...
And this works great. If there is any incoming data to read (response from device), everything is fine. However, if there is no device connected to ttySx there is nothing to respond to my write. That means nothing to read.
Now, FileInputStream.read() is a blocking call. When I call it in the thread, thread is effectively frozen. I cannot interrupt the thread because for that I would have to read something first. So far everything makes perfect sense.
As there is no response from the port for quite some time I decide that there is nothing connected and want to stop reading and dispose of the thread(actually I do not want to bother with the port anymore because with nothing connected, it is useless to me at this moment). As mentioned earlier interrupt itself is no good. What should be working, is to close() the FileInputStream (read() will throw an exception and hooray!). The close() works... As long as the read() read anything ever (like when I had an answering device connected, then disconnect it -> read() is stuck - because no data to read - but close() works).
However if there was not a thing connected to the port when the read() started (equals: I haven't read a single byte), the close() method does nothing. It does not close the stream. Nor does work the closing of FileInputStream channel.
I could create a workarround: Store the FileInputStream somewhere and when I want to read from the port again later, use the same instance. That would work for me. Unfortunately I would quite unnecessarily block the port itself. No other process (for example another application) could read from the port because it is stuck in "uninterruptable" read...
Any ideas why this is happening and how to make it right? Or some other way to detect if there is anything connected to the ttySx port?
Thanks.
EDIT1: The library used for communication with serial port is https://github.com/cepr/android-serialport-api
In the end we used FileInputStream::available().
First time we tried it, it was like:
Check if anything is available.
Read (regardless of availability)
Of course, when we checked the available, there was nothing to read yet. Then the read call blocked and waited for input. When we checked again, there was nothing available already, because read had cleared the port.
Therefore this suggestion Java close FileInputStream before reading anything from M. Prokhorov was the correct one for my situation.
If anyone would wonder about the behavior in question:
From researching it, it seems that reading streams was not designed for ports/sockets in first place. It was designed for regular files. You read, reach the end of document and close the stream. The exceptions are designed for wrong sequential usage of a stream (you open it, close id and then try to read).
If you enter blocking mode, it will block until it reads at least a byte. No way around it. Close initializes the "closing state" similarly to setting the interrupt state of a thread.
What can go wrong if I simply replace
socket = new Socket()
with
socket = SocketChannel.open().socket()?
Background: I have some legacy code using new Socket(), and I wanted to be able to interrupt the socket.connect() call. I don't want to rewrite the code to use NIO. I learned that Thread.interrupt() does not interrupt socket.connect(), but that socket.close() on another thread is supposed to interrupt the connection. Oddly, that worked with Java 7 but not Java 6.
I somehow got it into my head that using socket = SocketChannel().open().socket() would magically allow me to use Thread.interrupt() to interrupt socket.connect(). It doesn't, but oddly, it does make socket.close() interrupt socket.connect() in Java 6 too!
Note that I'm not directly using the attached SocketChannel in any way---it appears when I create the Socket and never again.
What can go wrong with this?
There are several.
A Socket acquired via a SocketChannel doesn't appear to support read timeouts.
The InputStream and OutputStream of a socket aren't independent: they have a mutual lock in common.
Why do you want to interrupt the connect() call? Surely all you want is a connect timeout?
Differences in the type of thrown exceptions could break existing code.
For instance, closing a Socket from a different thread while Socket.getInputStream().read() is blocking will result in AsynchronousCloseException after replacing, instead of SocketException that legacy code could be expecting. (AsynchronousCloseException is not a subclass of SocketException.)
However, Socket.getInputStream().read() will still throw SocketException if the close from the other thread gets in before read().
I'm programming a simple Java NIO server and have a little headache: I get normal InputStreams i need to pipe to my clients. I have a single thread performing all writes, so this creates a problem: if the InputStream blocks, all other connection writing will be paused.
I can use InputStream.available() to check if there are any incoming data I can read without blocking, but if I've reached end-of-stream it seems I must call read() to know.
This creates a major headache for me, but I can't possibly believe I'm the first to have this problem.
The only options I've come up with so far:
Have a separate thread for each InputStream, however that's just silly since I'm using non-blocking I/O in the first place. I could also have a thread pool doing this but then again that limits the amount of simultaneous clients I can pipe the InputStream to.
Have a separate thread reading these streams with a timeout (using another thread to interrupt if reading has lasted longer than a certain amount of time), but that'll most certainly choke the data flow should I have many open InputStreams not delivering data.
Of course, if there was a magic InputStream.isEof() or isClosed() then this wouldn't be any problem at all :'(
".....Have a separate thread for each InputStream, however that's just silly since I'm using non-blocking I/O in the first place...."
It's not silly at all. First you need to check whether you can retrieve a SelectableChannel from your InputStream implementation. If it does you are lucky and you can just register it with a selector and do as usual. But chances are that your InputStream may have a channel that's not a SelectableChannel, in which case "Have a separate thread for each InputStream" is the obvious thing to do and probably the right thing to do.
Note that there is a similar problem discussed in SO about not able to get a SelectableChannel from an inputstream. Unfortunately you are stuck.
I have a single thread performing all
writes
Have you stopped to consider whether that is part of the problem rather than part of the solution?
I use a Java Socket object in my client application. I need to know when the line to the server is broken, or if any event caused the socket to be dead.
I see two methods:
catching SocketException when writing in or reading from the socket, considering these exceptions kill the socket
when catching these exceptions, checking the Socket.isClosed() method to know if it killed the socket
Does any of these methods guarantee I'll know when the socket is dead and won't work again, even if a temporary problem on the line is solved?
Can we except a (Socket)Exception thrown during an operation on a socket to imply the socket is dead?
Is there a better method to know this?
At least:
Receiving an exception does NOT mean the socket is always dead, from Socket.setSoTimeout() javadoc:
If the timeout expires [on a read for instance, a java.net.SocketTimeoutException is raised, though the Socket is still valid.
The closed flag of the socket seems to be set only when the Socket.close() method is called, so I would not rely on it.
This is usually done by a timeout. This is mandatory if you don't trust the other side (like every time). Without a timeout, an attacker can DoS your application easily by opening connections without sending anything. Once you hit the socket limit of your system, the application might even crash...
A "Dead Socket" can be considered as an abnormal status. It is just a errornous bahaviour. So I don't think you can handle this situation effectively.
Since there is nothing like a keep-alive between sockets, you will learn that the connection is broken not until ,next time you try to write onto this socket.
I am working on a mobile communicator and after establishing connection to the server using following method (to illustrate that I am using StreamConnection, InputStream and OutputStream) I distribute inputStream and outputStream between two separate threads, lets call them Sender and Receiver.
Connection method:
private InputStream inputStream;
private OutputStream outputStream;
private StreamConnection connection;
public void connect(String host, String port) throws IOException {
String connectionString = "socket://" + host + ":" + port;
connection = (StreamConnection) Connector.open(connectionString);
inputStream = connection.openDataInputStream();
outputStream = connection.openOutputStream();
}
Sender thread is waiting for anything to appear in the out buffer. When output buffer is empty, Sender waits (by calling wait() method on sender thread). Any input into the output buffer calls notify() method on the sending thread.
Receiver thread polls the InputStream using int available() method and when there is something to receive, it calls blocking int read() method. Everything works like a charm in various emulators and few devicdes I have handy around.
However there is one phone that seems to missbehave. Whenever one thread calls available() or read() on InputThread object, while the other thread calls write() on the OutputStream object, the Input stream finishes. All subsequent reads will return value -1, which means that the InputStream got closed.
After massive google-fu, I came accross this post on nokia forums, where simplex/duplex properties of a device are being discussed and that seems to be the case with the device I have troubles with. Normally (99% of the time) calls to read() and write() can be simultaneous without any problems.
My question is then: Did anybody came accross similar problems? How did/would you sort out the issue of one thread independently reading, while another is independently writing into the established connection, so that they do not call read() or available() while calling write()?
Any pointers in any directions greatly appreciated!
Normally, very little is guaranteed when we talk about multi-threaded applications. I would recommend to use a single thread in your application and try to manage it using a single worker. Some devices do have behavioral problems and so what we see on one device does not appear to work on some other device.
I have worked a lot with mobile games where a lot of animation has to be rendered without compromising the speed of the game. I have realized that you can do more with a single thread and it makes your application very portable (with almost no changes).
If you are waiting for the threads to complete either READ or WRITE operation, so it looks like you are actually doing this sequentially. So more or less, things would be complicated with more than one thread. Instead, built a wait-notify mechanism, based on some predetermined factor and allow the SINGLE thread to either read or write to the socket stream. Switching between threads is a very costly operation, than this scheme.
Hope this answers your question.
Between that kind of problem and mobile network operators filterning data, most mobile java developers use the "http://" protocol instead of "socket://".
Of course, that means not using duplex connection anymore and making many GET and POST requests instead.
Far from ideal, I know.