views:

1284

answers:

4

How can I implement a threaded UDP based server in Java ?

Basically what I want, is to connect multiple clients to the server, and let each client have his own thread. The only problem is, that I don't know how to check if a client is trying to connect to the server and spawn a new thread for it.

boolean listening = true;

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

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

In this case the server will spawn new threads until it runs out of memory. Here's the code for the ServerThread ( I think I need here a mechanism that stalls the creation of the ServerThread until a client tries to connect.

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

So fathers of Java programming please help.

A: 

Since UDP is a connectionless protocol, why do you need to spawn a new thread for each connection? When you receive a UDP packet maybe you should spawn a new thread to take care of dealing with the message received.

UDP connections are not like TCP connections. They do not remain active and such is the design of UDP.

The handlePacket() method of this next code block can do whatever it wants with the data received. And many clients can send multiple packets to the same UDP listener. Maybe it will help you.

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() );
      }
     }
    }
Peter D
just curious, but whats the 'w' prefix all about? Maybe i'm c-damaged but it sure looks like a word aligned int or something... B-)
KarlP
Ah, the w is for working variable. It's a convention they enforce at my place of work that I now have a habit of doing. Working variables start with a w and parameters with a p.
Peter D
+2  A: 

Have you looked at the Apache Mina project? I believe even one of its examples takes you through how to setup an UDP-based server with it. If this for a real product, I would not recommend trying to come up with your own implementation from scratch. You will want to use a library to accomplish this so you are not using one thread per connection, rather a thread pool.

Elijah
+1  A: 

I don't really see the need.

Its a school thing right?

If you need to keep track of the clients, you should have a local representation of each client (a Client object on your server). It can take care of whatever client-specific things you need to do.

In that case You need to be able to find out from which client the message was sent from. (using information from the message.) You can keep the clients in a map.

The most effective way is probably to do all handling in the main thread, unless whatever that needs to be done can "block" waiting for external events (or if some things that's supposed to happen might take a long time and some a very short.)

public class Client {

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

}

The client object can perhaps start a new thread in handleMessage() if neccesary.

You shouldn't start multiple server threads.

The server thread can do:

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

If there are no client-specific things to care about, just read the messages and handle them as they arrive, in one thread.

KarlP
+2  A: 

The design for this to a certain extent depends on whether each complete UDP "dialog" just requires a single request and immediate response, whether it's a single request or response with retransmissions, or whether there'll be a need to process lots of packets for each client.

The RADIUS server I wrote had the single request + retransmit model and spawned a thread for each incoming packet.

As each DatagramPacket was received it was passed to a new thread, and then that thread was responsible for sending back the response. This was because the computation and database accesses involved in generating each response could take a relatively long time and it's easier to spawn a thread than to have some other mechanism to handle new packets that arrive whilst old packets are still being processed.

public class Server implements Runnable {
    public void run() {
        while (true) {
            DatagramPacket packet = socket.receive();
            new Responder(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);
    }
}
Alnitak