我正在使用套接字和输入,输出流开发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;
}
}
更新:因为误解了异常
答案 0 :(得分:0)
在异常情况下,底层连接可能被破坏 远程主机或网络软件(例如连接 在TCP连接的情况下重置)。当连接断开时 通过网络软件检测到以下内容适用于返回的 输入流:
网络软件可能会丢弃由缓冲的字节 插座。未被网络软件丢弃的字节可以是 阅读使用阅读。
如果套接字上没有缓冲字节,或者所有缓冲的字节 已被阅读消耗,然后所有后续调用将被阅读 抛出IOException。
如果套接字上没有缓冲字节,而套接字没有 使用关闭关闭,然后可用将返回0.
来自:http://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#getInputStream()
特别注意“后续通话”部分。这意味着如果您已经在read
调用中阻止,则上述有关读取调用的条件(尚未)适用。
到目前为止的解释。现在解决方案: 即使通信空闲,您也可以(许多可能中的一种)定期发送消息。因此,发件人会检测到连接丢失,也可以关闭插播广告。
编辑:为了让它更清晰......
,而
我想重点是(我假设)服务器输入读取并在那里停留很长时间,而客户端在连接中断时接收数据。因此,它将不断调用并从read
返回。在等待读取解除阻塞时仍然可能发生连接丢失,但可能性要小得多。