5

Does anybody have more helpful information on the Exception "Try again"?

I'm sending Bitmaps between apps using LocalServerSocket and LocalSocket:

Output:

socket = new LocalSocket();
socket.connect(new LocalSocketAddress(SOCKET_NAME));
fos = new DataOutputStream(socket.getOutputStream());
...

public void onEvent() {
    fos.writeInt(width);
    fos.writeInt(height);
    fos.writeInt(newBuffer.length);
    fos.write(newBuffer);
}

Input:

server = new LocalServerSocket(SOCKET_NAME);
socket = server.accept(); 
socket.setSoTimeout(60);

while(true) {

    int width = fis.readInt(); // IO Exception being thrown here
    int height = fis.readInt(); 
    int length = fis.readInt();
    byte[] bytes = new byte[length];
    fis.read(bytes);
}

[try/catch etc removed for clarity]

04-18 09:19:11.664: W/System.err(1268): java.io.IOException: Try again
04-18 09:19:11.664: W/System.err(1268):     at android.net.LocalSocketImpl.readba_native(Native Method)
04-18 09:19:11.664: W/System.err(1268):     at android.net.LocalSocketImpl.access$400(LocalSocketImpl.java:29)
04-18 09:19:11.664: W/System.err(1268):     at android.net.LocalSocketImpl$SocketInputStream.read(LocalSocketImpl.java:92)
04-18 09:19:11.664: W/System.err(1268):     at libcore.io.Streams.readFully(Streams.java:81)
04-18 09:19:11.664: W/System.err(1268):     at java.io.DataInputStream.readInt(DataInputStream.java:124)
04-18 09:19:11.664: W/System.err(1268):     at com.test.util.BitmapSendingUtils$BitmapReceiver$1.run(BitmapSendingUtils.java:105)
Graeme
  • 25,714
  • 24
  • 124
  • 186

5 Answers5

4

The exception you see is probably the java equivalent to the EAGAIN error. See for example this answer.

You should handle the exception and try the failed IO operation again.

Community
  • 1
  • 1
Malte Tancred
  • 268
  • 1
  • 5
  • Its throwing on a specific blocking operation. Doesn't look like the above answer applies. Well, it shouldn't anyway. – Graeme Apr 28 '13 at 09:51
  • Ah, I see. Is it a bug in LocalSocketImpl? What happens if you treat the error as an EAGAIN and do try again? – Malte Tancred Jun 05 '13 at 05:31
3

I've since rengineered this as I couldn't find the solution. But while implementing it a different way I came across these errors in the original code:

byte[] bytes = new byte[length];
fis.read(bytes);

Should be:

byte[] content = new byte[length];
int read = is.read(content);
while(read < content.length) {
    read += is.read(content, read, content.length - read);
}

as .read(byte[]) doesn't slurp the whole thing at once. I assumed that this continually slurped and blocked while it did so.

There is also this:

socket.setSoTimeout(60);

The arg is in millis rather than seconds so should be:

socket.setSoTimeout(60 * 1000);

I still don't know the cause of the above badly named exception though so hopefully someone will still answer this if they know!

Graeme
  • 25,714
  • 24
  • 124
  • 186
0

try as flow, use mInputValid to control whether end the flow:

private int fill(byte[] buffer, int offset,int length) throws IOException {
    int sum = 0, len;
    while ((sum<length) && mInputValid) {
        try{
            len = is.read(buffer, offset + sum, length - sum);
            if (len < 0) {
                throw new IOException("End of stream");
            } else{
                sum += len;
                Log.i(TAG, "is.read: " + len + " buffer:" + buffer[0]);
            }
        }
        catch (IOException e){
            e.printStackTrace();
            Log.i(TAG, "read input fail, try again");
            continue;
        }
    }
    return sum;
}
0

I think the "Try again" IOException should actually be handled in the same way a SocketTimeoutException would be handled. This is a very poorly implemented API, but we are used to such crappy design on Android:

private int read(byte[] buffer) throws IOException {

    while (true) {
        try {
            return fis.read(buffer);
        } catch (SocketTimeoutException e) {
            continue;
        } catch (IOException e) {
            String message = e.getMessage();
            if (message != null && message.equals("Try again")) {
                continue;
            }
            throw e;
        }
    }
}

private int readInt() throws IOException {
    while (true) {
        try {
            return fis.readInt();
        } catch (SocketTimeoutException e) {
            continue;
        } catch (IOException e) {
            String message = e.getMessage();
            if (message != null && message.equals("Try again")) {
                continue;
            }
            throw e;
        }
    }
}
Nappy
  • 3,016
  • 27
  • 39
0

I know I am late to the party, but I just solved the same issue and there are a number of things that can cause this:

  1. Not calling outputStream.flush() on sending. If you use writers, it's writer.flush(). This sends the last buffer. If you are not using buffers, it doesn't mean they aren't there. Stream send data in bytes, so unless you are sending a single byte, chances are there's some buffer down the line that doesn't get sent, and the receiver gets half an int.
  2. If you are keeping the streams open, there is no way to detect the stream's end: so the Java will thrown an exception if you try to do things like reader.read(buffer), when size of the buffer exceeds the amount of data sent. In this case you must implement some kind of prototocle (header telling the length or some sort of end token, to know when to stop reading).
  3. If you are closing streams after sending message and calling output.flush(), this exception can be caused by what you meantioned: socket timeouts, as well as disconnects.
Megakoresh
  • 746
  • 1
  • 11
  • 30