Java 插座连接超时上限
我正在使用Java套接字。我有一行代码:Java 插座连接超时上限,java,sockets,Java,Sockets,我正在使用Java套接字。我有一行代码: Socket webSocket = new Socket(); webSocket.connect(new InetSocketAddress(domain, 80), 120000); 指定的超时为120000ms(2分钟)。我很好奇这个超时是否真的被遵守,或者它是否被限制在平台默认连接超时值。另外,如何检查平台的默认连接超时值?换句话说,调用此代码时超时是多少: Socket webSocket = new Socket(domain, 80);
Socket webSocket = new Socket();
webSocket.connect(new InetSocketAddress(domain, 80), 120000);
指定的超时为120000ms(2分钟)。我很好奇这个超时是否真的被遵守,或者它是否被限制在平台默认连接超时值。另外,如何检查平台的默认连接超时值?换句话说,调用此代码时超时是多少:
Socket webSocket = new Socket(domain, 80);
首先,此超时是否取决于平台?我知道有SO\u TIMEOUT
,但我认为它只影响read()
超时,而不影响connect()
我认为存在默认超时,因为不指定超时值仍然会导致连接超时:connect默认套接字超时为0,这意味着从不超时。
如果它实际上在x分钟后超时,这意味着它已在代码中设置。在您的情况下是2分钟。默认套接字超时为0,这意味着从不超时。
如果它实际上在x分钟后超时,这意味着它已在代码中设置。在您的情况下是2分钟。默认套接字超时为0,这意味着从不超时。
如果它实际上在x分钟后超时,这意味着它已在代码中设置。在您的情况下是2分钟。默认套接字超时为0,这意味着从不超时。
如果它实际上在x分钟后超时,这意味着它已在代码中设置。就您的情况而言,这是2分钟。进一步调查,您会发现java连接超时和系统级连接超时之间存在细微的区别 通过更改行:
webSocket.connect(new InetSocketAddress(domain, 80), 120000);
NET_ThrowNew(env, err, "connect");
例如:
webSocket.connect(new InetSocketAddress(domain, 80), 10);
您将看到一个完全不同的异常:java.net.SocketTimeoutException
,而不是通常的java.net.ConnectException
对Socket.connect()
的实际调用实际上被推迟到一个SocketImpl
抽象类,以便定义精确的机制。从Socket
中的connect()
方法摘录中可以看出:
...
if (!oldImpl)
impl.connect(epoint, timeout);
else if (timeout == 0) {
if (epoint.isUnresolved())
impl.connect(addr.getHostName(), port);
else
impl.connect(addr, port);
...
从根本上说,第二个异常(ConnectException
)是一个依赖于实现的异常,这意味着操作系统本身有一个最大超时时间,该时间在设置java超时时间之前已经达到。进一步探索,在检查ConnectException
的堆栈跟踪后,我们看到类似的情况(在windows计算机上):
请注意,异常实际上是从本机方法传播的,即从本节传播的(由OpenJDK提供):
该行:
rv = connect(fd, (struct sockaddr *)&sa, sa_len);
实际上是对Winsock2 connect函数的调用,可以查看其MSDN页面。Winsock2套接字本身已设置为默认套接字(setsockopt
中的optval
为零)。这意味着它继承了发送和接收的任何系统默认超时。如果连接尝试超过默认超时值,则会在rv
中出现SOCKET\u错误
,从而导致线路:
webSocket.connect(new InetSocketAddress(domain, 80), 120000);
NET_ThrowNew(env, err, "connect");
要运行,传播ConnectException
备份堆栈。(如果您不相信我,请查看OpenJDK源代码中的DualStackPlainSocketImpl.c
)
嗯。。。java设置超时到哪里去了?答案是在方法socketConnect()
下的文件DualStackPlainSocketImpl.java
中转换到本机层之前的一个堆栈级别,特别是以下片段:
configureBlocking(nativefd, false);
try {
connectResult = connect0(nativefd, address, port);
if (connectResult == WOULDBLOCK) {
waitForConnect(nativefd, timeout);
}
} finally {
configureBlocking(nativefd, true);
}
其中,connect0
是对本机函数的实际调用
本质上,当java出现有限的非零超时时,它会以异步模式启动本机套接字连接,并等待超时过期或本机方法完成,以先发生的为准。设置较大超时值的问题是,本机连接函数本身可能超时并引发ConnectException
而不是通常的SocketTimeoutException
。(在Java 8下的特定Windows 10系统上)
同样的练习可以在不同的系统上进行,以确定套接字超时工作的确切机制
tl;医生:
共识是,基本上所有套接字操作都是实现定义的。即使从第一个堆栈层开始,您也会发现,
Socket
将其大部分工作推迟到由操作系统实现的抽象的SocketImpl
。因此,操作系统完全有可能(如上所述)有更长、更短或完全不存在的超时。从某种意义上说,java超时只有在短于操作系统默认超时(如果有)的情况下才能正常工作,因此您应该准备好处理这两种情况(操作系统因其本机超时而引发异常,而不是java特定超时到期)。进一步调查,您会发现java连接超时和系统级连接超时之间存在细微的区别
通过更改行:
webSocket.connect(new InetSocketAddress(domain, 80), 120000);
NET_ThrowNew(env, err, "connect");
例如:
webSocket.connect(new InetSocketAddress(domain, 80), 10);
您将看到一个完全不同的异常:java.net.SocketTimeoutException
,而不是通常的java.net.ConnectException
对Socket.connect()
的实际调用实际上被推迟到一个SocketImpl
抽象类,以便定义精确的机制。从Socket
中的connect()
方法摘录中可以看出:
...
if (!oldImpl)
impl.connect(epoint, timeout);
else if (timeout == 0) {
if (epoint.isUnresolved())
impl.connect(addr.getHostName(), port);
else
impl.connect(addr, port);
...
从根本上说,第二个异常(ConnectException
)是一个依赖于实现的异常,这意味着操作系统本身有一个最大超时时间,该时间在设置java超时时间之前已经达到。进一步探索,在检查ConnectException
的堆栈跟踪后,我们看到类似的情况(在windows计算机上):
请注意,异常实际上是从本机方法传播的,即从本节传播的(由OpenJDK提供):