views:

1202

answers:

3

I am new to multithreading & socket programming in Java. I would like to know what is the best way to implement 2 threads - one for receiving a socket and one for sending a socket. If what I am trying to do sounds absurd, pls let me know why! The code is largely inspired from Sun's tutorials online.I want to use Multicast sockets so that I can work with a multicast group.

class Server extends Thread
{

    static protected MulticastSocket socket = null;
    protected BufferedReader in = null;
    public InetAddress group;

    private static class Receive implements Runnable
    {

        public void run()
        {
            try
            {
                byte[] buf = new byte[256];
                DatagramPacket pkt = new DatagramPacket(buf,buf.length);
                socket.receive(pkt);
                String received = new String(pkt.getData(),0,pkt.getLength());
                System.out.println("From server@" + received);          
                Thread.sleep(1000);
            }
            catch (IOException e)
            { 
                System.out.println("Error:"+e);
            }   
            catch (InterruptedException e)
            { 
                System.out.println("Error:"+e);
            }   

        }

    }


    public Server() throws IOException
    {
        super("server");
        socket = new MulticastSocket(4446);
        group = InetAddress.getByName("239.231.12.3");
        socket.joinGroup(group);
    }

    public void run()
    {

        while(1>0)
        {   
            try
            {
                byte[] buf = new byte[256];
                DatagramPacket pkt = new DatagramPacket(buf,buf.length);        
                //String msg = reader.readLine();
                String pid = ManagementFactory.getRuntimeMXBean().getName();
                buf = pid.getBytes();
                pkt = new DatagramPacket(buf,buf.length,group,4446);
                socket.send(pkt);
                Thread t = new Thread(new Receive());
                t.start();

                while(t.isAlive())
                { 
                    t.join(1000);
                }
                sleep(1);
            }
            catch (IOException e)
            { 
                System.out.println("Error:"+e);
            }   
            catch (InterruptedException e)
            { 
                System.out.println("Error:"+e);
            }   

        }
        //socket.close();
    }

    public static void main(String[] args) throws IOException
    {
        new Server().start();
        //System.out.println("Hello");
    }

}
+1  A: 

Wanting to create threads in an application is not absurd! You won't need exactly 2 threads, but I think you're talking about 2 classes that implement the Runnable interface.

The threading API has gotten better since Java 1.5 and you don't need to mess with java.lang.Thread anymore. You can simply create a java.util.concurrent.Executor and submit Runnable instances to it.

The book Java Concurrency in Practice uses that exact problem - creating a threaded socket server - and walks through several iterations of the code to show the best way to do it. Check out the free sample chapter, which is great. I won't copy/paste the code here, but look specifically at listing 6.8.

Drew
Thanks Drew, I didn't know you could do that! I am gonna take a look at the concurrentExecutor right away
Ravi
+2  A: 

First thing is first: your classes should start with a capital letter per the Java Naming Conventions:

Class names should be nouns, in mixed case with the first letter of each internal word capitalized. Try to keep your class names simple and descriptive. Use whole words-avoid acronyms and abbreviations (unless the abbreviation is much more widely used than the long form, such as URL or HTML).

Second: Try to break down the code into coherent sections and organize them around some common feature that you're dealing with... perhaps around the functionality or the model you're programming.

The (basic) model for the server is that the only thing it does is receive socket connections... the server relies on a handler to handle those connections and that's it. If you try to build that model it would look something like this:

class Server{
    private final ServerSocket serverSocket;
    private final ExecutorService pool;

    public Server(int port, int poolSize) throws IOException {
      serverSocket = new ServerSocket(port);
      pool = Executors.newFixedThreadPool(poolSize);
    }

    public void serve() {
      try {
        while(true) {
          pool.execute(new Handler(serverSocket.accept()));
        }
      } catch (IOException ex) {
        pool.shutdown();
      }
    }
  }

  class Handler implements Runnable {
    private final Socket socket;
    Handler(Socket socket) { this.socket = socket; }
    public void run() {
      // receive the datagram packets
    }
 }

Third: I would recommend that you look at some existing examples.

Updated per comments:
OK Ravi, there are some big issues with your code and some minor issues with it:

  1. I assume that the Receive class is your client... you should pull that out as a separate program (with its own main class) and run your server and multiple clients at the same time. Spawning a new "client thread" from your server for every new UDP package you send is a disturbing idea (big issue).

  2. When you make your client application, you should make it run the receiving code in its own while loop (minor issue), e.g.:

    public class Client extends Thread
    {
        public Client(/*..*/)
        {
            // initialize your client
        }
    
    
    
    public void run()
    {
        while(true)
        {
            // receive UDP packets
            // process the UDP packets
        }
    }
    
    
    public static void main(String[] args) throws IOException
    {
        // start your client
        new Client().start();
    }
    
    }
  3. You should only need just one thread per client and one thread per server (you technically don't even a separate thread in there since main has its own thread), so you might not find the ExecutorService that useful.

Otherwise your approach is correct... but I would still recommend that you check out some of examples.

Lirik
http://www.developer.com/java/ent/article.php/3645111/Java-5s-BlockingQueue.htm - Doug Lea's 'simple server'
John V.
@John Ah, yes... thanks John, that's what I was looking for.
Lirik
+1 Good answer !!!!!
Romain Hippeau
the start() method on the server class in Ravi's example is part of the Thread class, which the server class extends. Other than that, this is a great answer.
Jim Hurne
@Jim thanks! :) Updated my answer.
Lirik
Ravi
Ravi
@Ravi, ok... then I don't see anything particularly wrong with your implementation. Is there a specific reason that you *need* to create multiple new threads to receive packets? I would pull that out into a separate thread altogether, but I don't know what's your motivation for doing it that way.
Lirik
@Lirik: Well, I am not sure when I really need to use threads. Because the socket.receive() waits indefinitely until a packet arrives, I thought I should make a thread for that. What I basically need to implement: a node can receive a packet any time but what if it receives a packet during the send or vice versa? I think I need threads for this, right. So I guess what you are saying is : keep the receive in a separate thread and the send as part of the main thread? Thanks for your patience by the way!
Ravi
@Ravi: the key thing here, as you seem to have noticed already, is not to send on the same thread that you receive on. Have one thread for receiving packets and then have as many threads as you find necessary for sending packets. This sort of interaction is demonstrated in my server example where the socket connection blocks on accept. The thread that handles the accepted packet can also be used to send/broadcast something (which it usually does)... I hope that makes sense :).
Lirik
@Lirik: Hmmm, thanks a lot for your feedback...I think I know what I am doing now :)
Ravi
A: 

2 threads is fine. One reader another writer. Remember that with UDP you should not spawn new handler threads (unless what you're doing takes a long time), I recommend throwing the incoming messages into a processing Queue. The same for the send, have a send thread that blocks on an incoming Queue for UDP send.

Xepoch