2013-05-29 59 views
1

我目前正在爲Android這個學期的一個小個人項目工作。我要做的就是用我的Android手機與我的https服務器建立很多連接,以便服務器關閉。我對編程一無所知,因爲我正在學習網絡而不是計算機語言。但我不知何故從這裏一塊一塊地收集起來,並做出如下的代碼。我認爲它使用套接字連接。Java多個SSL客戶端到一臺服務器

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手機制作代碼時該代碼是否會相同,但我只想先看到發生的事情。我真的很絕望,請幫助我。非常感謝你。

回答

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()退出時也會這樣做 - 只要知道這在編程中通常是不好的做法,如果您希望在打開連接的代碼塊之後沒有退出整個程序的情況下重用此代碼( S)。

+0

感謝斯科特,但是當我輸入'netstat -an | grep 443'在終端上,我仍然只能看到一個已建立的連接。沒有其他辦法填滿桌子嗎?再次感謝。 – user2430608

+0

反斜槓太多。應該是單身而不是雙。 – EJP

0

從我所能理解的,你試圖讓多個客戶端(電話)連接到你的服務器。

您的服務器看起來很穩固。您應該可以修改它以輕鬆處理多個客戶端。

通常您需要某種類型的處理程序來處理傳入的客戶端連接。您將需要一個循環來等待新的連接,然後需要一個線程來獨立處理每個連接。每個套接字實例只能處理一個連接。套接字工廠允許您將多個套接字實例綁定到服務器。我有兩個類來處理多個連接。我的第一個類是服務器本身,第二個類是處理每個客戶端的線程。

如果你不熟悉線程,你應該檢查它。

這是服務器類:

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; 
} 
} 

您現在可以通過包含所有客戶端載體中保存的每個客戶端線程迭代的能力。這將允許您處理多個客戶端並獨立與每個客戶端進行交互。這包括讀取輸入/輸出流。

這些類是我用於我在夏季開發的簡單遠程管理系統的那些類的精簡版。您應該可以根據需要修改它們以滿足您的需求。例如,您可以向客戶端線程構造函數添加一個參數以跟蹤命名。

我希望這解釋瞭如何處理到服務器的多個傳入連接。 隨意DM或電子郵件瞭解更多信息。

乾杯

相關問題