当前位置: 首页 > 知识库问答 >
问题:

Android客户端-服务器通信在输入时引发异常。阅读

景稳
2023-03-14

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

通信基于每边的三个线程(服务器有接受新套接字的额外线程)

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

第二个线程是接收器,它定期读取套接字(通过输入tream.read),如果有消息,它会通过LinkedBlockingQueue将消息传递给主管

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

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

问题是:防止客户端接收器抛出异常(这看起来像一些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个答案

叶健柏
2023-03-14

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

>

如果套接字上没有缓冲的字节,或者所有缓冲的字节都已被read占用,那么所有后续的read调用都将抛出IOException。

如果套接字上没有缓冲的字节,并且未使用close关闭套接字,那么available将返回0。

发件人:http://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#getInputStream()

尤其是“后续电话”部分。这意味着,如果您已经在一个read调用中阻塞,则上述关于read调用的条件(尚未)不适用。

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

编辑:为了更清楚一点...

  1. 连接丢失

然而

  1. 呼叫读取(块!)
  2. 等待输入:连接丢失
  3. --也不例外

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

 类似资料:
  • 我有一个使用Netty用Java设计的非常简单的服务器。我还使用Java NIO包编写了一个简单的客户端。我可以将Netty服务器与客户端连接起来,但当消息发送到服务器时,我会遇到以下例外情况: 我的输出: 我的服务器程序: 我的ServerHandler: 我的NIO Java客户端: 2)我正在使用LengthFieldBasedFrameDecoder和LengthPrepender来消除半

  • 问题内容: 我目前处于论文项目的研究阶段。 我的项目是用于移动设备的票务预订系统,我选择了以Android为目标。 我预计需要具有中央服务器的客户端/服务器架构,因此目前正在研究Android如何与此类服务器进行通信。服务器将授予客户端访问票务信息的权限,客户端会将有关票务预订的信息发送到服务器。我正在寻找服务器的Java EE,因为Java是我最有经验的语言。 我知道Android附带了和以及一

  • 问题内容: 所以现在,我正在制作一个基于客户端服务器应用程序的多线程。在服务器端,我为接受的每个连接创建了一个线程。 在线程类中,我创建了一种将命令发送到客户端的方法。我只想要的是如何将参数发送到所有正在运行的客户端?为简单起见,我只想使此服务器向所有连接的客户端发送消息。 我已经阅读了这篇文章,并从此链接中找到方法。但是,当我尝试使用自己的代码时,中没有类似的方法。 好的,这是我的服务器和线程示

  • 本文向大家介绍python服务器与android客户端socket通信实例,包括了python服务器与android客户端socket通信实例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了python服务器与android客户端socket通信的方法。分享给大家供大家参考。具体实现方法如下: 首先,服务器端使用python完成,下面为python代码: 下面是Android代码: 安卓代

  • 我对spring boot和SSL还很陌生。我已经开发了一个SSL rest web服务器,它具有服务器密钥存储库、私钥和服务器CA,并且能够正确地处理相互X.509证书身份验证。我已经测试过,它可以与Postman和Python客户机一起工作HTTPS请求,并且所有工作都正常,服务器和客户机都可以成功地交换和验证对方的证书。 但我的情况有点不同, 我已经创建并连接了一个Postgresql数据库

  • 现在我的ServerSocket是这样的 一切正常,客户端连接,发送一些数据,服务器读取它,但我的问题是如何从我的服务器发送消息到所有的客户端?我目前保存客户端上的ArrayList,所以我可以只是循环,ArrayList打开一个作家和刷新它,但我想发送的数据,我得到我的ClientConnection类 我应该如何处理这个代码?在服务器类上完成的所有操作?或