I am writing to and reading from a Linux file in java, which in reality is a communication port to a hardware device. To do this I use RandomAccessFile (I'll explain why later) and it works well in most cases. But sometimes a byte is lost and then my routine blocks indefinitely since there is no timeout on the read method.
To give some more details on the file: it is a USB receipt printer that creates a file called /dev/usb/lp0 and though I can use a cups driver to print, I still need the low level communication through this file to query the status of the printer.
The reason I use RandomAccessFile is that I can have the same object for both reading and writing.
I tried to make a version with InputStream and OutputStream instead (since that would allow me to use the available() method to implement my timeout). But when I first open the InputStream and then the OutputStream I get an exception when opening the OutputStream since the file is occupied.
I tried writing with the OutputStream and then closing it before opening the InputStream to read, but then I lose some or all of the reply before it has opened the InputStream.
I tried switching to channels instead (Files.newByteChannel()). This also allows me to have just one object, and the documentation says it only reads the bytes available and returns the count (which also allows me to implement a timeout). But it blocks in the read method anyway when there is nothing to read, despite what the documentation says.
I also tried a number of ways to implement timeouts on the RandomAccessFile using threads.
The first approach was to start a separate thread at the same time as starting to read, and if the timeout elapsed in the thread I closed the file from the thread, hoping that this would unlock the read() operation with an exception, but it didn't (it stayed blocked).
I also tried to do the read in a separate thread and brutally kill it with the deprecated Thread.stop() once the time had elapsed. This worked one time, but it was not possible to reopen the file again after that.
The only solution I have made work is to have a separate thread that continuously calls read, and whenever it gets a byte it puts it in a LinkedBlockingQueue, which I can read from with a timeout. This approach works, but the drawback is that I can never close the file (again for the same reasons explained above, I can't unblock a blocked read). And my application requires that I sometimes close this connection to the hardware.
Anyone who can think of a way to read from a file with timeout that would work in my case (that allows me to have both a read and a write access open to the file at the same time)?
I am using Java8 by the way.
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.
Looking at the constructor of RandomAccessFile for the mode it says 'rws' The file is opened for reading and writing. Every change of the file's content or metadata must be written synchronously to the target device.
Does this imply that the mode 'rw' is asynchronous? Do I need to include the 's' if I need to know when the file write is complete?
Are RandomAccessFile writes asynchronous?
The synchronous / asynchronous distinction refers to the guarantee that the data / metadata has been safely to disk before the write call returns. Without the guarantee of synchronous mode, it is possible that the data that you wrote may still only be in memory at the point that the write system call completes. (The data will be written to disk eventually ... typically within a few seconds ... unless the operating system crashes or the machine dies due to a power failure or some such.)
Synchronous mode output is (obviously) slower that asynchronous mode output.
Does this imply that the mode 'rw' is asynchronous?
Yes, it is, in the sense above.
Do I need to include the 's' if I need to know when the file write is complete?
Yes, if by "complete" you mean "written to disc".
That is true for RandomAccessFile and java.io classes when using multiple threads. The mode "rw" offers asynchronous read/write but you can use a synchronous mode for read and write operations.
Is it possible to have one thread write to the OutputStream of a Java Socket, while another reads from the socket's InputStream, without the threads having to synchronize on the socket?
Sure. The exact situation you're describing shouldn't be a problem (reading and writing simultaneously).
Generally, the reading thread will block if there's nothing to read, and might timeout on the read operation if you've got a timeout specified.
Since the input stream and the output stream are separate objects within the Socket, the only thing you might concern yourself with is, what happens if you had 2 threads trying to read or write (two threads, same input/output stream) at the same time? The read/write methods of the InputStream/OutputStream classes are not synchronized. It is possible, however, that if you're using a sub-class of InputStream/OutputStream, that the reading/writing methods you're calling are synchronized. You can check the javadoc for whatever class/methods you're calling, and find that out pretty quick.
Yes, that's safe.
If you wanted more than one thread reading from the InputStream you would have to be more careful (assuming you are reading more than one byte at a time).
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 am using the javax.comm package to perform read and write operations on the SerialPort.
I have created an object of type InputStream as InputStream in;
My question is ....
Irrespective of data availibility on the SerialPort, in.available() always returns a zero due to which I am not able to decide whether bytes are available or not.
If i use the in.read() directly, it seems to block the execution forever..
Please help...
Awaiting your reply..
You can also mail me on my email address..
In anticipation of your reply....
Utsav
This is typical behavior of block I/O. The read() is going to block till some bytes are available, EOF or error. You should create a new thread and just wait for more data.
Don't use available() call because it may create a fast loop and drive up your CPU usage. If you really want do this in a single thread, looking into NIO.