2011-10-04 24 views
0

當我重新啓動應用程序時,出現BindException。它充當等待遠程控制消息的服務器。 ServerSocket在後臺線程(AsyncTask)中運行。重新啓動我的應用程序後,我總是得到上述異常。我必須等待10分鐘,直到它再次綁定到端口才能聽取。重新啓動應用程序後出現「BindException:地址已被佔用」

我嘗試了不同的端口(全部> 50000),所以我確定沒有其他應用程序阻止我的端口。我試圖小心關閉套接字,並試圖使用SO_REUSEADDR選項。另外我確信在運行時只有一個連接打開,因爲我記錄了每個socketbind。

所以我認爲,連接沒有正確關閉。我讀過關於套接字不立即關閉的習慣。但是,在每次重新啓動應用程序時,我都等不到10分鐘,我沒有找到縮短或殺死這個時間的方法。

你有什麼想法嗎?

例外:

10-04 16:39:22.526: WARN/System.err(4974): java.net.BindException: Address already in use 
10-04 16:39:22.526: WARN/System.err(4974):  at org.apache.harmony.luni.platform.OSNetworkSystem.bind(Native Method) 
10-04 16:39:22.526: WARN/System.err(4974):  at dalvik.system.BlockGuard$WrappedNetworkSystem.bind(BlockGuard.java:275) 
10-04 16:39:22.526: WARN/System.err(4974):  at org.apache.harmony.luni.net.PlainSocketImpl.bind(PlainSocketImpl.java:165) 
10-04 16:39:22.526: WARN/System.err(4974):  at java.net.ServerSocket.<init>(ServerSocket.java:123) 
10-04 16:39:22.526: WARN/System.err(4974):  at java.net.ServerSocket.<init>(ServerSocket.java:74) 
10-04 16:39:22.526: WARN/System.err(4974):  at com.*******.remote.RemoteHandlerListener$1.doInBackground(RemoteHandlerListener.java:114) 

代碼:

ServerSocket server; 
try { 
    server = new ServerSocket(); 
    server.setReuseAddress(true); 
    server.bind(new InetSocketAddress(serverport)); 
} catch (IOException e) { 
    e.printStackTrace(); 
    return null; 
} 

while (true) { 
    BufferedReader inStream = null; 
    Socket client = null; 
    try { 
     client = server.accept(); 
     inStream = new BufferedReader(new InputStreamReader(client.getInputStream())); 
     // read from stream 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } finally { 
     if (inStream != null) { 
      try { 
       inStream.close(); 
      } catch (IOException e) { } 
     } 
     if (client != null) { 
      try { 
       client.close(); 
      } catch (IOException e) { } 
     } 
    } 
} 
try { 
    server.close(); 
} catch (IOException e) { } 

的異常在server.bind語句拋出。

編輯: 問題的原因:自接受呼叫阻塞後,線程不會自行終止。該程序沒有完全終止,並且套接字未被綁定。

解決方案:將SO_TIMEOUT設置爲套接字並在while() - 循環中檢查isCancelled。這樣,如果你調用cancel(),線程就會完成。

+0

您可以定義「重新啓動」和「後臺線程」嗎?你是從任務管理器中殺死應用程序並重新啓動它,還是重新安裝.apk?當你說後臺線程時,你使用的是AsyncTask還是傳統的Java線程,並且它被標記爲守護進程?這些都與應用程序生命週期和虛擬機如何與併發單元一起工作。 –

+0

通過重新啓動,我的意思是在開始活動中按下後退按鈕,然後通過單擊圖標,然後再次啓動它,從而調用onDestroy方法,在那裏停止線程。不涉及任務管理器或重新安裝。通過taskmanager殺死應用程序解決了這個問題,但並不是真正的解決方案。 –

+0

作爲後臺線程我使用AsyncTask。 –

回答

0

嘗試打印所有捕獲到的異常的堆棧跟蹤。這可能會有很大的幫助。也許你發佈的代碼有問題。您正在創建try-catch塊而不處理Exception。你甚至不知道有沒有。


更新:下一步是確保您的應用程序真正停止。乍一看你的代碼,你從來沒有退出你的無限循環接受客戶端。嘗試解決,並添加一個print語句在關閉的ServerSocket後:

try { 
    server.close(); 
    System.out.println("Server successfully stopped."); 
} catch (IOException e) { } 

確保你在你的應用程序的輸出找到。

如果你想馬虎,你可以使用強制執行的應用程序(和ServerSocket的)關機:

System.exit(0); 
+0

我添加了缺少的printStackTrace()。除了BindException外,不會引發其他異常。 –

+0

是的,這是問題。我沒有中斷線程,但檢查線程是否應該停止(通過isCancelled)並讓線程自行終止。現在如果沒有傳入連接會發生什麼?是的,自accept() - 調用被阻塞以後,線程不會自行終止。這種方式線程沒有停止。愚蠢的錯誤;) –

0

我同意 - 這通常表明重啓未能正確地終止服務器進程。不知何故它仍在運行,因此端口仍然被阻塞。

等待10分鐘有點長。只需檢查(如果可能)以前運行的java進程是否已終止。

+0

這是一個有用的提示。確保通過手動殺死應用程序確實停止了應用程序。但是,我如何確保我的應用程序始終被終止,或者如何在重新啓動時終止它? –

+0

確定在「啓動」應用程序時創建的操作系統進程,然後您知道需要注意哪個進程以確定它是否仍然存在。根據啓動程序的包裝,它可以是啓動的可執行文件的名稱或Java。從任務管理器/進程列表中關閉該進程將會關閉套接字,但是如果進程可能會在磁盤上留下不一致的狀態,那麼應該小心。一些不太健壯的應用程序在重要部分死亡時不會重新啓動。 –

0

如果你還沒有,你應該學習Android開發的東西Activity Lifecycles。那篇文章的tl; dr是,Android操作系統完全不能保證應用程序何時會被殺死,除非它可以隨時發生,這就是爲什麼他們提供onPause,onResume,onRestart等等。你不能永遠保證你的應用程序總是會完全死掉,但是你可以執行自己的清理,並且我建議在onPause中關閉你的線程並關閉你的套接字(或其他管理)。另外,當使用Java套接字(不管它是否是Android)時,讓程序終止成爲關閉套接字的動作永遠不是好習慣。你應該幾乎總是在某種清理區域關閉它們。特別是在處理線程時。

更新:你說你打回去然後重新啓動。這不會調用onDestroy。 onDestroy僅在操作系統需要內存並完全殺死您的應用時纔會調用(相當於在任務管理器中將其殺死)

+0

你是對的。 onStop()本來就是我想的方式。 –

相關問題