使用连接构造函数创建套接字的连接超时时间是多少?

4
使用连接构造函数创建的套接字的连接超时时间是多久?在Java SE 6中,以下Socket构造函数会立即连接套接字,而不需要在构建后调用connect:Socket(InetAddress地址,int端口),Socket(InetAddress主机,int端口,boolean流),Socket(InetAddress地址,int端口,InetAddress localAddr,int localPort),Socket(String host,int port),Socket(String host,int port,boolean stream)和Socket(String host,int port,InetAddress localAddr,int localPort)。虽然Java SE创建了500种构建套接字的方法,这很好、方便,您可以浏览500个构造函数列表,找到一个大致符合您要求的构造函数(而不是调用new Socket(),然后调用Socket#connect()),但这些构造函数的文档都没有说明连接超时时间或是否/如何调用connect(SocketAddress endpoint,int timeout)。也许构造函数文档中关于createSocketImpl的内容暗示了超时时间,或者其他地方的一些文档说了什么?有人知道任何一个构造函数的实际连接超时时间是多少吗?背景:好的,假设规范真的含糊不清(我以为Java是可移植的?),我正在试图弄清楚客户代码在看似随机的时间被冻结的原因。我有一些调用一些开源库的代码,该库调用其中一个构造函数。我想知道调用其中一个构造函数是否会使超时时间无限长或非常长。我不知道客户使用的JDK版本,因此如果规范中有超时时间,那就太好了。我想我可以从客户那里获得JDK版本,但它可能是闭源JDK。在这种情况下,我是否可以反向工程化他们的SE库版本中的代码来找出答案?这难吗?我会入狱吗?
6个回答

3
尽管Java文档表示超时时间是无限的,但实际上这意味着JVM不会对连接操作施加任何超时限制,然而操作系统可以对任何套接字操作施加超时设置。
因此,实际超时时间将取决于您的操作系统TCP/IP层设置。
一个好的编程实践是为所有套接字操作设置超时时间,最好通过配置文件进行配置。具有可配置性的优点是根据部署环境的网络负载,可以调整超时时间,而无需重新构建/测试/发布整个软件。

我假设你说的是明确地将超时设置为0(而不是我提到的构造函数的超时)。问题在于,我正在分析别人编写的代码,以找出它为什么会卡在客户现场。 - megazord
当使用构造函数时,默认超时时间为0(无限)。因此,行为仍将取决于操作系统设置。 - Hitesh
是的,我现在明白了(尽管通过“无限超时”,人们可能会认为规范意味着无限超时)。 - megazord

3

Java规范是有问题的。它没有说明任何构造函数的超时时间,因此实现可以将超时时间设置为0.000000000001纳秒,并仍然正确。此外:非有限超时时间甚至不被虚拟机实现所尊重(如在此处所见),因此看起来规范并不重要,因为没有人遵循它。

结论:您必须阅读客户JVM的闭源二进制文件(可能是非法的,但您必须做您必须做的事情),还要阅读操作系统套接字文档。


没有人能够跟上它。没有平台支持无限制的连接超时。 - user207421
2
“没有人能够跟上它。”即使在TCP套接字中这是真的,仍然可以通过packet(7)来完成...不断发送SYN直到获得响应。实际上,即使你所说的话是明显错误的,实现也可以简单地每次创建新的套接字并永远尝试连接。问题在于制作Java套接字模块的兄弟们没有决定它们是只是socket(2)的包装器还是实际有用的高级模块。显然这个模块没有经过深思熟虑。 - Dude Bro
1
当然,Java可以自己发送SYN数据包或在内部循环,但它没有这样做。操作系统已经有了TCP/IP实现,这就是Java使用的内容。没有平台支持无限超时,这仍然是真实的。我不知道您所说的“显然未经思考的模块”是什么意思。 - user207421

2
根据资料(我这里看的是1.5_13版本,但不应有区别),不同的Socket构造函数都调用了Socket(SocketAddress, SocketAddress, boolean),该函数定义如下:
private Socket(SocketAddress address, SocketAddress localAddr,
           boolean stream) throws IOException {
    setImpl();

    // backward compatibility
    if (address == null)
        throw new NullPointerException();

    try {
        createImpl(stream);
        if (localAddr == null)
        localAddr = new InetSocketAddress(0);
        bind(localAddr);
        if (address != null)
        connect(address);
    } catch (IOException e) {
        close();
        throw e;
    }
}

connect(SocketAddress)的定义如下:

public void connect(SocketAddress endpoint) throws IOException {
    connect(endpoint, 0);
}

因此,超时时间为无限(正如@Keppil已经指出的那样)。

2

1
Socket类自Java 1.0以来就存在,但当时只能创建立即连接的套接字,并且无法指定连接超时。自Java 1.4以来,可以创建未连接的套接字,然后使用connect方法指定超时时间。我认为有人简单地忘记了“旧”构造函数的文档说明,指定这些构造函数仍然在没有显式超时的情况下运行。
具有超时参数的连接方法的文档读取“超时为零被解释为无限超时”。实际上,这也是不正确的,因为它仅意味着Java VM不暗示超时。即使超时为0,连接操作仍可能在操作系统的TCP / IP堆栈中超时。

1
嗯...也许他们应该只是记录生成的C调用。 - megazord
megazord:当然,这是非常具体于实现的细节,无法在API文档中记录。他们当然可以写下,大多数情况下使用的TCP/IP堆栈将超时,因此“无限超时”不必过于严格解释。 - jarnbjo

1

这是与平台相关的,但大约需要一分钟左右。connect() 的 Javadoc 在声明它是无限的时是不正确的。还要注意,connect() 超时参数只能用于减少默认值,而不能增加它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接