Androin學習筆記四十二:Java android Socket通訊檢測(server)連線是否斷開
阿新 • • 發佈:2019-01-24
Pre
在利用socket寫通訊程式的時候,想檢測伺服器是否還活著。
從網上找了很多資料,都沒有自己合適的,最後自己想了個辦法,不過也相當於截取了心跳檢測的一部分。
這裡檢測的是遠端server的連線,而不是本地是否連線成功。首先想到socket類的方法isClosed()、isConnected()、isInputStreamShutdown()、isOutputStreamShutdown()
等,但經過試驗並檢視相關文件,這些方法都是本地端的狀態,無法判斷遠端是否已經斷開連線。
而有一個方法sendUrgentData
,檢視文件後得知它會往輸出流傳送一個位元組的資料,只要對方Socket的SO_OOBINLINE屬性沒有開啟,就會自動捨棄這個位元組。
或者,其實如果斷開連線了,你傳送過去的資料會收不到,最後client會丟擲io異常。
但是,上面兩個方法,丟擲異常的時間長達15秒!簡直不能忍。
解決思路
當然,這裡的需求環境是:傳送資料次數非常少,幾乎只需要判斷一兩次,資料是集中傳送的。那麼,就可以這樣了:
只要client在傳送資料前,先發送自定義的一個測試資料,並自定義一個String之類的變數(初始值null)來接收server發回的資料,client發完測試資料,睡500毫秒(自定義時間)(非同步接收伺服器訊息),然後立刻檢測這個string是不是null,就可以知道server是否收到訊息了。
程式碼
客戶端app上的部分程式碼
/**客戶端執行緒,用來建立連線和傳送訊息 */
public class Client implements Runnable{
Socket s=null;
DataInputStream dis=null;
DataOutputStream dos=null;
private boolean isConnected=false;
Thread receiveMessage=null;
/**傳送訊息
* @param str 傳送的資訊,client僅向server傳送兩次訊息,這是我自己的應用需求,根據實際情況來做你的。
* @throws IOException
* */
public void sendMessage(String str) throws IOException{
dos.writeUTF(str);
dos.flush();
}
/**斷開連線*/
public void disConnect(){
try {
dos.close();
dis.close();
s.close();
} catch (IOException e) {
System.out.println("client closed error");
e.printStackTrace();
}
}
/**建立socket連線,開啟接收資料執行緒 * */
public void run() {
try {
s=new Socket(SERVER_HOST_IP,SERVER_HOST_PORT);
s.setOOBInline(true);
dis=new DataInputStream(s.getInputStream());
dos=new DataOutputStream(s.getOutputStream());
System.out.println("connected!");
isConnected=true;
receiveMessage=new Thread(new ReceiveListenerThread());
receiveMessage.start();
//傳送imei
sendMessage(IMEI);
} catch (UnknownHostException e) {
System.out.println("fuwuqoweikaiqi");
e.printStackTrace();
} catch (IOException e) {
System.out.println("ioerr");
e.printStackTrace();
}
}
private class ReceiveListenerThread implements Runnable{
//這一部分接收資料的處理,請根據實際情況修改
String data[]=new String[3];
public void run() {
try {
if(isConnected){
String receivedMessage=dis.readUTF();
System.out.println(receivedMessage);
serverStarted=true;
data=receivedMessage.split("_");
isLegal=Integer.parseInt(data[0]);
num1=Integer.parseInt(data[1]);
num2=Integer.parseInt(data[2]);
System.out.println(""+isLegal+num1+""+num2);
}
if(isConnected){
finalOK=dis.readUTF();
}
}catch (SocketException e){
System.out.println("exit!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
呼叫:
Client client=null;
/**客戶端網路執行緒*/
Thread tClient=null;
client=new Client();
tClient=new Thread(client);
tClient.start();
伺服器上:
/** 這是伺服器用來接收處理客戶端的執行緒類 */
class Client implements Runnable {
private Socket s;
private DataInputStream dis = null;
private DataOutputStream dos = null;
private boolean isConnected = false;
public Client(Socket s) {
this.s = s;
try {
dis = new DataInputStream(s.getInputStream());
dos = new DataOutputStream(s.getOutputStream());
isConnected = true;
} catch (IOException e) {
System.out.println("on clients' data in and out have error");
// e.printStackTrace();
}
}
public void run() {
String str;
try {
// 先檢查是否是合法的客戶端
while (isConnected) {
str = dis.readUTF();
str = dis.readUTF();
//此處的具體程式碼省略
dos.writeUTF("ok");
dos.flush();
}
}
} catch (EOFException e) {
System.out.println("Client closed");
Home.appendMessage((legalNum + 1) + "號客戶端已經登出");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dis != null)
dis.close();
if (dos != null)
dos.close();
if (s != null)
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客戶端判斷伺服器是否還活著程式碼:
try {
//客戶端傳送一個測試資訊
client.sendMessage(cookie);
System.out.println("send");
//睡1秒
SystemClock.sleep(1000);
//這個finalok是在客戶端的接收執行緒那裡處理的。如果不是null說明伺服器沒問題
if(finalOK!=null){
client.disConnect();
exit("感謝您的使用,本次已經結束~");
}else{
throw new IOException() ;
}
//超時檢測
} catch (IOException e) {
new AlertDialog.Builder(MainActivity.this).setTitle("提示").setPositiveButton("好的", null).setMessage("伺服器關閉了,請聯絡管理員並在伺服器重新開啟後再次點選【傳送】來提交資料").show();
client.disConnect();
e.printStackTrace();
}