【问题标题】:"IOException: Try again" while using LocalServerSocket使用 LocalServerSocket 时出现“IOException:再试一次”
【发布时间】:2013-04-11 06:51:30
【问题描述】:

有没有人有关于例外“再试一次”的更多有用信息?

我正在使用LocalServerSocketLocalSocket 在应用程序之间发送位图:

输出:

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);
}

输入:

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 等]

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)

【问题讨论】:

    标签: android localserversocket localsocket


    【解决方案1】:

    我知道我迟到了,但我刚刚解决了同样的问题,有很多原因可能导致此问题:

    1. 发送时未调用outputStream.flush()。如果你使用作家,它是writer.flush()。这将发送最后一个缓冲区。如果您不使用缓冲区,这并不意味着它们不存在。流以字节为单位发送数据,因此除非您发送单个字节,否则可能会有一些缓冲区未发送,并且接收者会获得半个 int。
    2. 如果您保持流打开,则无法检测流的结束:因此,如果您尝试执行reader.read(buffer) 之类的操作,当buffer 的大小超过发送的数据。在这种情况下,您必须实现某种 prototocle(标头告诉长度或某种结束标记,以知道何时停止阅读)。
    3. 如果您在发送消息并调用output.flush() 后关闭流,则此异常可能是由您的意思引起的:套接字超时以及断开连接。

    【讨论】:

      【解决方案2】:

      我认为实际上应该以与处理 SocketTimeoutException 相同的方式处理“再试一次”IOException。这是一个实现得很糟糕的 API,但我们已经习惯了 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;
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        try as flow,使用mInputValid控制是否结束流:

        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;
        }
        

        【讨论】:

          【解决方案4】:

          您看到的异常可能是与 EAGAIN 错误等效的 java。参见例如this answer

          您应该处理异常并再次尝试失败的 IO 操作。

          【讨论】:

          • 它抛出一个特定的阻塞操作。看起来上面的答案不适用。好吧,无论如何都不应该。
          • 啊,我明白了。它是 LocalSocketImpl 中的错误吗?如果您将错误视为 EAGAIN 并重试,会发生什么情况?
          【解决方案5】:

          我已经重新设计了这个,因为我找不到解决方案。但是在以不同的方式实现它时,我在原始代码中遇到了这些错误:

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

          应该是:

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

          因为.read(byte[]) 不会一下子吞下整个东西。我认为它在这样做时会不断地啜饮和阻塞。

          还有这个:

          socket.setSoTimeout(60);
          

          参数的单位是毫秒而不是秒,所以应该是:

          socket.setSoTimeout(60 * 1000);
          

          我仍然不知道上述错误命名异常的原因,所以希望有人知道后仍然会回答这个问题!

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-05-16
            • 2023-03-29
            • 2020-07-09
            • 2020-01-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多