私の状況は次のとおりです。
どちらも Android OS を搭載した 2 台のデバイス
One Devices はサーバーです。これは Service で実行され、スレッドを実行して接続とすべての通常のプロトコルを作成します。
もう 1 つは 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 プロトコルを最終的に実行しました。
それを行うために、タイムアウトを使用して新しいスレッドを作成しました。パケットを送信した後にサーバーが応答しなかった場合、これは接続を停止し、クライアントに通知します
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);
}
これが役立つことを願っています。