无法从套接字的setSoTimeout

时间:2018-02-19 09:24:15

标签: java http

我正在尝试使用HTTP 1.1功能实现基本的Web服务器。服务器的超时时间为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;
      }
    }
  }
}

程序以下列格式读取缓冲的数据包输入:

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

重复读取此输入,直到缓冲输入为空。 因为setSoTimeout嵌套在while循环中,所处理的每个新数据包都会将计时器重置为2000ms。

封装此方法的方法handleClientSocket会抛出SocketTimeoutException,它会被start方法中的try-catch块捕获。

因此,当达到超时时,它应该打印Time's up

我可以连接到网络服务器并获得一个工作页面,但是,在发送请求后约2秒我无法模拟“连接已关闭”。

1 个答案:

答案 0 :(得分:1)

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

无效。您必须首先测试它为null:

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

程序以下列格式读取缓冲的数据包输入:

GET \background.png HTML\1.1

不,它没有。它查找HTTP/1.1,反斜杠应该是HTTP中的正斜杠,所以应该是:

GET /background.png HTTP/1.1

那是你正在测试的内容。

请注意,HTTP中的行分隔符定义为\r\n,而不只是\n

  

重复读取此输入,直到缓冲输入为空。

不,不是。读取空白行,对等体关闭连接或发生读取超时。当缓冲的输入为空时,readLine()不会返回null或空行'。它会阻止。

  

因为setSoTimeout嵌套在while循环中,所处理的每个新数据包都会将计时器重置为2000ms。

不必要的。设置后,超时保持不变。你不需要每次循环都设置它。您应该在循环之前将其设置为。目前,第一次读取时根本没有读取超时。

您也丢弃每个奇数行。这看起来不对。

如果您未从此代码中获取SocketTimeoutExceptions,则每次致电readLine()时,数据都会在超时期限内到达。

否则当你没有读取超时时,你会在第一个readLine()中阻止。

或者你因为第一次错误而得到NullPointerExceptions

编辑或者你根本不在readLine()。你不是。您已处理了一个完整的请求,将其读取到标题的末尾,然后返回到main方法。所以,没有读取超时。我设法通过重构你的接受循环来获得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");
    }