android应用activity第一次进入正常第二次进入报错

时间:2022-03-02 16:33:05

         在android 开发中工作中遇到一个问题,第一次进入应用,正常退出,若采用finish(),则第二次进入时候,程序出现如下错误(代码中有serversocket)

    java.net.BindException: Address already in use: JVM_Bind

若是退出时在finish(),之后在继续调用system.exit(0),则第二次进入应用,则没有问题。

查阅资料时候 http://bbs.chinaunix.net/thread-2030722-1-1.html ,提到使用

如果服务端的程序关闭后,端口不能马上释放掉,需要等一会才能小时,在这之间再启动服务程序是起不来的,但是可以用这个函数,边面这种情况,服务程序关闭后,可以马上再起一次,不会冲突了。
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(&opt));

 理论知识 


关闭ServerSocket

     ServerSocket 的 close() 方法使服务器释放占用的端口, 并且断开与所有客户的连接. 当一个服务器程序运行结束时, 即使没有执行 ServerSocket 的 close() 方法, 操作系统也会释放这个服务器占用的端口. 因此, 服务器程序不一定要在结束之前执行 ServerSocket 的 close() 方法.

      在某些情况下, 如果希望及时释放服务器的端口, 以便让其他程序能占用该端口, 则可以显式调用 ServerSocket 的 close() 方法

SO_REUSEADDR 选项

设置该选项: public void setResuseAddress(boolean on) throws SocketException 
读取该选项: public boolean getResuseAddress() throws SocketException 
      这个选项与Socket 的选项相同, 用于决定如果网络上仍然有数据向旧的 ServerSocket 传输数据, 是否允许新的 ServerSocket 绑定到与旧的 ServerSocket 同样的端口上. SO_REUSEADDR 选项的默认值与操作系统有关, 在某些操作系统中, 允许重用端口, 而在某些操作系统中不允许重用端口.

  

      当 ServerSocket 关闭时, 如果网络上还有发送到这个 ServerSocket 的数据, 这个ServerSocket 不会立即释放本地端口, 而是会等待一段时间, 确保接收到了网络上发送过来的延迟数据, 然后再释放端口.

      许多服务器程序都使用固定的端口. 当服务器程序关闭后, 有可能它的端口还会被占用一段时间, 如果此时立刻在同一个主机上重启服务器程序, 由于端口已经被占用, 使得服务器程序无法绑定到该端口, 服务器启动失败, 并抛出 BindException:

     java.net.BindExcetpion: Address already in use: JVM_Bind                                               

      为了确保一个进程关闭了 ServerSocket 后, 即使操作系统还没释放端口, 同一个主机上的其他进程还可以立即重用该端口, 可以调用 ServerSocket 的 setResuseAddress(true) 方法:

        if(!serverSocket.getReuseAddress()) serverSocket.setReuseAddress(true);                                  

      值得注意的是, serverSocket.setReuseAddress(true) 方法必须在 ServerSocket 还没有绑定到一个本地端口之前调用, 否则执行 serverSocket.setReuseAddress(true) 方法无效. 此外, 两个共用同一个端口的进程必须都调用 serverSocket.setResuseAddress(true) 方法, 才能使得一个进程关闭 ServerSocket 后, 另一个进程的 ServerSocket 还能够立刻重用相同的端口.


按照这个思路,在serversocket创建监听时候,采用socket设置SO_REUSEADDR 。

设置的时候需要注意 

在以下代码中, 先把 ServerSocket 的 SO_REUSEADDR 选项设为 true, 然后再把它与 8000 端口绑定:

  ServerSocket serverSocket = new ServerSocket();
  serverSocket.setReuseAddress(true);              //设置 ServerSocket 的选项
  serverSocket.bind(new InetSocketAddress(8192));  //与8000端口绑定

      如果把以上程序代码改为:

  ServerSocket serverSocket = new ServerSocket(8192);
  serverSocket.setReuseAddress(true);              //设置 ServerSocket 的选项

      那么 serverSocket.setReuseAddress(true) 方法就不起任何作用了, 因为 SO_REUSEADDR 选项必须在服务器绑定端口之前设置才有效.


按照以上操作后,退出程序依然还是报错,所以进行返回操作时,在finsh(),之后关闭 myServerSocket.close(); 之后在多次的进入应用程序就再也不报错了 ,所以在以后的编程过程中,若在清理信息时候,需要考虑有木有serversocket 没有关闭的情况。


  引用了 http://blog.csdn.net/turkeyzhou/article/details/5007125 内容