1

经过大量的研发和谷歌搜索,无法解决我的问题。

环境设置

Web 服务器 (Tomcat 6.0.20) --> 代理服务器 (Windows Server 2007) --> 第三部分主机

我们有应用程序,它进行在线支付交易,在完成此交易后,我们希望将交易状态发送到第三方服务器。因此,从我们的 Web 服务器向第三方服务器发布数据会在代理服务器上为一项事务打开 2 个套接字,但是当我们在 Web 服务器上检查时,它只创建了一个套接字。那么为什么代理服务器上有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();

        }

    }
}

由于一天我们要处理超过 10,000 笔交易,所以代理的套接字数量正在增加,所以 2-3 天后,我们需要硬重启 Web 服务器以释放所有使用代理服务器打开的套接字。

HTTPClient 是否为 SSL 握手打开一个套接字并为实际数据发布打开另一个套接字?我不这么认为。那么它应该在 Web 服务器上而不是在代理服务器上

为了检查 web 服务器上的套接字和打开的端口,我们使用 netstat 命令。为了检查代理服务器上的套接字和开放端口,我们使用代理工具

4

2 回答 2

0

当我们在网络服务器上检查时,它只创建了一个套接字。

因为它只有一个入站连接。

那么为什么代理服务器上有2个套接字。

因为您通过代理服务器连接到两个不同的服务器?

代理的套接字数量越来越多,因此 2-3 天后,我们需要硬重启 Web 服务器以释放所有使用代理服务器打开的套接字。

那没有意义。具有双重连接的是代理服务器,而不是 Web 服务器。你上面说了。如果 Web 服务器的套接字不足,则说明有人没有正确关闭他们的连接:客户端、代理服务器或 Web 服务器。可能您的套接字工厂也需要覆盖 equals() 和 hashCode(),以启用连接池HttpClient可能执行的任何操作,我不是这方面的专家。

但是TrustManager是完全不安全的。如果您已将其部署在生产环境中,则您已经犯了重大的安全漏洞。目前这是一个更大的问题,即每隔几天就会用完套接字。

于 2012-07-10T09:41:04.407 回答
0

当套接字端口用完时,会发生事务超时。解决这个问题的方法是调优 TIMEWAIT 相关的 Windows 注册表参数:

  • TcpTimedWaitDelay

  • 最大用户端口

  • StrictTimeWaitSeqCheck

与 TIMEWAIT 相关的 Windows 注册表参数控制套接字端口在关闭后保持不可用的时间以及有多少端口可供使用。

通过设置这些windows注册表参数,我已经解决了这个问题,但不知道,执行与否是一个正确的解决方案。

于 2012-07-31T13:02:09.970 回答