【问题标题】:How to avoid java.net.BindException: Address already in use如何避免 java.net.BindException:地址已在使用中
【发布时间】:2012-04-03 12:09:49
【问题描述】:

以下运行了 1 小时然后关闭:

public class Mp extends JWindow implements MouseListener, MouseMotionListener {
    public static Mp j;
  private int serverPort = 0;
  private ServerSocket serverSock = null;
  private Socket sock = null; 

  public static void main(final String[] args) throws IOException, InterruptedException, Exception {
    j = new Mp();
    j.setVisible(true);
    j.waitForConnections();
  }

  public void waitForConnections() {
    while (true) {
      try {
        sock = serverSock.accept();
        System.out.println("[TCPMediaHandler]: Accepted new socket");
        TCPMediaHandler handler = new TCPMediaHandler(sock);
        handler.start();
      } catch (IOException e) {
        e.printStackTrace(System.err);
      }
    }
  }

  public Mp() throws IOException {
    this.serverPort = 38891;
    serverSock = new ServerSocket(serverPort);
    serverSock.setReuseAddress(true);
    //serverSock.setSoTimeout(500);
    //serverSock.setSoLinger(true, 0);
    System.out.println("[TCPMediaHandler]: Server started");      
        this.v1.setBackground(Color.BLACK);
    this.v1.addMouseListener(this);
    /* Close the window */
    this.addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent we) {
          System.exit(0); 
        }
      });
  }

当我重新运行相同的东西时,它会以 java.net.BindException 失败:

$ java -cp /var/tmp/dist/Mp.jar test.Mp
Exception in thread "main" java.net.BindException: Address already in use
    at java.net.PlainSocketImpl.socketBind(Native Method)
    at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:353)
    at java.net.ServerSocket.bind(ServerSocket.java:336)
    at java.net.ServerSocket.<init>(ServerSocket.java:202)
    at java.net.ServerSocket.<init>(ServerSocket.java:114)
    at test.Mp.<init>(Mp.java)
    at test.Mp.main(Mp.java)

大约需要 3 到 4 分钟才能再次成功执行。如何让它在关闭后立即工作?

跟进:

$ netstat | grep 38891
tcp       35      0 localhost:38891         localhost:37842         CLOSE_WAIT 
tcp        0      0 localhost:34955         localhost:38891         ESTABLISHED
tcp       32      0 localhost:38891         localhost:37824         CLOSE_WAIT 
tcp        0      0 localhost:38891         localhost:34955         ESTABLISHED

$ lsof -w -n -i tcp:38891
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
xdg-scree 5254  sun   29u  IPv4 231948      0t0  TCP *:38891 (LISTEN)
xdg-scree 5355  sun   29u  IPv4 231948      0t0  TCP *:38891 (LISTEN)
xdg-scree 5455  sun   29u  IPv4 231948      0t0  TCP *:38891 (LISTEN)
telnet    7058  sun    3u  IPv4 242987      0t0  TCP 127.0.0.1:34955->127.0.0.1:38891 (ESTABLISHED)
sleep     9002  sun   29u  IPv4 231948      0t0  TCP *:38891 (LISTEN)
sleep     9005  sun   29u  IPv4 231948      0t0  TCP *:38891 (LISTEN)
sleep     9008  sun   29u  IPv4 231948      0t0  TCP *:38891 (LISTEN)

【问题讨论】:

    标签: java linux networking tcp


    【解决方案1】:

    你会看到你的 setReuseAddress(true) 被调用得太晚了,即在绑定抛出异常之后。

    您可以通过三个步骤创建一个未绑定的 ServerSocket,使其可重用,然后绑定它。

    ServerSocket ss = new ServerSocket();
    ss.setReuseAddress(true);
    ss.bind(new InetSocketAddress(12345));
    

    【讨论】:

    • 谢谢!我已经按照您的建议进行了尝试。但我仍然无法修复它。请参阅上面我的编辑跟进部分。仍然很少有人显示 ESTABLISHED 但实际上我没有,甚至我的应用程序也被终止了。但我仍然可以telnet localhost thatport
    • @YumYumYum 端口处于 CLOSE_WAIT 状态表明应用程序在您获取该 netstat 时仍在运行。
    • 在我的场景中,我并不真正关心端口号,因此可以使用 ServerSocket myServer = new ServerSocket(0);最终 int 端口 = myServer.getLocalPort();
    • @tobi42 在这种情况下,您不会重复使用端口,因此不会有问题。
    【解决方案2】:

    我在我的一个程序中遇到了类似的问题,但最终我实际上只是从我的 IDE 中运行该程序的一个实例——我没有注意到。始终仔细检查后台没有运行任何东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-30
      • 2014-08-11
      • 2013-09-08
      • 2012-04-14
      • 1970-01-01
      • 1970-01-01
      • 2016-12-05
      • 2018-07-10
      相关资源
      最近更新 更多