简体   繁体   English

无法从套接字的 setSoTimeout 获取 SocketTimeoutException

[英]Unable to get SocketTimeoutException from socket's setSoTimeout

I'm trying to implement a basic webserver with HTTP 1.1 functionality.我正在尝试实现一个具有 HTTP 1.1 功能的基本网络服务器。 The server has a timeout of 2 seconds - if no new packets are requested for 2 seconds, the socket is closed.服务器有 2 秒的超时时间 - 如果 2 秒内没有请求新数据包,则套接字将关闭。

private void start(int port) throws IOException{
  System.out.println("Starting server on port " + port);
  ServerSocket serverSocket = new ServerSocket(port);
  try{
    while(true){
      Socket clientSocket = serverSocket.accept();
      handleClientSocket(clientSocket, serverSocket);
    }
  }catch(SocketTimeoutException e){
    System.out.println("Time's up");
  }
}

/**
 * Handles requests sent by a client
 * @param  client Socket that handles the client connection
 */
private void handleClientSocket(Socket client, ServerSocket server) throws IOException, SocketTimeoutException {

  BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
  String line;

  while((line = in.readLine()) != null && !line.isEmpty()){
    String[] header = line.split(" ");
    if(header[0].equals("GET")){
      switch(header[2]){
        case "HTTP/1.0":
          generate(client, in.readLine(), header);
          System.out.println("close");
          client.close();
        break;
        case "HTTP/1.1":
          generate(client, in.readLine(), header);
          client.setSoTimeout(2000); 
        break;
        default:
          System.out.println("This is not suppose to happen.");
        break;
      }
    }
  }
}

The program reads a buffered input of packets in the following format:该程序以以下格式读取数据包的缓冲输入:

GET \background.png HTML\1.1
Host: localhost:8000

This input is repeatedly read till the buffered input is empty.重复读取此输入,直到缓冲的输入为空。 Because the setSoTimeout is nested in the while loop, every new packet processed will reset the timer to 2000ms.因为setSoTimeout嵌套在 while 循环中,所以每个处理的新数据包都会将计时器重置为 2000 毫秒。

The method encapsulating this, handleClientSocket , throws a SocketTimeoutException , which is caught by the try-catch block from the start method.封装它的方法handleClientSocket抛出一个SocketTimeoutException ,它被start方法的 try-catch 块捕获。

Hence, when the timeout is reached it should print Time's up .因此,当达到超时时,它应该打印Time's up

I am able to connect to the webserver and get a working page, however, I am not able to simulate the "connection closed" ~ 2 seconds after the request is sent.我能够连接到网络服务器并获得一个工作页面,但是,我无法在请求发送后 2 秒模拟“连接关闭”。

 while(!(line = in.readLine()).isEmpty()){

Invalid.无效的。 You must test it for null first:您必须先测试它是否为空:

 while((line = in.readLine()) != null && !line.isEmpty()){

The program reads a buffered input of packets in the following format:该程序以以下格式读取数据包的缓冲输入:

GET \background.png HTML\1.1

No it doesn't.不,它没有。 It looks for HTTP/1.1 , and the backslashes should be forward slashes in HTTP, so it should be:它寻找HTTP/1.1 ,反斜杠应该是 HTTP 中的正斜杠,所以它应该是:

GET /background.png HTTP/1.1

That's what you're testing for.这就是你要测试的。

And note that the line separator in HTTP is defined as \\r\\n , not just \\n .请注意,HTTP 中的行分隔符定义为\\r\\n ,而不仅仅是\\n

This input is repeatedly read till the buffered input is empty.重复读取此输入,直到缓冲的输入为空。

No it isn't.不,不是。 It is read until a blank line is read, the peer closes the connection, or a read timeout occurs.它一直被读取,直到读取到一个空行、对等方关闭连接或发生读取超时。 readLine() does not return null, or an empty line, when 'the buffered input is empty'.当“缓冲输入为空”时, readLine()不会返回 null 或空行。 It blocks.它阻塞。

Because the setSoTimeout is nested in the while loop, every new packet processed will reset the timer to 2000ms.因为 setSoTimeout 嵌套在 while 循环中,所以每个处理的新数据包都会将计时器重置为 2000 毫秒。

Unnecessary.不必要。 Once set, the timeout stays set.一旦设置,超时将保持设置。 You don't need to set it every time around the loop.您不需要每次都在循环中设置它。 You should set it before the loop.您应该在循环之前设置它。 At present there is no read timeout at all on the first read.目前,第一次读取根本没有读取超时。

You are also discarding every odd-numbered line.您还丢弃了每条奇数行。 This doesn't seem right.这似乎不对。

If you aren't getting SocketTimeoutExceptions from this code, data is arriving within the timeout period every time you call readLine() .如果您没有从此代码中获得SocketTimeoutExceptions ,则每次调用readLine()时,数据都会在超时时间内到达。

Or else you are blocking in the first readLine() , when there is no read timeout yet.否则,当还没有读取超时时,您会在第一个readLine()中阻塞。

Or else you are getting NullPointerExceptions because of the first error.否则你会因为第一个错误而得到NullPointerExceptions

EDIT Or else you aren't in readLine() at all.编辑否则你根本不在readLine()中。 You aren't.你不是。 You have handled one entire request, read it to the end of the headers, and then returned to the main method.你已经处理了一个完整的请求,把它读到头的末尾,然后返回到 main 方法。 So, no read timeout.所以,没有读取超时。 I managed to get a SocketTimeoutException by restructuring your accept loop as follows:我通过按如下方式重构您的接受循环设法获得了SocketTimeoutException

    while (true)
    {
        try (Socket clientSocket = serverSocket.accept())
        {
            System.out.println("accepted " + clientSocket);
            for (;;)
            {
                handleClientSocket(clientSocket, serverSocket);
            }
        }
        catch (SocketTimeoutException e)
        {
            System.out.println("Time's up");
        }
        System.out.println("request handling ended");
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM