You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Apache HttpClient 5.4.2配置自定义套接字工厂实现TLS/非TLS流量DSCP标记的问题咨询

Apache HttpClient 5.4.2配置自定义套接字工厂实现TLS/非TLS流量DSCP标记的问题咨询

大家好,我目前正在尝试给Apache HttpClient发送的数据包配置DSCP标记——也就是在IP头里设置流量类别(Traffic Class)或服务类型(Type-of-Service)字段。之前在旧版本的HttpClient里已经顺利实现了这个功能,但升级到最新版本后遇到了卡点,想请社区的大佬们帮忙看看。

旧版本可行方案(HttpClient 5.3.1 / Core 5.2.4)

在旧版本中,我通过自定义PlainConnectionSocketFactorySSLConnectionSocketFactory的子类来实现DSCP标记,这两个类当时还未被弃用,代码运行完全正常:

HTTP流量的DSCP标记实现

import java.io.IOException;
import java.net.Proxy;
import java.net.Socket;
import java.net.SocketException;

import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
import org.apache.hc.core5.http.protocol.HttpContext;


class CustomDscpPlainConnectionSocketFactory extends PlainConnectionSocketFactory {

    private int dscpValue;

    CustomDscpPlainConnectionSocketFactory(int dscpValue) {
        this.dscpValue = dscpValue;
    }

    @Override
    public Socket createSocket(final HttpContext context) throws IOException {
        Socket socket = super.createSocket(context);
        socket.setTrafficClass(dscpValue << 2);
        return socket;
    }

    @Override
    public Socket createSocket(final Proxy proxy, final HttpContext context) throws IOException {
        Socket socket = super.createSocket(proxy, context);
        socket.setTrafficClass(dscpValue << 2);
        return socket;
    }
}

HTTPS流量的DSCP标记实现

import java.io.IOException;
import java.net.Proxy;
import java.net.Socket;
import java.net.SocketException;

import javax.net.ssl.SSLContext;

import org.apache.hc.client5.http.ssl.HttpsSupport;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.http.protocol.HttpContext;

class CustomDscpSSLConnectionSocketFactory extends SSLConnectionSocketFactory {

    private int dscpValue;

    public CustomDscpSSLConnectionSocketFactory(final int dscpValue,
            final SSLContext sslContext,
            final String[] supportedProtocols) {
        super(sslContext.getSocketFactory(), supportedProtocols,
                getCipherSuites().toArray(String[]::new),
                HttpsSupport.getDefaultHostnameVerifier());
        this.dscpValue = dscpValue;
    }

    public CustomDscpSSLConnectionSocketFactory(SSLContext sslContext) {
        super(sslContext);
    }

    @Override
    public Socket createSocket(HttpContext context) throws IOException {
        Socket socket = super.createSocket(context);
        socket.setTrafficClass(dscpValue << 2);
        return socket;
    }

    @Override
    public Socket createSocket(final Proxy proxy, final HttpContext context) throws IOException {
        Socket socket = super.createSocket(proxy, context);
        socket.setTrafficClass(dscpValue << 2);
        return socket;
    }
}

旧版本HttpClient配置

import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;

var plainSocketFactory = new CustomDscpPlainConnectionSocketFactory(20);
var sslConnSocketFactory =  new CustomDscpSSLConnectionSocketFactory(20, sslContext, getProtocols())
PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
                RegistryBuilder.<ConnectionSocketFactory>create()
                        .register(URIScheme.HTTP.id, plainSocketFactory)
                        .register(URIScheme.HTTPS.id, sslConnSocketFactory)
                        .build());
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create()
                .setRedirectStrategy(DefaultRedirectStrategy.INSTANCE)
                .setConnectionManager(poolingmgr);
CloseableHttpClient httpClient = httpClientBuilder.build();

新版本遇到的问题(HttpClient 5.4.2 / Core 5.3.3)

升级到最新版本后,PlainConnectionSocketFactorySSLConnectionSocketFactory都被弃用了,我需要改用新的API适配:

HTTPS流量的新方案(已成功)

我通过自定义DefaultClientTlsStrategy的子类实现了HTTPS流量的DSCP标记,目前运行正常:

import java.net.Socket;
import java.net.SocketException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;

import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
import org.apache.hc.client5.http.ssl.HttpsSupport;
import org.apache.hc.core5.reactor.ssl.SSLBufferMode;


    public class CustomClientTlsStrategy extends DefaultClientTlsStrategy {
    
        private int dscpValue;
    
        public CustomClientTlsStrategy(final int dscpValue,
                final SSLContext sslContext,
                final String[] supportedProtocols) {
            super(sslContext, supportedProtocols,
                   getCipherSuites().toArray(String[]::new),
                    SSLBufferMode.STATIC, HttpsSupport.getDefaultHostnameVerifier());
            this.dscpValue = dscpValue;
        }
    
        protected void initializeSocket(final SSLSocket socket) {
          socket.setTrafficClass(dscpValue << 2);
        }
    }

HTTP流量的新方案(未生效)

我尝试自定义ManagedHttpClientConnectionFactory来处理HTTP流量,但发现connection.getSocket()总是返回null,导致DSCP标记根本没被设置:

import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;

import org.apache.hc.client5.http.impl.io.ManagedHttpClientConnectionFactory;
import org.apache.hc.client5.http.io.ManagedHttpClientConnection;

    public class CustomManagedHttpClientConnectionFactory extends ManagedHttpClientConnectionFactory {
    
        private int dscpValue;
        public CustomManagedHttpClientConnectionFactory(int dscpValue) {
            super();
            this.dscpValue = dscpValue;
        }
        @Override
        public ManagedHttpClientConnection createConnection(final Socket socket) throws IOException {
            ManagedHttpClientConnection connection = super.createConnection(socket);
            if (connection.getSocket() != null ) { // Socket here is always null and thus DSCP is never marked.
                connection.getSocket().setTrafficClass(dscpValue << 2);
            }
            return connection;
        }
    }

新版本HttpClient配置

CustomManagedHttpClientConnectionFactory customManagedHttpClientConnectionFactory = new CustomManagedHttpClientConnectionFactory(20);
var poolingmgrBuilder = PoolingHttpClientConnectionManagerBuilder.create();
poolingmgrBuilder.setTlsSocketStrategy(buildCustomTlsStrategy());
poolingmgrBuilder.setConnectionFactory(customManagedHttpClientConnectionFactory);

var poolingmgr = poolingmgrBuilder.build();

HttpClientBuilder httpClientBuilder = HttpClientBuilder.create()
                .setRedirectStrategy(DefaultRedirectStrategy.INSTANCE)
                .setConnectionManager(poolingmgr);
CloseableHttpClient httpClient = httpClientBuilder.build();

现在的核心问题就是HTTP流量的DSCP标记怎么都加不上,想请教下大家,在新版本的HttpClient里,应该怎么正确配置HTTP流量的DSCP标记呢?

备注:内容来源于stack exchange,提问作者Venkat

火山引擎 最新活动