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 关联的 InputStreamread() 调用将仅阻塞这段时间。如果超时到期,则会引发 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_TIMEOUTread() 调用将阻塞的超时时间。如果达到超时,将抛出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 的功能是啥以及它是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

SignInManager,它是啥以及如何使用,何时使用?

Laravel 应用程序密钥 - 它是啥以及它是如何工作的?

Plist:它是啥以及如何使用它

Lambda 解释和它是啥以及一个很好的例子[重复]

工单管理系统流程是啥?

MurmurHash - 它是啥?