Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Android客户端服务器通信在input.read上引发异常_Java_Android_Sockets_Client Server - Fatal编程技术网

Java Android客户端服务器通信在input.read上引发异常

Java Android客户端服务器通信在input.read上引发异常,java,android,sockets,client-server,Java,Android,Sockets,Client Server,我正在使用套接字和输入、输出流(没有像datainputstream、ObjectInputStream等包装类)开发Android服务器通信 通信基于每侧的三个线程(服务器具有接受新套接字的附加线程) 第一个线程是控制器,它通过LinkedBlockingQueue接受来自接收方的消息,对它们作出反应,并通过LinkedBlockingQueue将数据发送给发送方 第二个线程是周期性地读取套接字(通过InputStream.read)的接收器,若有消息,则通过LinkedBlockingQue

我正在使用套接字和输入、输出流(没有像datainputstream、ObjectInputStream等包装类)开发Android服务器通信

通信基于每侧的三个线程(服务器具有接受新套接字的附加线程)

第一个线程是控制器,它通过LinkedBlockingQueue接受来自接收方的消息,对它们作出反应,并通过LinkedBlockingQueue将数据发送给发送方

第二个线程是周期性地读取套接字(通过InputStream.read)的接收器,若有消息,则通过LinkedBlockingQueue将其传递给控制器

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

第三个线程是发送方,它定期从LinkedBlockingQueue接收消息并将数据发送到连接的另一端

问题是:防止客户端接收器上的异常抛出(这看起来像是Android的东西,因为input.read-alone不应该抛出任何与超时连接相关的异常)

以下是接收器的代码:

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;
}
公共类接收器实现可运行{
私有布尔运行=true;
封锁接收队列;
输入流输入;
//////////////////////////////建造师////////////////////////////////
公用接收器(阻止队列接收输出,输入流输入){
this.queueReceiverOut=queueReceiverOut;
this.in=in;
}
////方法////////////////////////////////
/**
*线程启动时运行。
*/
公开募捐{
int[]消息=新int[2];
字节[]数据;
消息队列消息;
试一试{
while(true){
msg=新消息队列();
message=receiveMessage();
System.out.println(“接收消息”);
如果(消息[0]!=-1){
System.out.println(“接收完整消息”);
如果(消息[1]!=0){
数据=接收数据(消息[1]);
msg.setMessageType(消息[0]);
msg.setDataLength(消息[1]);
msg.setData(数据);
队列接收输出(msg);
}否则{
msg.setMessageType(消息[0]);
msg.setDataLength(消息[1]);
队列接收输出(msg);
}
}
}
}捕获(IOE异常){
System.out.println(“----断开连接---”);
试一试{
MessageQueue msgReceiverOut=newmessagequeue();
msgReceiverOut.setMessageType(SocketMessages.STATUS_OFFLINE);
queueReceiverOut.put(msgReceiverOut);
}捕捉(中断异常e1){
//TODO自动生成的捕捉块
e1.printStackTrace();
}
e、 printStackTrace();
}捕捉(中断异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
public int[]receiveMessage()引发IOException{
int[]messageHead=newint[2];
messageHead[0]=in.read();
如果(消息头[0]!=-1){
System.out.println(“接收到类型为“+messageHead[0]”的消息);
int length1=in.read();
int length2=in.read();
int length3=in.read();
int length4=in.read();
消息头[1]=((长度1 24)和0xFF);
out.write((数据长度>>>16)和0xFF);
out.write((数据长度>>>8)和0xFF);
out.write((数据长度>>>0)和0xFF);
msg.setMessageType(messageType);
queueSenderOut.put(msg);
}
公共void sendData(字节[]数据)引发IOException{
字符串=新字符串(数据,“UTF-8”);
Log.v(getClass().getName(),“带内容:“+string”);
输出。写入(数据);
}
公共布尔值isRun(){
回程;
}
公共void setRun(布尔运行){
this.run=run;
}
}

更新:因为误解了异常

在异常情况下,基础连接可能会因以下原因中断: 远程主机或网络软件(例如连接 在TCP连接的情况下重置)。当连接断开时 网络软件检测到以下情况适用于返回的 输入流:

  • 网络软件可能会丢弃由缓存的字节 套接字。网络软件未丢弃的字节可以 使用read读取

  • 如果套接字上没有缓冲的字节,或所有缓冲的字节 已被read占用,则所有后续调用将读取 抛出一个IOException

  • 如果套接字上没有缓冲字节,并且套接字没有 已使用close关闭,则available将返回0

发件人:

尤其要注意“后续调用”部分。这意味着,如果您已经在
读取
调用中阻塞,则上述关于读取调用的条件(尚未)不适用

到目前为止,解释是正确的。现在来看解决方案: 您可以(多种可能性中的一种)定期发送消息,即使在通信空闲时也是如此。因此,您的发送方将检测到连接丢失,并可以关闭流中的消息


编辑:为了让它更清楚一点

  • 连接损耗
  • 呼叫读取
  • IOException
  • 鉴于

  • 调用读取(块!)
  • 等待输入:连接丢失
  • --也不例外

  • 我想重点是(我想)您的服务器进入读取并在那里停留很长时间,而您的客户端在连接断开时正在接收数据。因此,它将不断地从
    read
    调用并返回。在等待读取解除阻止时仍有可能发生连接断开,但可能性要小得多。

    双方是否定期发送?A
    read
    仅当调用连接时连接已丢失时才打开IOException。如果连接已丢失,则打开IOException
       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;
    }