当前位置: 首页 > 面试题库 >

使用Java中的套接字的HTTP 1.1持久连接

卞嘉许
2023-03-14
问题内容

假设我有一个Java程序,该程序使用HTTP
1.1在服务器上发出HTTP请求,并且不关闭连接。我提出一个请求,并读取从绑定到套接字的输入流返回的所有数据。但是,在发出第二个请求时,服务器没有响应(或者流有问题-
它不再提供任何输入)。如果我按顺序发出请求(请求,请求,读取),则可以正常工作,但(请求,读取,请求,读取)则不能。

有人能解释为什么会发生这种情况吗?(代码片段如下)。无论我做什么,第二个读取循环的isr_reader.read()都只会返回-1。

try{
        connection = new Socket("SomeServer", port);
        con_out = connection.getOutputStream();
        con_in  = connection.getInputStream();
        PrintWriter out_writer = new PrintWriter(con_out, false);
        out_writer.print("GET http://somesite HTTP/1.1\r\n");
        out_writer.print("Host: thehost\r\n");
        //out_writer.print("Content-Length: 0\r\n");
        out_writer.print("\r\n");
        out_writer.flush();

        // If we were not interpreting this data as a character stream, we might need to adjust byte ordering here.
        InputStreamReader isr_reader = new InputStreamReader(con_in);
        char[] streamBuf = new char[8192];
        int amountRead;
        StringBuilder receivedData = new StringBuilder();
        while((amountRead = isr_reader.read(streamBuf)) > 0){
            receivedData.append(streamBuf, 0, amountRead);
        }

// Response is processed here.

        if(connection != null && !connection.isClosed()){
            //System.out.println("Connection Still Open...");

        out_writer.print("GET http://someSite2\r\n");
        out_writer.print("Host: somehost\r\n");
        out_writer.print("Connection: close\r\n");
        out_writer.print("\r\n");
        out_writer.flush();

        streamBuf = new char[8192];
        amountRead = 0;
        receivedData.setLength(0);
        while((amountRead = isr_reader.read(streamBuf)) > 0 || amountRead < 1){
            if (amountRead > 0)
                receivedData.append(streamBuf, 0, amountRead);
        }
}
        // Process response here
    }

对问题的回答:是的,我收到来自服务器的分块响应。由于外部限制,我正在使用原始套接字。

为乱七八糟的代码表示歉意-我正在从内存中重写它,似乎引入了一些错误。

因此,共识是我必须执行一次(请求,读取,请求,读取)并让服务器关闭流,或者如果我这样做了(请求,读取,请求,读取),则必须在到达末尾之前停止流,以便
关闭流。


问题答案:

根据您的代码,只有在服务器收到/响应第一个请求后关闭输出流(您的输入流)时,您甚至到达处理发送第二个请求的语句的唯一时间。

这样做的原因是您的代码应该只读取第一个响应

while((amountRead = isr_reader.read(streamBuf)) > 0) {
  receivedData.append(streamBuf, 0, amountRead);
}

将阻塞直到服务器关闭输出流(即,当readreturn
-1)或套接字上的读取超时时间结束。在读取超时的情况下,将引发异常,您甚至无法发送第二个请求。

HTTP响应的问题在于它们直到响应结束时才告诉您要从流中读取多少字节。对于HTTP
1.0响应而言,这并不是什么大问题,因为服务器只是在响应之后关闭连接,从而使您能够通过简单地读取所有内容直到流的末尾来获取响应(状态行+标头+正文)。

使用HTTP 1.1持久连接,您将无法再简单地读取所有内容,直到流结束。您首先需要逐行读取状态行和标头,然后根据状态码和标头(例如Content-
Length)确定要读取多少字节以获得响应主体(如果存在于此处)所有)。如果正确执行上述操作,则在关闭连接或发生超时之前,您的读取操作将完成,并且您将完全读取服务器发送的响应。这将使您能够发送下一个请求,然后以与第一个请求完全相同的方式读取第二个响应。

PS请求,请求,读取可能在服务器支持请求流水线的意义上是“有效的”,因此可以接收和处理这两个请求,因此,您将这两个响应都读入一个缓冲区作为“第一个”响应。

PPS确保您PrintWriter正在使用US-ASCII编码。否则,根据您的系统编码,HTTP请求的请求行和标头可能格式错误(编码错误)。



 类似资料:
  • 我正在将堆栈转换为K8S。数据库需要持久存储。 我使用了 pv.yaml(根据@Whites11的回答进行了编辑): 我进入GUI上的PVC页面,并手动向索赔添加了一个卷(基于@Whites11的反馈)。我可以看到PVC已经更新了体积,但它仍然悬而未决。 意识到自从进行@Whites11建议的更改后,pod中的原始错误消息已经更改。现在是“persistentvolume”pvvolume“not

  • 问题内容: 简而言之,是否有一些适合高使用率和服务器的产品,还是我需要坚持不懈地改进?如果是这样,为什么他们将其删除? 问题答案: PHP 5.3中引入了对此的支持。对于此之前的版本,PDO和–上帝禁止– mysql扩展是唯一的选择。 引用手册: 与mysql扩展不同,mysqli不提供单独的功能来打开持久连接。要打开持久连接,连接时必须在主机名前加p:。

  • “持久连接”特性允许利用一个单独的网络连接来运行本来需要多个连接的多个命令。 6.8.1.Open (打开连接) 原型:function Open () 打开到服务器的持久连接。 6.8.2.Close (关闭连接) 原型:function Close () 关闭先前打开的持久连接。

  • 问题内容: 我正在加密服务器和客户端之间的TCP连接。在研究和测试过程中,我倾向于使用秘密密钥加密。我的问题是我找不到有关如何实现此功能的任何教程。我发现的教程围绕一次HTTP请求进行,我只需要一个SSL套接字。 我到目前为止编写的代码如下。我几乎可以肯定它需要扩展,我只是不知道该怎么做。任何帮助表示赞赏。 接受客户端连接的服务器代码 我只是不知道如何实际进行握手。 参考:http : //doc

  • 这很好,但没有SSL。 我已经使用OpenSSL为服务器和客户机生成了SSL证书,结果是: 服务器的证书(PEM格式) 客户端的证书(PEM格式) 服务器的私钥(PEM格式) 客户端的私钥(PEM格式) CA文件(PEM、CER和CRT格式) null 会出什么问题?

  • 问题内容: 我有一个使用JDBC连接到MySQL的应用程序。在某些情况下,JDBC连接空闲数小时(甚至几天),并且失去与MySQL的连接,然后尝试执行查询时除外。最好的解决方案是什么? 问题答案: 保持连接打开时间不足是一个坏习惯。当数据库打开时间过长时,它将强制关闭。您应该编写JDBC代码,以便它总是在您获取它们的同一块块中关闭连接(以及语句和结果集),以防止这样的资源泄漏。 但是,获取每个连接