2010-05-12 21 views
15

Sono nuovo alla programmazione Socket in Java e stavo cercando di capire se il codice sottostante non è una cosa sbagliata da fare. La mia domanda è:Prese Java: più thread client sulla stessa porta sulla stessa macchina?

Posso avere più client su ogni thread tenta di connettersi a un'istanza del server nello stesso programma e si aspettano il server per leggere e scrivere dati con isolamento tra i clienti"

public class Client extends Thread 
{ 
    ... 
    void run() 
    { 
     Socket socket = new Socket("localhost", 1234); 
     doIO(socket); 
    } 
} 

public class Server extends Thread 
{ 
    ... 
    void run() 
    { 
     // serverSocket on "localhost", 1234 
     Socket clientSock = serverSocket.accept(); 
     executor.execute(new ClientWorker(clientSock)); 
    } 
} 

Ora può ho istanze client multipli su diversi thread cercando di collegare sulla stessa porta della macchina attuale?

per esempio,

Server s = new Server("localhost", 1234); 
    s.start(); 
    Client[] c = new Client[10]; 
    for (int i = 0; i < c.length; ++i) 
    { 
     c.start(); 
    } 

risposta

3

Fino a quando un solo oggetto tenta di associare la porta per l'ascolto, quindi non ci sono problemi con la connessione di più client.

+0

Grazie ragazzi, ho pensato al porto come una singola entità fisica (come un filo) dal momento che ha un unico numero. Quindi il mio pensiero è che può essere utilizzato da un solo socket client, altrimenti più socket client potrebbero scrivere nello stesso filo alla volta. Ma dalle tue risposte, penso che la porta stessa sia composta da più risorse (ad esempio, come blocchi di memoria), ma il socket sarà associato a uno di quei blocchi probabilmente indicizzati da una chiave di associazione. – espcorrupt

+3

La porta è solo un numero. Non corrisponde a nulla di fisico. Una * connessione * è definita dalla tupla {protocollo, indirizzo di origine, porta di origine, indirizzo di destinazione, porta di destinazione}. Il sistema operativo sul lato client si occuperà di garantire numeri di porta in uscita diversi per ciascuna connessione in uscita. Quindi non vi è alcun problema nel disporre di più connessioni in entrata allo stesso host/porta di destinazione, anche se provengono tutte dallo stesso host di origine client. – EJP

0

Sì, non importa se i client sono locali o remoti. La cosa importante nel tuo esempio è che ClientWorker è thread-safe, poiché il tuo server avrà più istanze di quella classe (una per ogni connessione client).

1

In questo esempio, il tuo Server accetta e gestisce una connessione client alla volta. È possibile avere come numero Client s come si desidera tentare di connettersi, ma verrà gestito solo uno alla volta.

Non è chiaro se la logica del tuo executor sia multithread, dato che non hai fornito l'implementazione. Se l'executor delega a un threadpool o qualcosa del genere, è necessario assicurarsi che il proprio ClientWorker sia thread-safe, poiché si avranno più istanze in esecuzione in parallelo.

Sto ovviamente partendo dal presupposto che il tuo Client sia thread-safe, poiché la tua domanda riguarda solo lo Server.

8

Sì, tuttavia, solo un client sarà in grado di connettersi per l'esecuzione del thread come scritto.

Si può semplicemente mettere il server run() all'interno di un loop while while per consentire la connessione di più client. A seconda dell'esecutore, verranno eseguiti in serie o in parallelo.

public class Server extends Thread 
    { 
     ... 
     void run() 
     { 
      while(true){ 
       // serverSocket on "localhost", 1234 
       Socket clientSock = serverSocket.accept(); 
       executor.execute(new ClientWorker(clientSock)); 
      } 
     } 
    } 
0

Così. Per iniziare:

È possibile accettare più client con un server in quanto ne si accetta solo uno nel metodo run. Devi solo chiamare accept() una seconda volta.

