2009-04-21 9 views
9

Come posso implementare un server UDP basato su thread in Java?Come posso implementare un server UDP basato su thread in Java?

Fondamentalmente quello che voglio è connettere più client al server e lasciare che ogni client abbia il suo thread. L'unico problema è che non so come verificare se un client sta tentando di connettersi al server e generare un nuovo thread per esso.

boolean listening = true; 

System.out.println("Server started."); 

while (listening) 
    new ServerThread().start(); 

In questo caso il server genera nuovi thread fino a esaurimento della memoria. Ecco il codice per la ServerThread (penso che ho bisogno qui un meccanismo che bancarelle la creazione del ServerThread fino a quando un client tenta di connettersi.

public ServerThread(String name) throws IOException 
{ 
    super(name); 
    socket = new DatagramSocket(); 
} 

Così padri di programmazione Java prega di aiuto.

+9

Questo mi odora di compiti a casa. –

+1

So che questo è un vecchio Q, ma quello che hai fatto era loop durante l'ascolto, creando ogni volta nuovi DatagramSocket, il più velocemente possibile dal tuo sistema. Alla fine si esaurirà completamente la memoria. – garlicman

+1

Questa è una buona domanda che merita una risposta utilizzando ExecutorService. – JohnMerlino

risposta

13

Il design per questo in una certa misura dipende dal fatto che ogni "finestra di dialogo" UDP completa richiede solo una singola richiesta e una risposta immediata, sia che si tratti di una singola richiesta o risposta con ritrasmissioni, o se sia necessario elaborare un sacco di pacchetti per ogni cliente.

Il server RADIUS che ho scritto aveva la singola richiesta + ritrasmissione del modello e generato un thread per ogni pacchetto in ingresso.

Dato che ogni DatagramPacket è stato ricevuto, è stato passato a un nuovo thread e quindi tale thread era responsabile dell'invio della risposta. Questo perché gli accessi al database e al calcolo coinvolti nella generazione di ogni risposta potevano richiedere un tempo relativamente lungo ed è più facile generare un thread piuttosto che avere un altro meccanismo per gestire nuovi pacchetti che arrivano mentre i vecchi pacchetti sono ancora in fase di elaborazione.

public class Server implements Runnable { 
    public void run() { 
     while (true) { 
      DatagramPacket packet = socket.receive(); 
      new Thread(new Responder(socket, packet)).start(); 
     } 
    } 
} 

public class Responder implements Runnable { 

    Socket socket = null; 
    DatagramPacket packet = null; 

    public Responder(Socket socket, DatagramPacket packet) { 
     this.socket = socket; 
     this.packet = packet; 
    } 

    public void run() { 
     byte[] data = makeResponse(); // code not shown 
     DatagramPacket response = new DatagramPacket(data, data.length, 
      packet.getAddress(), packet.getPort()); 
     socket.send(response); 
    } 
} 
+0

Poiché Responder implementa solo Runnable, è necessario assegnargli un thread: (new Thread (new Responder (pacchetto))). Start(). L'utilizzo di un ExecutorService fornirebbe tuttavia una migliore gestione dei thread. – thoughtcrimes

+0

@thoughtcrimes Non penso che la classe 'ExecutorService' esistesse quando ho scritto per la prima volta il codice derivato da questo esempio. Buon punto sull'errore 'Thread'! – Alnitak

+0

Nel caso di "elaborare un sacco di pacchetti per ogni cliente". TCP è meglio dal suo persistente? – Sohaib

5

Dal UDP è un protocollo senza connessione, perché è necessario generare un nuovo thread per ogni connessione? Quando si riceve un pacchetto UDP forse si dovrebbe generare una nuova discussione per occuparsi del messaggio ricevuto.

Le connessioni UDP non sono come Connessioni TCP: non rimangono attive e tale è la progettazione di UDP.

Il metodo handlePacket() del prossimo blocco di codice può fare tutto ciò che desidera con i dati ricevuti. E molti client possono inviare più pacchetti allo stesso listener UDP. Forse ti aiuterà.

public void run() { 
     DatagramSocket wSocket = null; 
     DatagramPacket wPacket = null; 
     byte[] wBuffer = null; 

     try { 
      wSocket = new DatagramSocket(listenPort); 
      wBuffer = new byte[ 2048 ]; 
      wPacket = new DatagramPacket(wBuffer, wBuffer.length); 
     } catch (SocketException e) { 
      log.fatal("Could not open the socket: \n" + e.getMessage()); 
      System.exit(1); 
     } 

     while (isRunning) { 
      try { 
       wSocket.receive(wPacket); 
       handlePacket(wPacket, wBuffer); 
      } catch (Exception e) { 
       log.error(e.getMessage()); 
      } 
     } 
    } 
+0

solo curioso, ma qual è il prefisso 'w' tutto? Forse sono c-danneggiato ma sicuramente sembra una parola allineata int o qualcosa ... B-) – KarlP

+0

Ah, il w è per variabile di lavoro. È una convenzione che fanno rispettare il mio posto di lavoro che ora ho l'abitudine di fare. Le variabili di lavoro iniziano con w e parametri con p. –

+0

e qual è il prefisso per la classe lavoratrice? – lelloman

3

Hai guardato il progetto Apache Mina? Credo che persino uno dei suoi esempi ti porti attraverso come configurare un server basato su UDP con esso. Se questo fosse per un prodotto reale, non consiglierei di provare a creare la tua implementazione da zero. Si vorrà utilizzare una libreria per fare ciò, quindi non si è utilizzando un thread per connessione, piuttosto un pool di thread.

1

Non vedo davvero il bisogno.

È una cosa della scuola vero?

Se è necessario tenere traccia dei client, è necessario disporre di una rappresentazione locale di ciascun client (un oggetto Client sul server). Può prendersi cura di qualsiasi cosa specifica del cliente che devi fare.

In tal caso, è necessario essere in grado di scoprire da quale client è stato inviato il messaggio. (utilizzando le informazioni del messaggio.) È possibile mantenere i client in una mappa.

Il modo più efficace consiste probabilmente nel gestire tutto il thread principale, a meno che tutto ciò che deve essere fatto possa "bloccare" in attesa di eventi esterni (o se alcune cose che dovrebbero accadere potrebbero richiedere molto tempo e alcune molto breve.)

public class Client { 

    public void handleMessage(Message m) { 
    // do stuff here. 
    } 

} 

L'oggetto client può forse iniziare un nuovo thread in handleMessage() se necessario.

Non avviare più thread del server.

Il thread del server può fare:

while(running) { 
    socket.receive(DatagramPacket p); 
    client = figureOutClient(p); 
    client.handleMessage(p); 
} 

Se non ci sono cose specifiche per il cliente di preoccuparsi, basta leggere i messaggi e gestirli al loro arrivo, in un thread.

Problemi correlati