我有一个小项目,将涉及Java应用程序和FlaskWeb服务器之间的重复HTTPS通信,使保持TCP连接活跃是重要的.为了测试和理解这些技术的功能,我设置了一个简单的GET请求生成器,它向我的简单的FlaskWeb服务器应用程序发送多个带有时间倒数的GET请求并返回响应.在这样的设置中,我希望缓存TCP连接,但我认为我的FlaskTM应用程序在每次响应后都会断开连接.请注意,我对Java相当生疏,而且这是我第一次熟悉Flask.

我的Java GET请求生成器如下所示:

package com.deu;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class Main {

    public static void main(String[] args) {
        try {
            sendHttpRequests("http://127.0.0.1:5000", 1000, 5);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void sendHttpRequests(String url, int interval, int count) throws IOException, InterruptedException {
        URL hostURL = new URL(url);

        for (int i = 0; i < count; i++) {
            HttpURLConnection httpConn = (HttpURLConnection) hostURL.openConnection();
            httpConn.setRequestMethod("GET");

            BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));
            StringBuilder response = new StringBuilder();
            String line;

            while ((line = reader.readLine()) != null)
                response.append(line);

            System.out.println("Response to i="+i+" "+response.toString());
            reader.close();

            Thread.sleep(interval);
        }
    }

}

我的FlaskWeb服务器应用程序如下所示:

import flask
from flask import Flask, request
from werkzeug.serving import WSGIRequestHandler

app = Flask(__name__)


@app.route('/', methods=['GET'])
def hello_world():
    resp = flask.Response("Hello World!")
    print(request.headers)
    print(resp.headers)

    return resp


if __name__ == '__main__':
    WSGIRequestHandler.protocol_version = "HTTP/1.1"
    app.run()

在Java应用程序终止后,我分别为Java和FlaskTM应用程序获得的输出是:

Response to i=0 Hello World!
Response to i=1 Hello World!
Response to i=2 Hello World!
Response to i=3 Hello World!
Response to i=4 Hello World!
FLASK_APP = app.py
FLASK_ENV = development
FLASK_DEBUG = 0
In folder B:/Development/Projects/Python/ProjectABC
B:\Development\Projects\Python\ProjectABC\venv\Scripts\python.exe -m flask run
 * Serving Flask app 'app.py'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
User-Agent: Java/17.0.1
Host: 127.0.0.1:5000
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive


Content-Type: text/html; charset=utf-8
Content-Length: 12


127.0.0.1 - - [08/Apr/2023 01:26:28] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [08/Apr/2023 01:26:29] "GET / HTTP/1.1" 200 -
User-Agent: Java/17.0.1
Host: 127.0.0.1:5000
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive


Content-Type: text/html; charset=utf-8
Content-Length: 12


User-Agent: Java/17.0.1
Host: 127.0.0.1:5000
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive


Content-Type: text/html; charset=utf-8
Content-Length: 12


127.0.0.1 - - [08/Apr/2023 01:26:30] "GET / HTTP/1.1" 200 -
User-Agent: Java/17.0.1
Host: 127.0.0.1:5000
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive


Content-Type: text/html; charset=utf-8
Content-Length: 12


127.0.0.1 - - [08/Apr/2023 01:26:31] "GET / HTTP/1.1" 200 -
User-Agent: Java/17.0.1
Host: 127.0.0.1:5000
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive


Content-Type: text/html; charset=utf-8
Content-Length: 12


127.0.0.1 - - [08/Apr/2023 01:26:32] "GET / HTTP/1.1" 200 -

可以看到,请求接收到的响应与预期一致,甚至连接收到的请求标头FlaskTM应用程序都显示为Connection: keep-alive.但我认为每次都会创建一个新的TCP连接的原因是,响应头不包含Connection: keep-alivenetstat cmd命令的输出:

Active Connections

  Proto  Local Address          Foreign Address        State
  TCP    127.0.0.1:5000         DESKTOP-XXXXXXX:52821  TIME_WAIT
  TCP    127.0.0.1:5000         DESKTOP-XXXXXXX:52823  TIME_WAIT
  TCP    127.0.0.1:5000         DESKTOP-XXXXXXX:52824  TIME_WAIT
  TCP    127.0.0.1:5000         DESKTOP-XXXXXXX:52830  TIME_WAIT
  TCP    127.0.0.1:5000         DESKTOP-XXXXXXX:52831  TIME_WAIT

如果我对输出的理解是正确的(如果我错了,请纠正我),建立了5个不同的TCP连接,现在操作系统正在等待清除它们,表明keep-alive个失败.我在其他问题上搜索答案,试着回答WSGIRequestHandler.protocol_version = "HTTP/1.1",但无济于事.

注意:我正在try 先使用HTTP实现持久连接,然后再将其应用于HTTPS.

推荐答案

我一直在try 使用WSGI服务器来实现持久连接,Flask随附了名为Werkzeug的服务器.当我切换到部署WSGI服务器(在我的例子中是服务员)时,keep-alive开始工作,并且不再断开TCP连接.这个问题是由Werkzeug实施中的变化引起的.他们在2022-04-28发布的Version 2.1.2的更改日志(log)中写道:

禁用开发服务器中的Keep-Alive连接,这是Pythonhttp.server不够支持的.#2397

Werkzeug团队删除了持久连接支持,因为它扩展了http.server的缺点.虽然keep-alive功能的缺失在开发环境中可能不是必不可少的,这是可以理解的,但令人沮丧的是,互联网上关于这一点的交流很少,甚至没有.

Java相关问答推荐

如何让TaskView总是添加特定的列来进行排序?

当一个链表中间有一个循环时,它的松散部分会发生什么?

在Java中将Charsequence数组更改为String数组或List String<>

如何在访问完所有文件后加入所有线程?

Spring Batch 5-不要让它在数据库中自动创建表

Java .类参数不通过构造函数传递

SpringBoot+Java 17@Valid未验证POJO

如何解释Java中for-each循环中对Iterable的强制转换方法引用?

对字符串长度进行排序,但颠倒了顺序(最长字符串在前)

Tinylog中的滚动文件会在每次应用启动时覆盖日志(log)文件

如何从日志(log)行中删除包名称?

如何在不删除Java中已有内容的情况下覆盖文件内容?

基于配置switch 的@Controller的条件摄取

如何生成指定范围内的11位序列号?

如何处理两个几乎相同的XSD文件?

Java 17与Java 8双重表示法

如何使用Rascal Evaluator从编译的JAR访问Rascal函数?

多线程、并发和睡眠未按预期工作

如何在单元测试中获得我的装饰Mapstruct映射器的实例?

语句打印在错误的行(Java Token 问题)