Java Android客户端服务器通信在input.read上引发异常
我正在使用套接字和输入、输出流(没有像datainputstream、ObjectInputStream等包装类)开发Android服务器通信 通信基于每侧的三个线程(服务器具有接受新套接字的附加线程) 第一个线程是控制器,它通过LinkedBlockingQueue接受来自接收方的消息,对它们作出反应,并通过LinkedBlockingQueue将数据发送给发送方 第二个线程是周期性地读取套接字(通过InputStream.read)的接收器,若有消息,则通过LinkedBlockingQueue将其传递给控制器 当连接丢失时,客户端Android设备(已阻止input.read)立即抛出连接超时异常 第三个线程是发送方,它定期从LinkedBlockingQueue接收消息并将数据发送到连接的另一端 问题是:防止客户端接收器上的异常抛出(这看起来像是Android的东西,因为input.read-alone不应该抛出任何与超时连接相关的异常) 以下是接收器的代码:Java Android客户端服务器通信在input.read上引发异常,java,android,sockets,client-server,Java,Android,Sockets,Client Server,我正在使用套接字和输入、输出流(没有像datainputstream、ObjectInputStream等包装类)开发Android服务器通信 通信基于每侧的三个线程(服务器具有接受新套接字的附加线程) 第一个线程是控制器,它通过LinkedBlockingQueue接受来自接收方的消息,对它们作出反应,并通过LinkedBlockingQueue将数据发送给发送方 第二个线程是周期性地读取套接字(通过InputStream.read)的接收器,若有消息,则通过LinkedBlockingQue
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
读取
调用中阻塞,则上述关于读取调用的条件(尚未)不适用
到目前为止,解释是正确的。现在来看解决方案:
您可以(多种可能性中的一种)定期发送消息,即使在通信空闲时也是如此。因此,您的发送方将检测到连接丢失,并可以关闭流中的消息
编辑:为了让它更清楚一点
我想重点是(我想)您的服务器进入读取并在那里停留很长时间,而您的客户端在连接断开时正在接收数据。因此,它将不断地从
read
调用并返回。在等待读取解除阻止时仍有可能发生连接断开,但可能性要小得多。双方是否定期发送?Aread
仅当调用连接时连接已丢失时才打开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;
}