【问题标题】:While reading from socket how to detect when the client is done sending the request?从套接字读取时如何检测客户端何时完成发送请求?
【发布时间】:2012-11-01 11:02:07
【问题描述】:

我现在正在编写一个 http 服务器,但我在从套接字读取时遇到了问题。 我的问题是来自客户端的inputStream 永远不会结束,它会一直读取直到客户端关闭。 我知道客户端在发送 http 请求后并没有立即关闭与服务器的连接。 当客户端发送所有请求数据(即标头+正文)时,我如何退出while loop

while (in.hasNextLine()) {
    String line = in.nextLine();

    if (line.equals("")){ // last line of request header is blank
        break; // quit while loop when last line of header is reached
    } else {
        request = request + line + "\n";
    }
}

在阅读了cmets和你们的回答后,这就是我想出的,

     is = incoming.getInputStream();
            os = incoming.getOutputStream();
            in = new Scanner(is);
            out = new DataOutputStream(os);

            RequestHandler rh = new RequestHandler();
            int length = 0;
            while (in.hasNextLine()) {
                String line = in.nextLine();
                if (line.equals("")) { // last line of request message
                                        // header is a
                                        // blank line
                    break; // quit while loop when last line of header is
                            // reached
                }

                if (line.startsWith("Content-Length: ")) { // get the
                                                            // content-length
                    int index = line.indexOf(':') + 1;
                    String len = line.substring(index).trim();
                    length = Integer.parseInt(len);
                }

                request = request + line + "\n";
            }

             byte[] body = new byte[length];
             int i = 0;
             while (i < length) {
             byte b = in.nextByte();
             body[i] = b;
             i++;
             }

但是,我仍然不明白按字节读取。我可以编写我的代码来读取直到 -1,但是当没有 EOF 并且客户端没有关闭连接时仍然卡住。

【问题讨论】:

  • 如果是GET,则在得到\r\n\r\n后停止,如果有请求体,则在从请求体中读取Content-Length字节后停止。
  • Scanner.nextByte() 根据现行基数进行解析;它不返回原始字节。您应该为此使用DataInputStream。是的,我知道它的 readLine() 方法已被弃用。

标签: java sockets httprequest httpserver


【解决方案1】:

根据您正在处理的请求,有 3 种方法可以检测流的结束:

  1. 如果是GET或者HEAD请求,只需要读取HTTP头,如果存在请求体一般会被忽略,所以当遇到\r\n\r\n时,就到达了请求的末尾(实际上是请求标头)。
  2. 如果是POST方法,则读取头部中的Content-Length,最多读取Content-Length字节。
  3. 如果是POST方法且Content-Length头不存在,这种情况最有可能发生,读取直到返回-1,也就是EOF的信号。

【讨论】:

  • 省略 (1) 并仅使用 (2) 和 (3),对于所有方法,包括 GET、HEAD、PUT、POST、DELETE,... 如果客户端正在执行 keepalive,则您必须读到所有请求的末尾,否则你将无法正确获得下一个。
  • 嗨,@EJP,感谢您提及keepalive。如果Content-Length不存在,如果客户端在做keepalive,我如何检测请求的结束?
  • 这不是合法的情况。如果客户端正在进行保持活动,他必须发送一个内容长度,正如您在 (3) 中所说的那样。
  • 大多数非GET/HEAD 请求可以有消息体,因此将#2 和#3 限制为POST 是错误的。此外,“如果客户端正在进行保持活动,他必须发送内容长度”也不正确。如果使用Transfer-Encoding: chunkedContent-Type: multipart/...Content-Length 是可选的。并且阅读直到EOF 对请求无效,仅对响应有效。请参阅RFC 2616 Section 4.4 "Message Length",了解在所有情况下检测消息结束时需要遵循的确切规则,无论是否使用保持活动。
【解决方案2】:

我知道了:)谢谢你们的cmets和答案......

     is = incoming.getInputStream(); // initiating inputStream
            os = incoming.getOutputStream(); // initiating outputStream

            in = new BufferedReader(new InputStreamReader(is)); // initiating
                                                                // bufferReader
            out = new DataOutputStream(os); // initiating DataOutputSteream

            RequestHandler rh = new RequestHandler(); // create a
                                                        // requestHandler
                                                        // object

            String line;
            while ((line = in.readLine()) != null) {
                if (line.equals("")) { // last line of request message
                                        // header is a
                                        // blank line (\r\n\r\n)
                    break; // quit while loop when last line of header is
                            // reached
                }

                // checking line if it has information about Content-Length
                // weather it has message body or not
                if (line.startsWith("Content-Length: ")) { // get the
                                                            // content-length
                    int index = line.indexOf(':') + 1;
                    String len = line.substring(index).trim();
                    length = Integer.parseInt(len);
                }

                request.append(line + "\n"); // append the request
            } // end of while to read headers

            // if there is Message body, go in to this loop
            if (length > 0) {
                int read;
                while ((read = in.read()) != -1) {
                    body.append((char) read);
                    if (body.length() == length)
                        break;
                }
            }

            request.append(body); // adding the body to request

【讨论】:

    【解决方案3】:

    我想分享我运行良好的代码:

    private static String getClientRequest(Socket client) throws IOException, SocketException {
        System.out.println("Debug: got new client " + client.toString());
        BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));
    
        StringBuilder requestBuilder = new StringBuilder();
        String line;
        int contectLegnth = 0;
        
        while (!(line = br.readLine()).isBlank()) {
            requestBuilder.append(line + "\r\n");
            if (line.toLowerCase().startsWith("content-length")) {
                contectLegnth = Integer.parseInt(line.split(":")[1].trim());
            }
        }
        
    
        StringBuilder requestBodyBuilder = new StringBuilder();
        if (contectLegnth > 0) {
            int read;
            while ((read = br.read()) != -1) {
                requestBodyBuilder.append((char) read);
                if (requestBodyBuilder.length() == contectLegnth)
                    break;
            }
            requestBuilder.append("\r\n" + requestBodyBuilder);
        }
       
        return requestBuilder.toString();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-06
      • 2015-04-28
      • 1970-01-01
      • 1970-01-01
      • 2017-01-23
      • 1970-01-01
      相关资源
      最近更新 更多