Java 多个 SSL 客户端到一台服务器

标签 java sockets ssl

我目前正在为本学期的 Android 开发一个小型个人项目。我要做的是用我的 Android 手机与我的 https 服务器建立大量连接,这样服务器就会宕机。我对编程一无所知,因为我学习的是网络而不是计算机语言。但是我以某种方式从这里那里一点一点地收集并制作了如下代码。我认为它正在使用套接字连接。

import java.net.*;
import java.io.*;
import java.security.*;
import javax.net.ssl.*;

public class HTTPSClient {
    public static void main(String[] args) {
        System.out.println("Usage: java HTTPSClient host");

        int port = 443; // default https port
        String host = "192.168.0.8";

        TrustManager[] trustAll = new javax.net.ssl.TrustManager[]{
          new javax.net.ssl.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){}
          }
        };

        try {
            javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL");
            sc.init(null, trustAll, new java.security.SecureRandom());

            Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
            SSLSocketFactory factory = (SSLSocketFactory) sc.getSocketFactory();
            SSLSocket socket = (SSLSocket) factory.createSocket(host, port);

            Writer out = new OutputStreamWriter(socket.getOutputStream());
            out.write("GET / HTTP/1.0\\r\\n");
            out.write("\\r\\n");
            out.flush();

            // read response
            BufferedReader in = new BufferedReader(
            new InputStreamReader(socket.getInputStream()));
            int c;
            while ((c = in.read()) != -1) {
                System.out.write(c);
            }
            // out.close();
            // in.close(); 
            // socket.close();

        } catch (Exception e) {
            System.err.println(e);
        }
    }
}

我在我的 macbook 上启用了 https,我可以看到正在监听的端口 443。当我执行上面的代码时,我可以通过'netstat -an | 看到一个已建立的连接。 grep 443' 直到我停止它。我的问题是:如果我想用这段代码建立多重连接,我应该添加什么?这段代码有可能吗?我的想法是,如果我可以在我的 macbook 上看到大量已建立的 443 端口连接,我将无法使用浏览器连接 https:://localhost,因为机器已关闭。我不知道这是否正确,但我希望。因为学期快结束了,反正我也得做点东西汇报一下。

我不确定在为 Android 手机编写代码时该代码是否相同,但我只想先看看会发生什么。我真的很绝望,请帮助我。非常感谢。

最佳答案

据我所知,您正在尝试让多个客户端(手机)连接到您的服务器。

您的服务器看起来很可靠。您应该能够修改它以轻松处理多个客户端。

通常您需要某种处理程序来处理传入的客户端连接。您将需要一个循环来等待新连接,然后需要一个线程来独立处理每个连接。套接字的每个实例只能处理一个连接。套接字工厂允许您将套接字实例多次绑定(bind)到服务器。我有两个类来处理多个连接。我的第一个类是服务器本身,第二个是处理每个客户端的线程。

如果您不熟悉线程,您应该检查一下。

这是服务器类:

public class ServerThread extends Thread
{
    private Vector<ClientHandlerThread> connectedClients = new Vector<ClientHandlerThread>(20, 5);

