应用程序重启后,“BindException:地址已在使用中”

时间:2011-10-04 15:10:52

标签: java android sockets

当我重新启动应用程序时,我遇到了BindException。它充当等待远程控制消息的服务器。 ServerSocket在后台线程(AsyncTask)中运行。重启我的应用程序后,我总是得到上面提到的例外。我必须等待10分钟,直到它再次绑定到端口才能收听。

我尝试了不同的端口(全部> 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-statement上抛出异常。

编辑: 问题原因:由于accept-call阻塞,线程不会自行终止。该程序没有完全终止,套接字没有解除绑定。

解决方案:将SO_TIMEOUT设置为套接字并在while()循环中检查isCancelled。这样,如果你对它调用cancel(),线程就会完成。

3 个答案:

答案 0 :(得分:0)

尝试打印所有捕获的异常的堆栈跟踪。这可能会有很大帮助。也许你发布的代码有问题。您正在创建try-catch块而无需处理异常。你甚至不知道是否有。


更新:下一步是确保您的应用程序真正停止。乍一看您的代码从不退出接受客户的无限循环。尝试修复它并在关闭serversocket后添加print语句:

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

确保在应用程序的输出中找到它。

如果你想要马虎,你可以使用以下方法强制执行应用程序(以及serversocket):

System.exit(0);

答案 1 :(得分:0)

我同意 - 通常这表示重新启动无法正常终止服务器进程。不知怎的,它仍然在运行,因此端口仍然被阻止。

等待10分钟有点长。只需检查(如果可能)先前运行的java进程是否已终止。

答案 2 :(得分:0)

如果你还没有,你应该在Activity Lifecycles上学习Android开发者的东西。该文章的tl;博士是Android操作系统绝对不能保证应用程序什么时候会被杀死,除非它可以随时发生,这就是为什么它们提供onPause,onResume,onRestart等等。你不能永远保证你的应用程序将永远完全死亡,但你可以执行自己的清理工作,我建议在onPause内部杀死你的线程并关闭你的套接字(或其他一些管理)。

此外,当使用Java套接字(无论是否为Android)时,让程序终止成为关闭套接字的操作绝不是一个好习惯。你应该几乎总是在某种清理区域自己关闭它们。特别是在处理线程时。

更新:你说你正在回击然后重新启动。这不会调用onDestroy。 onDestroy仅在操作系统需要内存并完全杀死您的应用程序时调用(相当于在任务管理器中将其杀死)