1

多くの研究開発とグーグル検索の後、問題をトラブルシューティングできませんでした。

環境設定

Web サーバー (Tomcat 6.0.20) --> プロキシ サーバー (Windows Server 2007) --> サード パーティのホスト

オンライン決済取引を行うアプリケーションがあり、この取引の完了後、取引のステータスをサードパーティのサーバーに送信したいと考えています。したがって、Web サーバーからサード パーティのサーバーにデータを送信すると、プロキシ サーバーでは 1 つのトランザクションに対して 2 つのソケットが開かれますが、Web サーバーで確認すると、ソケットは 1 つしか作成されていません。SO なぜプロキシ サーバーで 2 ソケット。

以下は私のサンプルコードです

import javax.net.ssl.*;
import javax.net.SocketFactory;
import java.net.*;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.Hashtable;
import java.math.BigInteger;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.protocol.*;


public class HTTPPostDemo {

    private String privateKey;
    private String host;
    private int port;
    private String userName;
    private Header[] headers = null;

    public class MySSLSocketFactory implements SecureProtocolSocketFactory {

        private TrustManager[] getTrustManager() {
            TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                    public void checkClientTrusted(
                            java.security.cert.X509Certificate[] certs, String authType) {
                    }
                    public void checkServerTrusted(
                            java.security.cert.X509Certificate[] certs, String authType) {
                    }
                }
            };
            return trustAllCerts;
        }

        public Socket createSocket(String host, int port) throws IOException, UnknownHostException {

            TrustManager[] trustAllCerts = getTrustManager();
            try {
                SSLContext sc = SSLContext.getInstance("SSL");
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
                HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
                SocketFactory socketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
                return socketFactory.createSocket(host, port);
            } catch (Exception ex) {
                throw new UnknownHostException("Problems to connect " + host + ex.toString());
            }
        }

        public Socket createSocket(Socket socket, String host, int port, boolean flag) throws IOException, UnknownHostException {
            TrustManager[] trustAllCerts = getTrustManager();
            try {

                SSLContext sc = SSLContext.getInstance("SSL");
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
                HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
                SocketFactory socketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
                return socketFactory.createSocket(host, port);
            } catch (Exception ex) {
                throw new UnknownHostException("Problems to connect " + host + ex.toString());
            }

        }

        public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException, UnknownHostException {

            TrustManager[] trustAllCerts = getTrustManager();
            try {
                SSLContext sc = SSLContext.getInstance("SSL");
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
                HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
                SocketFactory socketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
                return socketFactory.createSocket(host, port, clientHost, clientPort);
            } catch (Exception ex) {
                throw new UnknownHostException("Problems to connect " + host + ex.toString());
            }

        }
    }

    public SslClient(String host, int port, String userName, String privateKey) {
        this.host = host;
        this.port = port;
        this.userName = userName;
        this.privateKey = privateKey;
    }

    protected String md5Sum(String str) {
        String sum = new String();
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            sum = String.format("%032x", new BigInteger(1, md5.digest(str.getBytes())));
        } catch (Exception ex) {
        }
        return sum;

    }

    public String getSignature(String xml) {
        return md5Sum(md5Sum(xml + privateKey) + privateKey);
    }

    public String sendRequest(String xml) throws Exception {

        HttpClient client = new HttpClient();
        client.setConnectionTimeout(60000);
        client.setTimeout(60000);
        String response = new String();
        String portStr = String.valueOf(port);
        Protocol.registerProtocol("https", new Protocol("https", new MySSLSocketFactory(), port));
        String signature = getSignature(xml);
        String uri = "https://" + host + ":" + portStr + "/";
        PostMethod postRequest = new PostMethod(uri);
        postRequest.addRequestHeader("Content-Length", String.valueOf(xml.length()));
        postRequest.addRequestHeader("Content-Type", "text/xml");
        postRequest.addRequestHeader("X-Signature", signature);
        postRequest.addRequestHeader("X-Username", userName);
        postRequest.setRequestBody(xml);
        System.out.println("Sending https request....." + postRequest.toString());

        try {
            client.executeMethod(postRequest);
        } catch (Exception ex) {
            throw new TaskExecuteException("Sending post got exception ", ex);
        }

        response = postRequest.getResponseBodyAsString();
        headers = postRequest.getRequestHeaders();
        return response;
    }

    public String getPrivateKey() {
        return privateKey;
    }

    public void setPrivateKey(String privateKey) {
        this.privateKey = privateKey;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Header[] getHeaders() {
        return headers;
    }

    public void setHeaders(Header[] headers) {
        this.headers = headers;
    }

    public static void main(String[] args) {

        String privateKey = "your_private_key";
        String userName = "your_user_name";
        String host = "demo.site.net";
        int port = 55443;

        String xml =
                "<?xml version='1.0' encoding='UTF-8' standalone='no' ?>"
                + "<!DOCTYPE OPS_envelope SYSTEM 'ops.dtd'>"
                + "<OPS_envelope>"
                + "<header>"
                + "<version>0.9</version>"
                + "<msg_id>2.21765911726198</msg_id>"
                + "<msg_type>standard</msg_type>"
                + "</header>"
                + "<body>"
                + "<data_block>"
                + "<dt_assoc>"
                + "<item key='attributes'>"
                + "<dt_assoc>"
                + "<item key='domain'>test-1061911771844.com</item>"
                + "<item key='pre-reg'>0</item>"
                + "</dt_assoc>"
                + "</item>"
                + "<item key='object'>DOMAIN</item>"
                + "<item key='action'>LOOKUP</item>"
                + "<item key='protocol'>XCP</item>"
                + "</dt_assoc>"
                + "</data_block>"
                + "</body>"
                + "</OPS_envelope>";

        SslClient sslclient = new SslClient(host, port, userName, privateKey);

        try {
            String response = sslclient.sendRequest(xml);
            System.out.println("\nResponse is:\n" + response);
        } catch (Exception e) {
            e.printStackTrace();

        }

    }
}