   public void run()
   {
    SSLServerSocket sslDataTraffic = null;
    SSLServerSocket sslFileTraffic = null;
    SSLServerSocketFactory sslFac = null;

    try
    {
        System.out.print("Validating SSL certificate... ");
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(new FileInputStream(certificateDir), password);
        System.out.println("DONE.");

        System.out.print("Creating trust engine........ ");
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(keyStore);
        System.out.println("DONE.");

        System.out.print("Creating key engine.......... ");
        KeyManagerFactory kmf = KeyManagerFactory.getInstance((KeyManagerFactory.getDefaultAlgorithm()));
        kmf.init(keyStore, password);
        System.out.println("DONE.");

        System.out.print("Creating SSL context......... ");
        System.setProperty("https.protocols", "SSL");
        SSLContext  ctx = SSLContext.getInstance("SSL");
        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        sslFac = ctx.getServerSocketFactory();
        System.out.println("DONE.");
    }
    catch (Exception e) {}

    try
    {
        System.out.print("Creating data socket......... ");
        sslDataTraffic = (SSLServerSocket) sslFac.createServerSocket(dataPort);
        System.out.println("DONE. Est. on:" + dataPort);
    }
    catch (IOException e)
    {
        System.out.println("FAILED.");
        System.out.println(e.toString() + " ::: " + e.getCause());
        System.exit(-1);
    }

    try
    {
        System.out.print("Creating file socket......... ");
        sslFileTraffic = (SSLServerSocket) sslFac.createServerSocket(filePort);
        System.out.println("DONE. Est. on:" + filePort);

    }
    catch (IOException e)
    {
        System.out.println("FAILED.");
        System.out.println(e.toString() + " ::: " + e.getCause());
        System.exit(-1);
    }

    while (running)
        {
            SSLSocket sslDataTrafficSocketInstance = (SSLSocket) sslDataTraffic.accept();
            SSLSocket sslFileTrafficSocketInstance = (SSLSocket) sslFileTraffic.accept();
            ClientHandlerThread c = new ClientHandlerThread(sslDataTrafficSocketInstance, sslFileTrafficSocketInstance);
            c.start();
            connectedClients.add(c);
        }
}

注意类末尾的 while 循环。它将等到客户端连接(调用 accept() 方法)。创建一个独立线程来处理该客户端(电话)。

客户端线程如下:

public class ClientHandlerThread extends Thread
{
private boolean running = true;

private SSLSocket dataSocket;
private SSLSocket fileSocket;

private PrintWriter writer;
private BufferedReader reader;
private InputStream inputStream;
private OutputStream outputStream;

public ClientHandlerThread(
        SSLSocket dataSocket,
        SSLSocket fileSocket)
{
    this.dataSocket = dataSocket;
    this.fileSocket = fileSocket;

    try
    {
        this.reader = new BufferedReader(new InputStreamReader(this.dataSocket.getInputStream()));
        this.writer = new PrintWriter(this.dataSocket.getOutputStream());
        this.inputStream = fileSocket.getInputStream();
        this.outputStream = fileSocket.getOutputStream();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }

    this.ip = this.dataSocket.getInetAddress().getHostAddress();
}

public void run()
{
    try
    {
        writer.println("SERVER_HANDSHAKE_INIT");
        writer.flush();

        String fromClient;
        while (running && (fromClient = reader.readLine()) != null)
        {
            if (fromClient.equals("CLIENT_HANDSHAKE_INIT"))
                System.out.println("Client Connected: " + getIP());
        }
    }
    catch (IOException e)
    {
        e.getCause();

    }
}

    public String getIP()
{
    return ip;
}

public boolean isRunning()
{
    return running;
}

public void setRunning(boolean running)
{
    this.running = running;
}
}

您现在可以遍历包含所有客户端的 Vector 中的每个客户端线程。这将允许您处理多个客户端并独立地与每个客户端交互。这包括读取输入/输出流。

这些类(class)是我在夏季开发的一个简单远程管理系统中使用的类(class)的精简版本。您应该能够根据需要修改它们以满足您的需要。例如,您可以向客户端线程构造函数添加一个参数来跟踪命名。

我希望这解释了如何处理到服务器的多个传入连接。 随时 DM 或给我发电子邮件以获取更多信息。

干杯

关于Java 多个 SSL 客户端到一台服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16803785/

相关文章:

java - Java 8 是否缺少处理可变流的 Stream.concat?

java - 本地 JVM 之间的通信

c++ - OpenSSL 将消息拆分为两条记录

ruby SSL 代理(MITM)

c# - 调用 TLS 1.0 和 TLS 1.2 Web 服务的 ASP.NET 应用程序

java - 事务第二部分中的 Save(List<S>) 与 save(Entity)

java - 使用 bash globing 设置 Java 命令行属性

java - 无法多次连接mysql

php - 套接字 - 超时

c# - 如何使用初始字节连接到套接字