阻止应用程序绑定到已绑定的套接字

时间:2013-05-16 15:46:28

标签: java sockets

如何阻止Java应用程序绑定到另一个进程已在Windows上绑定的套接字?

我遇到一个问题,我有一个正在侦听端口80的Java应用程序。应用程序启动正常并且报告没有异常。我无法弄清楚为什么我无法连接端口80.其他端口工作正常。我检查了netstat上其他正在监听80的进程并找到了Skype。我不认为这是可能的,但经过一些研究,我猜测Skype正在使用SO_REUSEADDR选项进行监听。在这种状态下,接受申请是不确定的。我希望我的Java应用程序在此实例中使用绑定异常(或其他)失败。

如果我可以通过Java访问该选项,我似乎可以使用SO_EXCLUSIVEADDRUSE,但我不认为这是可能的。围绕SO_REUSEADDR有很多问题和答案,但我找不到任何问题和答案。这不仅仅是关于Skype(我可以关闭收听部分),我希望我的程序在这种情况下更加强大。

这是来自Windows 7盒子上netstat -abn的片段:

    Proto  Local Address          Foreign Address        State
    TCP    0.0.0.0:80             0.0.0.0:0              LISTENING [java.exe]
    TCP    0.0.0.0:80             0.0.0.0:0              LISTENING [Skype.exe]

这就是为什么我假设Skype正在使用SO_REUSEADDR

进程似乎没有在不同的接口上侦听。

以下是代码片段。端口是80:

    myServerSocket = new ServerSocket(myTcpPort);
    while (true) {
        new HTTPSession( myServerSocket.accept(), threadPool );
    }

作为进一步的信息,我创建了一个示例程序,以尽量减少任何副作用或错误处理的消息。

    import java.net.ServerSocket;

    public class PortTest
    {
        public static void main(String[] args)
        {
            System.out.println( "Hit Ctrl-C to stop.\n" );

            try {
                ServerSocket myServerSocket = new ServerSocket(80);
                System.out.println( "Before the accept() call.");
                myServerSocket.accept();
                System.out.println( "After the accept() call." );
            }
            catch (Exception ex ) {
                System.out.println("Error listening.");
                ex.printStackTrace();
            }
         }

    }

运行此示例程序(PortTest)时以及Skype正在运行并侦听端口80时,我仍然没有异常。为了进一步测试,我执行了第二个实例PortTest,我确实看到了正在使用的端口消息

    Error listening.
    java.net.BindException: Address already in use: JVM_Bind
            at java.net.DualStackPlainSocketImpl.bind0(Native Method)
            at java.net.DualStackPlainSocketImpl.socketBind(Unknown Source)
            at java.net.AbstractPlainSocketImpl.bind(Unknown Source)
            at java.net.PlainSocketImpl.bind(Unknown Source)
            at java.net.ServerSocket.bind(Unknown Source)
            at java.net.ServerSocket.<init>(Unknown Source)
            at java.net.ServerSocket.<init>(Unknown Source)
            at PortTest.main(PortTest.java:10)

2 个答案:

答案 0 :(得分:2)

socket = new ServerSocket(0);

会自动为您选择一个免费端口。

此外,此代码将告诉您端口是否可用:

boolean portAvaliable = true;
    ServerSocket s = null;
    try {
          s = new ServerSocket(yourPort);
         }
     catch (IOException e)
        {
          portAvaliable = false;
        } 
     finally {
        if (s != null)
          try {
               s.close();
              } 
          catch (IOException e) 
              { 
               //handle the exception
              }

答案 1 :(得分:0)

对于任何想知道的人来说,7u25之前的Java都存在这个问题。

以下摘自release note of Java 7u25

  

更改Windows平台上的网络API实施

     

在   Windows上的网络API实现已更改为   默认情况下使用SO_EXCLUSIVEADDRUSE套接字选项。这种变化是   解决使用IPv4和IPv4时出现的异常情况所必需的   需要绑定到同一端口的IPv6应用程序。

这个问题是Windows独有的,因为 [1] SO_REUSEADDR [2] 在那里工作的时髦。