2

我目前正在为这个学期使用 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 手机编写代码时该代码是否相同,但我只想先看看发生了什么。我真的很绝望,请帮助我。非常感谢。

4

2 回答 2

1

据我了解,您正试图让多个客户端(电话)连接到您的服务器。

您的服务器看起来很坚固。您应该能够对其进行修改以轻松处理多个客户端。

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

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

这是服务器类:

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 中的每个客户端线程。这将允许您处理多个客户端并独立地与每个客户端进行交互。这包括读取输入/输出流。

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

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

干杯

于 2013-11-24T20:56:34.630 回答
0

您可以更改代码以循环打开连接:

        int numConnections = 100;
        for (int i=0; i<numConnections; i++) {
            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();
        }

我强烈建议将套接字对象保留在数组或集合变量中,并在完成后关闭 I/O 流和套接字,但这也将在 main() 退出时完成 - 只要知道这在编程中通常是不好的做法,如果你想要在打开连接的代码块之后整个程序没有退出的情况下重用此代码。

于 2013-05-29T01:34:11.590 回答