Android客户端 - 服务器通信在input.read上抛出异常

时间:2014-09-13 13:47:02

标签: java android sockets client-server

我正在使用套接字和输入,输出流开发Android-Server通信(没有像datainputstream,objectinput stream等包裹类)。

Communiction基于每一方的三个线程(服务器具有接受新套接字的附加线程)

第一个帖子是导演,它通过LinkedBlockingQueue接收来自接收者的消息,对他们做出反应并通过LinkedBlockingQueue将数据发送给发件人

第二个线程是接收器,它定期读取套接字(通过InputStream.read),如果有消息则将它传递给使用LinkedBlockingQueue的导向器

当连接丢失时,Client-Android设备(已阻止input.read)立即抛出连接超时异常

第三个线程是发件人,它定期从LinkedBlockingQueue获取消息并将该数据发送到连接的另一端

问题是:防止在ClientSide接收器上抛出异常(这看起来很像Android的东西,因为input.read本身不应该抛出任何与超时连接有关的异常

这是接收者代码:

public class Receiver implements Runnable {

private boolean run = true;

BlockingQueue<MessageQueue> queueReceiverOut;

InputStream in;

////////////////////////////// CONSTRUCTOR ////////////////////////////////

public Receiver(BlockingQueue<MessageQueue> queueReceiverOut, InputStream in) {

    this.queueReceiverOut = queueReceiverOut;
    this.in = in;

}
// ////////////////////////////// METHODS ////////////////////////////////

/**
 * Runs when thread starts.
 */

public void run() {

    int[] message = new int[2];

    byte[] data;

    MessageQueue msg;

    try {

        while(true) {

            msg = new MessageQueue();

            message = receiveMessage();

            System.out.println("receives message");

            if(message[0] != -1) {

                System.out.println("receives full message");

                if(message[1] != 0) {

                    data = receiveData(message[1]);

                    msg.setMessageType(message[0]);
                    msg.setDataLength(message[1]);
                    msg.setData(data);

                    queueReceiverOut.put(msg);

                } else {

                    msg.setMessageType(message[0]);
                    msg.setDataLength(message[1]);
                    queueReceiverOut.put(msg);

                }
            }

        }

    } catch (IOException e) {

        System.out.println("----disconnected-----");

        try {

            MessageQueue msgReceiverOut = new MessageQueue();

            msgReceiverOut.setMessageType(SocketMessages.STATUS_OFFLINE);
            queueReceiverOut.put(msgReceiverOut);

        } catch (InterruptedException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        e.printStackTrace();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}



public int[] receiveMessage() throws IOException {

    int[] messageHead = new int[2];

    messageHead[0] = in.read();

    if(messageHead[0] != -1) {

        System.out.println("received message with type : " + messageHead[0]);

        int length1 = in.read();
        int length2 = in.read();
        int length3 = in.read();
        int length4 = in.read();

        messageHead[1] = ((length1 << 24) + (length2 << 16) + (length3 << 8) + (length4 << 0));

        System.out.println(" with length : " + messageHead[1]);

    }

    return messageHead;

}

public byte[] receiveData(int length) throws IOException {

    byte[] buffer = new byte[length];

     // Read in the bytes
    int offset = 0;
    int numRead = 0;
    while (offset < length
    && (numRead = in.read(buffer,
    offset, length - offset)) >= 0) {
    offset += numRead;
    }

    // Ensure all the bytes have been read in
    if (offset < length) {
    throw new IOException("Could not completely read file ");
    }

    return buffer;

}

public boolean isRun() {
    return run;
}

public void setRun(boolean run) {
    this.run = run;
}

}

和发件人:

   public class Sender implements Runnable {

private boolean run = true;

BlockingQueue<MessageQueue> queueSenderIn;

BlockingQueue<MessageQueue> queueSenderOut;

OutputStream out;

////////////////////////////// CONSTRUCTOR ////////////////////////////////

public Sender(BlockingQueue<MessageQueue> queueSenderIn, BlockingQueue<MessageQueue> queueSenderOut, OutputStream out) {

    this.queueSenderOut = queueSenderOut;
    this.queueSenderIn = queueSenderIn;
    this.out = out;

}
// ////////////////////////////// METHODS ////////////////////////////////

/**
 * Runs when thread starts.
 */

@Override
public void run() {

    MessageQueue msg;

    try {

        while(run) {

            msg = queueSenderIn.poll(2, TimeUnit.SECONDS);

            if(msg != null) {

                sendMessage(msg.getMessageType(),msg.getDataLength());

                if(msg.getDataLength()!=0) {

                    sendData(msg.getData());

                }

            }

        }

        Log.v(getClass().getName(),"sender destroyed");

    } catch (IOException e) {
        Log.v(getClass().getName(),"connection closed");
        e.printStackTrace();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}



public void sendMessage(int messageType, int dataLength) throws IOException, InterruptedException {

    MessageQueue msg = new MessageQueue();

    Log.v(getClass().getName(), "sending message type : " + messageType);
    out.write(messageType);

    Log.v(getClass().getName(), "sending data with length : " +dataLength);

    out.write((dataLength >>> 24) & 0xFF);
    out.write((dataLength >>> 16) & 0xFF);
    out.write((dataLength >>>  8) & 0xFF);
    out.write((dataLength >>>  0) & 0xFF);

    msg.setMessageType(messageType);

    queueSenderOut.put(msg);

}

public void sendData(byte[] data) throws IOException {

    String string = new String(data,"UTF-8");

    Log.v(getClass().getName(), " with content : " + string);

    out.write(data);

}

public boolean isRun() {
    return run;
}

public void setRun(boolean run) {
    this.run = run;
}

}

更新:因为误解了异常

1 个答案:

答案 0 :(得分:0)

  

在异常情况下,底层连接可能被破坏   远程主机或网络软件(例如连接   在TCP连接的情况下重置)。当连接断开时   通过网络软件检测到以下内容适用于返回的   输入流:

     
      
  • 网络软件可能会丢弃由缓冲的字节   插座。未被网络软件丢弃的字节可以是   阅读使用阅读。

  •   
  • 如果套接字上没有缓冲字节,或者所有缓冲的字节   已被阅读消耗,然后所有后续调用将被阅读   抛出IOException。

  •   
  • 如果套接字上没有缓冲字节,而套接字没有   使用关闭关闭,然后可用将返回0.

  •   

来自:http://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#getInputStream()

特别注意“后续通话”部分。这意味着如果您已经在read调用中阻止,则上述有关读取调用的条件(尚未)适用。

到目前为止的解释。现在解决方案: 即使通信空闲,您也可以(许多可能中的一种)定期发送消息。因此,发件人会检测到连接丢失,也可以关闭插播广告。


编辑:为了让它更清晰......

  1. 连接丢失
  2. 致电阅读
  3. IOException的
  4. ,而

    1. call read(blocks!)
    2. 等待输入:连接丢失
    3. - 没有异常!
    4. 我想重点是(我假设)服务器输入读取并在那里停留很长时间,而客户端在连接中断时接收数据。因此,它将不断调用并从read返回。在等待读取解除阻塞时仍然可能发生连接丢失,但可能性要小得多。

相关问题