Quindi, nel ciclo for: innanzitutto è necessario creare ogni volta un nuovo oggetto Client. Quindi è possibile chiamare c[i].start(); e non c.start().

Ora posso avere più client istanze su diversi thread che tentano di connettersi sulla stessa porta della macchina corrente ?

Sì, è possibile. Basta creare nuovi thread ed eseguirli. Questo dovrebbe funzionare perfettamente.

aspettiamo che il server per leggere e scrivere dati con isolamento tra i clienti

È possibile utilizzare la vostra esperienza delle tecniche di base IO come con il file-io:

OutputStream os = socket.getOutputStream(); 
PrintStream pw = new PrintStream(os, true); // Or PrintWriter, I don't know what the best one is. 
pw.println("Hello, other side of the connection!"); 

E per leggendo usa un BufferedReader.

0

si può provare qualcosa su queste linee

public class MultiThreadServer extends Application { 
    // Text area for displaying contents 
    private TextArea ta = new TextArea(); 

    // Number a client 
    private int clientNo = 0; 

    @Override // Override the start method in the Application class 
    public void start(Stage primaryStage) { 
    // Create a scene and place it in the stage 
    Scene scene = new Scene(new ScrollPane(ta), 450, 200); 
    primaryStage.setTitle("MultiThreadServer"); // Set the stage title 
    primaryStage.setScene(scene); // Place the scene in the stage 
    primaryStage.show(); // Display the stage 

    new Thread(() -> { 
     try { 
     // Create a server socket 
     ServerSocket serverSocket = new ServerSocket(8000); 
     ta.appendText("MultiThreadServer started at " 
      + new Date() + '\n'); 

     while (true) { 
      // Listen for a new connection request 
      Socket socket = serverSocket.accept(); 

      // Increment clientNo 
      clientNo++; 

      Platform.runLater(() -> { 
      // Display the client number 
      ta.appendText("Starting thread for client " + clientNo + 
       " at " + new Date() + '\n'); 

      // Find the client's host name, and IP address 
      InetAddress inetAddress = socket.getInetAddress(); 
      ta.appendText("Client " + clientNo + "'s host name is " 
       + inetAddress.getHostName() + "\n"); 
      ta.appendText("Client " + clientNo + "'s IP Address is " 
       + inetAddress.getHostAddress() + "\n"); 
      }); 

      // Create and start a new thread for the connection 
      new Thread(new HandleAClient(socket)).start(); 
     } 
     } 
     catch(IOException ex) { 
     System.err.println(ex); 
     } 
    }).start(); 
    } 

    // Define the thread class for handling new connection 
    class HandleAClient implements Runnable { 
    private Socket socket; // A connected socket 

    /** Construct a thread */ 
    public HandleAClient(Socket socket) { 
     this.socket = socket; 
    } 

    /** Run a thread */ 
    public void run() { 
     try { 
     // Create data input and output streams 
     DataInputStream inputFromClient = new DataInputStream(
      socket.getInputStream()); 
     DataOutputStream outputToClient = new DataOutputStream(
      socket.getOutputStream()); 

     // Continuously serve the client 
     while (true) { 
      // Receive radius from the client 
      double radius = inputFromClient.readDouble(); 

      // Compute area 
      double area = radius * radius * Math.PI; 

      // Send area back to the client 
      outputToClient.writeDouble(area); 

      Platform.runLater(() -> { 
      ta.appendText("radius received from client: " + 
       radius + '\n'); 
      ta.appendText("Area found: " + area + '\n'); 
      }); 
     } 
     } 
     catch(IOException e) { 
     ex.printStackTrace(); 
     } 
    } 
    } 

    /** 
    * The main method is only needed for the IDE with limited 
    * JavaFX support. Not needed for running from the command line. 
    */ 
    public static void main(String[] args) { 
    launch(args); 
    } 
} 
Problemi correlati