我的情况如下:
两台设备,均运行 Android 操作系统,
一个设备是服务器,它与服务一起运行并运行线程以创建连接和所有正常协议,
另一个是任何带有 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 评论的心跳协议。
为此,我创建了一个超时的新线程,如果服务器在发送数据包后没有回复,则停止连接并通知客户端
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);
}
希望这能有所帮助。