我的情况如下:
两个设备,均使用Android OS运行,
One Devices是服务器,它运行Service并运行线程来创建连接和所有正常协议,
另一个是带有android设备的客户端,这也运行一个带有连接线程的服务。
一切正常,即使客户端关闭应用程序,向服务器发送通知并关闭套接字,以及服务器是否也正常停止。
问题是服务器突然关机(关闭电源)或丢失wifi。
然后客户端永远不会检测到服务器已经停止意味着套接字被破坏了,因为从来没有我永远的意思。我等了几分钟,连接仍然存在。 我还添加了一个使用ObjectOutputStream每20秒发送一个数据包的系统,但这个发送没有任何异常。
为什么会这样?我该如何解决这个问题?
我已经阅读了一些有关此问题的帖子,但任何解决方案对我都有用。
这是服务器线程连接:
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
try {
mSocket.setKeepAlive(true);
mSocket.setSoTimeout(20 * 1000);
mOutput = new ObjectOutputStream(mSocket.getOutputStream());
mInput = new ObjectInputStream(mSocket.getInputStream());
while (mSocket.isConnected() && isAlive) {
try {
MotePacket packet = (MotePacket) mInput.readObject();
if (packet==null) continue;
MotePacket result = renderPacket(packet);
if (result==null) continue;
mOutput.writeObject(result);
mOutput.flush();
if (!isAccepted) break;
} catch (java.net.SocketTimeoutException ste) {
continue;
} catch (ClassNotFoundException ex) {
continue;
} catch (StreamCorruptedException ex) {
continue;
}
}
closeSocket();
} catch (Exception e) {
e.printStackTrace();
try {
closeSocket();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
这是客户端主题:
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
try {
mSocket = new Socket(mIp, mPort + 1);
mSocket.setSoTimeout(10 * 1000);
;// Log.v("MPB", "Sck connected " + mSocket.isConnected());
mOutput = new ObjectOutputStream(mSocket.getOutputStream());
mInput = new ObjectInputStream(mSocket.getInputStream());
;// Log.v("MPB", "Socket");
isAlive = true;
mOutput.writeObject(new MotePacket(Type.DISCOVERY,new ConnectPacket(android_id, DeviceInfo.getDeviceName())));
mOutput.flush();
while (mSocket.isConnected() && isAlive) {
try {
MotePacket packet = (MotePacket) mInput.readObject();
if (packet==null) continue;
switch (packet.getHeader()) {
case DISCOVERY:
DiscoveryPacket data = (DiscoveryPacket) packet
.getPayload();
if (data.getAck() == EngelAck.ENGEL_REJECT) {
isAlive = false;
mCallback.onConnectionReject();
break;
}
mCallback.onConnectionStablished(data.getNative_service_port());
break;
case CONNECTION:
;// Log.v("MPB", "Packet connection recevied");
mCallback.onPacketReceived((NetPacket) packet.getPayload());
break;
}
} catch (java.net.SocketTimeoutException ste) {
mSocket.sendUrgentData(1);
continue;
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
continue;
} catch (StreamCorruptedException ex) {
ex.printStackTrace();
continue;
}
}
;// Log.v("MPB", "Socket dead");
mCallback.onConnectionLost();
mSocket.shutdownOutput();
mSocket.shutdownInput();
mSocket.close();
} catch (Exception e) {
// TODO Auto-generated catch block
;// Log.v("MPB", "Socket Exception, closing it");
mCallback.onConnectionLost();
e.printStackTrace();
try {
mSocket.shutdownOutput();
mSocket.shutdownInput();
mSocket.close();
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
我知道它看起来很充满废话,但只是为了检查一切。 如果有人可以帮助我,我将不胜感激
感谢。
更新
如果有人对如何解决这个问题感兴趣,我终于做了@Nikolai N Fetissov评论的Heartbeat协议。
要做到这一点,我创建了一个超时的新线程,如果服务器在发送数据包后没有回复,则停止conexion并通知客户端
Handler hReply;
Runnable checkReply = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
Log.i("MPB", "Check if closed");
isAlive=false;
mCallback.onConnectionLost();
try {
mSocket.shutdownOutput();
mSocket.shutdownInput();
mSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.i("MPB", "Already closed");
}
}
};
public void sendPacketToJavaServer(EngelMotePacket packet) throws Exception {
if (mOutput!=null) {
if (hReply!=null)
hReply.removeCallbacks(checkReply);
hReply = new Handler();
Log.v("MPB", "send packet to server");
mOutput.writeObject(packet);
mOutput.flush();
hReply.postDelayed(checkReply, DELAY_REPLY);
}
else
throw new SocketTimeoutException();
}
然后在客户接收到答案的部分,如果收到答复,则删除回调
if (hReply !=null) {
Log.i("MPB", "remove check if closed");
hReply.removeCallbacks(checkReply);
}
希望这可以提供帮助。
答案 0 :(得分:3)
解决此类问题的传统方法是实施应用程序级协议心跳。假设没有其他应用程序数据通过连接发送,请在N
秒不活动后发送心跳消息。这意味着另一方可以假设在没有收到任何消息超过N
秒后连接已经死亡。
答案 1 :(得分:0)
此外,我添加了一个使用ObjectOutputStream每20秒发送一个数据包的系统,但这是在没有任何异常的情况下发送的。
TCP使用重新传输计时器来检测发送失败,但可能需要一些时间(甚至10分钟)。因此,发送可能不会返回错误,因为数据是从主机发送但未到达。尝试等待15分钟,看看发送是否仍然成功。