setSoTimeout 的功能是啥以及它是如何工作的?
Posted
技术标签:
【中文标题】setSoTimeout 的功能是啥以及它是如何工作的?【英文标题】:What is the functionality of setSoTimeout and how it works?setSoTimeout 的功能是什么以及它是如何工作的? 【发布时间】:2012-10-01 00:21:05 【问题描述】:我正在尝试自己学习 Socket。我对 Oracle 网站上的以下文字有点困惑。我对此有一些疑问。提前感谢您提供任何明确的解释。
setSoTimeout
public void setSoTimeout(int timeout) 抛出 SocketException
使用指定的超时启用/禁用 SO_TIMEOUT,以毫秒为单位。将此选项设置为非零超时后,对与此 Socket 关联的
InputStream
的read()
调用将仅阻塞这段时间。如果超时到期,则会引发java.net.SocketTimeoutException
,尽管 Socket 仍然有效。必须在进入阻塞操作之前启用该选项才能生效。超时必须 > 0。超时为零被解释为无限超时。
-
什么是 SO_TIMEOUT?
Socket 是连接的端点。如果我说
mySocket.setSoTimeout(2000);
这是否意味着我在 2000 毫秒内阻止从服务器/客户端读取此套接字的任何输入,而在此时间之后,套接字已准备好读取数据?
超时过期是什么意思?
在阻塞操作之前必须启用什么选项?
无限超时意味着套接字不再读取?
【问题讨论】:
【参考方案1】:这是否意味着我在 2000 毫秒内阻止从服务器/客户端读取此套接字的任何输入,而在此时间之后,套接字已准备好读取数据?
不,这意味着如果在 2000 毫秒内没有数据到达,则会抛出 SocketTimeoutException
。
超时过期是什么意思?
这意味着 2000 毫秒(在您的情况下)过去了,没有任何数据到达。
在阻塞操作之前必须启用的选项是什么?
没有一个“必须”启用。如果您的意思是“可能启用”,这就是其中之一。
无限超时意味着套接字不再读取?
多么奇怪的建议。这意味着如果没有数据到达,您将永远阻塞读取。
【讨论】:
不错的答案,尽管套接字 API 没有SO_TIMEOUT
套接字选项。实现并不是那么简单。
错字?并非如此,SO_TIMEOUT
是对特定于操作系统的机制的抽象。在 Unix 系统上,JVM 使用 poll 或 select。在 Windows 上,它使用仅限 Windows 的 SO_RCVTIMEO
套接字选项。
EJP,这个问题是关于 Java 套接字 API 中的SO_TIMEOUT
选项的。如果您研究它是如何实现的(至少在 OpenJDK 中),您会发现 Windows 实现使用 SO_RCVTIMEO
,而 Linux/Solaris 实现使用 poll 或 select 来达到相同的效果。比较hg.openjdk.java.net/jdk7/jdk7-gate/jdk/file/9b8c96f96a0f/src/… 和hg.openjdk.java.net/jdk7/jdk7-gate/jdk/file/9b8c96f96a0f/src/…
@Joni 你是这个名字游戏的发起者,让我们准确地完成它。 Java Socket
API 中没有 'SO_TIMEOUT
选项。有一个Socket.setSoTimeout()
方法,其Javadoc 不准确地引用SO_TIMEOUT
,正如您在第一条评论中正确所说的那样,它不存在。我知道它是如何实施的,我也知道其中的原因。
没有理由必须使用 SO_RCVTIMEO 实现 SO_TIMEOUT。如果您阅读 OpenJDK 7 源代码,您会发现以下注释:SO_TIMEOUT 是用于指定 ServerSocket.accept 和 Socket.getInputStream().read 超时的套接字选项。它通常不映射到本机级别的套接字选项。对于 Windows,我们对此进行特殊处理,并使用 SOL_SOCKET/SO_RCVTIMEO 套接字选项来指定套接字上的接收超时。 在 Linux 和 Solaris 上,它们使用 poll
代替。如果你没有看到讨论 SO_TIMEOUT 是如何实现的意义,你为什么要提出 SO_RCVTIMEO?【参考方案2】:
JavaDoc 解释的很好:
将此选项设置为非零超时,read() 调用 与此 Socket 关联的 InputStream 将仅针对此阻塞 多少时间。如果超时到期,则 引发了 java.net.SocketTimeoutException,尽管 Socket 仍然存在 有效的。必须在进入阻止之前启用该选项 操作才能生效。超时必须 > 0。超时为零 被解释为无限超时。
SO_TIMEOUT
是read()
调用将阻塞的超时时间。如果达到超时,将抛出java.net.SocketTimeoutException。如果您想永久阻塞,将此选项设置为零(默认值),那么read()
调用将阻塞,直到至少可以读取 1 个字节。
【讨论】:
感谢您的回复,但我仍然不知道超时到期是什么意思?这是否意味着预期的时间过去了。例如:mySocket.setSoTimeout(2000); mySocket 会在 2000 毫秒后过期吗?那么除了零的情况外,总是超时会过期吗? 我只是觉得setSoTimeout
被命名为 setSoTimeout
而不是 setSocketTimeout
很奇怪,为什么?
@tom_mai78101 有时会缩短方法以避免长名称。
setSoTimeout()
方法显然是以SO_TIMEOUT
选项命名的。它设置SO_TIMEOUT.
这个值是否仅适用于套接字上没有接收到数据的情况?长期阅读怎么样?仅供参考,我有一个服务电话,我想确保它不会超过 2 秒。这样做是创建一个监视请求的线程的唯一方法吗?【参考方案3】:
这个例子让我明白了一切:
如您所见, setSoTimeout 防止程序挂起!它等待SO_TIMEOUT
时间!如果它没有得到任何信号,它就会抛出异常!这意味着时间已到!
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
public class SocketTest extends Thread
private ServerSocket serverSocket;
public SocketTest() throws IOException
serverSocket = new ServerSocket(8008);
serverSocket.setSoTimeout(10000);
public void run()
while (true)
try
System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
Socket client = serverSocket.accept();
System.out.println("Just connected to " + client.getRemoteSocketAddress());
client.close();
catch (SocketTimeoutException s)
System.out.println("Socket timed out!");
break;
catch (IOException e)
e.printStackTrace();
break;
public static void main(String[] args)
try
Thread t = new SocketTest();
t.start();
catch (IOException e)
e.printStackTrace();
【讨论】:
这正是我在回复中所解释的......无论如何,我很高兴,因为你终于明白了这个套接字选项的目的;.)) 这也正是它在 Javadoc 中所说的。以上是关于setSoTimeout 的功能是啥以及它是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章