【问题标题】:Stop Socket with timeout from waiting after data read from socket从套接字读取数据后等待超时停止套接字
【发布时间】:2017-01-17 05:04:55
【问题描述】:

我正在尝试使用 tcp 套接字创建一个 java http 服务器。 HTTP 1.1 有一个超时值,该值将使连接保持持久并等待一小段时间以获取来自客户端的可能数据。我正在尝试使用:clientSocket.setSoTimeout() 在我的程序中实现这个计时器。尽管这有助于使连接保持打开一段时间,但它会在允许读取下一个请求之前等待确切的时间。

例如:

如果超时设置为 5 秒,

请求 1 被读取。然后套接字挂起,等待 5 秒结束。
读取请求 2。套接字等待 5 秒后再次启动。

如果我的超时设置为较大的值,这被证明是一个问题。不应出现这种情况,因为一旦收到请求就应该对其进行处理,并且只有在指定的持续时间内没有收到任何数据时才会超时。

谁能告诉我如何解决这个问题?

编辑:

对于面临类似问题的人,这是我的解决方案:

由于客户端一直等到超时才接收到所有数据,所以我猜测客户端并不知道服务器的所有数据都已接收完毕。因此,我在 HTTP 响应数据包中添加了一个内容长度字段。现在,我的客户端在收到数据后不再挂起。 setSoTimeout 确实按说明工作!

【问题讨论】:

  • 你能展示一些你的代码吗?也许是接受客户的部分?
  • 我只用了一行来接受客户端:client = server.accept(); 放在while(true) 循环中不断监听连接。
  • 当然可以,但是接下来会发生什么?我怀疑,您错过了将处理客户端的任务传递给另一个线程,但是如果没有看到任何代码,就很难说出确切的问题出在哪里。这就是他们在帮助中心谈论“最小、完整和可验证的示例”的原因。 stackoverflow.com/help/mcve
  • 我的服务器没有使用任何多线程。是否可以在没有多线程的情况下进行超时?
  • '持久连接'并不意味着'服务器将通过相同的连接发送响应'。在 HTTP 中总是如此。这意味着客户端可以通过同一连接发送更多请求。 HTTP 不“做”任何事情。实现就是这样做的。你正在实施它:你去做。您需要比目前在此项目中获得的任何地方更好的 HTTP 知识。

标签: java sockets http network-programming socket-timeout-exception


【解决方案1】:

HTTP 1.1 有一个超时值,该值将使连接保持持久并等待一小段时间以获取来自客户端的可能数据。

不是真的。它有一个 connection: keep-alive 设置,这是默认行为,它允许端点在空闲一段时间后关闭未使用的连接,但它本身没有超时属性。

我正在尝试通过使用:clientSocket.setSoTimeout() 在我的程序中实现此计时器。

这与 HTTP 没有任何关系。这是一个套接字读取超时。

尽管这有助于让连接保持打开一段时间,但它会在允许读取下一个请求之前等待确切的时间。

不,不会的。如果在超时期限内没有数据到达,它将导致读取方法抛出SocketTimeoutException。没有别的了。

例如:

如果超时设置为 5 秒,

请求 1 被读取。然后socket挂起,等待5秒结束。

没有。

请求 2 被读取。套接字等待 5 秒后再次启动。

不,它没有。这一切都是你编造的。这是幻想。

如果我的超时设置为较大的值,这将是一个问题。

任何超时值无论大小都不是问题,因为它根本不会发生。

这不应该是这种情况,因为一旦收到请求就应该处理它,并且只有在指定的持续时间内没有收到任何数据时才应该超时。

这正是Socket.setSoTimeout() 已经在做的事情。

你的问题是建立在一个谬误之上的。

【讨论】:

  • 如果我将超时设置为一个较大的值,我观察到在发送下一个请求之前会有很长的延迟。
  • 每读取一个请求,socket 就会抛出超时异常。然后客户端必须建立一个新连接才能下载下一个文件。这还不足以证明我的观点吗?
  • 套接字在读取下一个请求时抛出超时异常。不是'在读取每个请求之后'。套接字不只是自发地“挂起,直到 5 秒结束”。下一个请求之前的延迟意味着客户端没有在超时期限内发送一个,所以你得到了一个读取超时,所以你得到了一个SocketTimeoutException,正如我上面所说的。因此,您刚刚正确实施的是服务器端连接空闲超时。我不知道这应该证明你的什么观点,但事实并非如此,或者你的问题包含什么,如果有的话。
  • 这如何解释当我将超时时间增加到 20 秒时,响应时间会有更多延迟?例如。在这种情况下,我的浏览器需要很长时间才能加载网页和对象。
  • @LanceHAOH 在没有发布代码的情况下尝试讨论代码的行为是完全毫无意义的。
【解决方案2】:

好的,当您收到连接时,请像这样启动一个新线程:

class ClientService extends Thread {

    private final Socket clientSocket;

    public ClientService(Socket clientSocket) {
      this.clientSocket=clientSocket;
    }

    public void run() {
      // do your work with the Socket clientSocket here
    }

}

你的服务器代码应该是这样的:

while (true) {
    Socket clientSocket = server.accept();
    new ClientService(clientSocket).start();
}

它将允许您处理响应而无需等待另一个直到超时。

【讨论】:

  • 我正在处理一个仅具有单个持久连接的客户端。所以应该不需要多线程吧?
  • 简单回答:不。即使使用单个客户端,您的连接也可以挂起直到超时,如果您希望客户端能够在不等待前一个连接完成的情况下创建另一个连接,那么您需要多线程。在很多情况下,客户端可以断开连接并立即尝试重新连接,如果没有多线程,它需要等到之前的“死”连接超时并让另一个连接被处理。
  • 如果我使用setSoTimeout(),socket收到数据后会立即停止等待吗?
  • @LanceHAOH 当然会。这是一个超时。超时内数据到达 => 没有超时。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-13
  • 2017-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多