1 日で 10,000 以上のトランザクションを処理しているため、プロキシのソケット数が増加しているため、2 ~ 3 日後に Web サーバーをハード リブートして、プロキシ サーバーで開いているすべてのソケットを解放する必要があります。

HTTPClient は、SSL ハンドシェイク用に 1 つのソケットを開き、実際のデータ ポスト用に別のソケットを開きますか? 私はそうは思わない。次に、プロキシサーバーではなくWebサーバーにある必要があります

Web サーバーでソケットと開いているポートを確認するには、netstat コマンドを使用します。プロキシ サーバーでソケットと開いているポートをチェックするために、プロキシ ツールを使用しています。

4

2 に答える 2

0

ソケット ポートが不足すると、トランザクション タイムアウトが発生します。この問題の解決策は、TIMEWAIT 関連の Windows レジストリ パラメータを調整することです。

  • TcpTimedWaitDelay

  • MaxUserPort

  • StrictTimeWaitSeqCheck

TIMEWAIT 関連の Windows レジストリ パラメータは、ソケット ポートが閉じられた後、ソケット ポートが使用できない期間と、使用可能なポートの数を制御します。

これらの Windows レジストリ パラメータを設定することで、この問題は解決しましたが、実装するのが正しい解決策であるかどうかはわかりません。

于 2012-07-31T13:02:09.970 に答える
0

Web サーバーで確認すると、ソケットが 1 つしか作成されていません。

受信接続が 1 つしかないためです。

SO なぜプロキシ サーバーで 2 ソケット。

プロキシ サーバー経由で 2 つの異なるサーバーに接続しているためですか?

プロキシのソケット数が増えているため、2 ~ 3 日後に Web サーバーをハード リブートして、プロキシ サーバーで開いているすべてのソケットを解放する必要があります。

それは意味がありません。Web サーバーではなく、二重接続を持つのはプロキシ サーバーです。あなたは上でそれを言った。Web サーバーのソケットが不足している場合は、クライアント、プロキシ サーバー、または Web サーバーのいずれかが接続を正しく閉じていません。おそらくあなたのソケットファクトリは equals() とおそらく hashCode() もオーバーライドする必要がありますHttpClient.

しかし、あなたTrustManagerは根本的に安全ではありません。これを本番環境にデプロイしている場合は、すでに重大なセキュリティ違反を犯しています。これは現在、数日ごとにソケットが不足するというより大きな問題です

于 2012-07-10T09:41:04.407 に答える