A Simple Multicast Chat Program

Hi All,

I am trying to complete an excersize in Java, to create a Simple Multicast Chat Program. I have been given the following code:

public class Chat {

public static void main (String argv[]) {
  MulticastSender msend = new MulticastSender ("224.123.111.101", 45000, 1);
  Thread sender = new Thread (msend);
  ChatWindow cw = new ChatWindow (msend, argv[0]);
  sender.start ();

  MulticastSniffermsniff=new MulticastSniffer("224.123.111.101",45000,1,cw.getOutput());
  Thread sniffer = new Thread (msniff);
  sniffer.start ();
  }
}
 

import java.awt.*;
import java.awt.event.*;

public class ChatWindow extends Frame implements ActionListener {
TextArea output = new TextArea ();
TextField input = new TextField ("", 20);
Button add = new Button ("Say");
Label say = new Label ("Say :");
MulticastSender msend = null;
String name = "";

public ChatWindow (MulticastSender msend, String name) {
  this.name = name;
  this.msend = msend;
  buildGui ();
  }

public void actionPerformed (ActionEvent e) {
  String send = "(" + name + ") " + this.input.getText ();
  msend.send (send.getBytes ());
  input.setText ("");
  }

public TextArea getOutput () {
  return (output);
  }

public void buildGui () {
  output.setEditable (false);
  this.setSize (400, 400);
  this.setLayout (new GridBagLayout ());
  Panel inputLayout = new Panel ();
  inputLayout.setLayout (new GridBagLayout ());
  GridBagConstraints gbcInput = new GridBagConstraints ();
  gbcInput.anchor = GridBagConstraints.WEST;
  gbcInput.fill = GridBagConstraints.NONE;
  gbcInput.weighty = 0;
  gbcInput.gridx = 0;
  gbcInput.gridy = 0;

  gbcInput.weightx = 0;
  inputLayout.add (say, gbcInput);
  gbcInput.fill = GridBagConstraints.HORIZONTAL;
  gbcInput.gridx = 1;
  gbcInput.weightx = 1;
  inputLayout.add (input, gbcInput);
  gbcInput.gridx = 2;
  gbcInput.fill = GridBagConstraints.NONE;
  gbcInput.weightx = 0;
  inputLayout.add (add, gbcInput);
  add.addActionListener (this);

  GridBagConstraints gbcOutput = new GridBagConstraints ();
  gbcOutput.anchor = GridBagConstraints.CENTER;
  gbcOutput.fill = GridBagConstraints.BOTH;
  gbcOutput.weightx = 1;
  gbcOutput.weighty = 1;
  gbcOutput.gridx = 0;
  gbcOutput.gridy = 0;
  this.add (output, gbcOutput);
  gbcOutput.anchor = GridBagConstraints.WEST;
  gbcOutput.gridy = 1;
  gbcOutput.weighty = 0;
  this.add (inputLayout, gbcOutput);
  this.show ();
  }
}

I have been asked to:
Develop an appropriate sender class
Develop an appropriate sniffer class

Im not really sure where to start, can anyone help?
LVL 2
mtcmediaAsked:
Who is Participating?
 
ozymandiasConnect With a Mentor Commented:
I'm not sure.
I would have to assume that it is possible to have a MulticastSocket and a DatagramSocket bound to the same port. Since the MulticastSocket only listens maybe there is no contention so it's allowed.
0
 
ozymandiasCommented:
There are lots of projects developing multicasting applications in Java . Here is one example where you can get the complete set of libraries and the source code, so you can have a look at how best to implement it :

http://www.experimentalstuff.com/Technologies/JRMS/
0
 
mtcmediaAuthor Commented:
Thanks for that, and I have read a lot of resources similar to above - but I am still unsure how to build the two remaining classes from the above source. Can anyone help?
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
ozymandiasCommented:
This resource is a Java MultiCast Chat program.
It implements a MulticastSender and MulticastReceiver (similar in function to your MulticastSniffer).

Have a look at the source.

http://jmc.logicnet.ro/
0
 
mtcmediaAuthor Commented:
I cant open .jar files.

Can someone please post the classes I need? If so that would be GREAT!

Thanks in advance for your help!
0
 
ozymandiasCommented:
winzip will open jar files.

However, in VERY BASIC form here are the classes.

public class Chat {

     public static void main (String argv[]) {
          MulticastSender msend = new MulticastSender ("230.0.0.1", 4446, 1);
          Thread sender = new Thread (msend);
          ChatWindow cw = new ChatWindow (msend, "test");
          sender.start ();

          MulticastSniffer msniff = new MulticastSniffer("230.0.0.1",4446,1,cw.getOutput());
          Thread sniffer = new Thread (msniff);
          sniffer.start ();
     }
}
0
 
ozymandiasCommented:
import java.awt.TextArea;
import java.net.*;
import java.io.*;

public class MulticastSniffer extends Thread{

     public static int MSG_SIZE = 1024;

    protected MulticastSocket socket;
    protected InetAddress mcAddress;
    protected InetAddress lAddress;
    protected boolean interrupt = false;
    protected int port;

     TextArea output;

     public MulticastSniffer(String address, int port, int dunno, TextArea ta){
          output = ta;
          this.port = port;
        try {
            mcAddress = InetAddress.getByName(address);
            lAddress = InetAddress.getLocalHost();
            System.out.println(lAddress);
        } catch(UnknownHostException e) {
            e.printStackTrace();
        }
     }

     public void run(){
        DatagramPacket packet;
        try {
            socket = new MulticastSocket(port);
            socket.setInterface(lAddress);
            socket.joinGroup(mcAddress);
             while (!interrupt){
                    byte[] buf = new byte[MSG_SIZE];
                    packet = new DatagramPacket(buf, buf.length);
                    socket.receive(packet);
                    String received = new String(packet.getData());
                    System.out.println("Data : " + received);
                    output.append(received + "\n");
               }
               socket.leaveGroup(mcAddress);
               socket.close();
        } catch(IOException e) {
            e.printStackTrace();
        }
     }

}
0
 
ozymandiasCommented:
import java.net.*;
import java.io.*;

public class MulticastSender extends Thread{

     protected DatagramSocket socket = null;
     protected String mcAddress;
     protected int port;
     protected int dunno;
     public boolean interrupt = false;

     public MulticastSender(String address, int port, int i){
          mcAddress = address;
          this.port = port;
          dunno = i;
     }

     public void run(){
          /*
          try{
               socket = new DatagramSocket(port);
          }catch(SocketException e) {
             e.printStackTrace();
          }
          while (!interrupt){
          }
          socket.close();
          */
     }

     public void send(byte[] b){
          try{
               socket = new DatagramSocket(port-1);
               InetAddress group = InetAddress.getByName(mcAddress);
               DatagramPacket packet = new DatagramPacket(b, b.length, group, port);
               socket.send(packet);
               socket.close();
          }catch (IOException e) {
             e.printStackTrace();
          }
     }

}
0
 
ozymandiasCommented:
If you run two copies of Chat whatever you type in one windows will appear in the other.

0
 
mtcmediaAuthor Commented:
Hey ozymandias,

Great thanks for that, I am at work just now, but will try and run it as soon as I get home.

It all seems clear enough, apart from one question. In the multicastsender class, when does the send method get called? I notice you have commented out the run, so should the send method body be inside run? Or just call send from run? Im not sure how this bit works.

Thanks again!
0
 
ozymandiasCommented:
In the sender I have commeneted out the run portion because I had to test the program on one computer. If I bind one instance of the thread to the send port then I cannot run another instance of the program because the port will always be in use.

So for testing I create the socket on each send() rather than in run().

The send method() gets called by the ChatWindow when you click on the "say" button.
0
 
ozymandiasCommented:
Here is a modified version of the sender that will allow two instance of Chat to run on the same machine. The run() method will search for an available send port if the normal one is in use.

import java.net.*;
import java.io.*;

public class MulticastSender extends Thread{

     protected DatagramSocket socket = null;
     protected String mcAddress;
     protected int port;
     protected int dunno;
     public boolean interrupt = false;

     public MulticastSender(String address, int port, int i){
          mcAddress = address;
          this.port = port;
          dunno = i;
     }

     public void run(){
          boolean isBound = false;
          int sendport = port;
          while (!isBound){
               try{
                    socket = new DatagramSocket(sendport);
                    isBound = true;
               }catch(SocketException e) {
                  sendport++;
               }
          }
          while (!interrupt){
          }
          socket.close();
     }

     public void send(byte[] b){
          try{
               InetAddress group = InetAddress.getByName(mcAddress);
               DatagramPacket packet = new DatagramPacket(b, b.length, group, port);
               socket.send(packet);
          }catch (IOException e) {
             e.printStackTrace();
          }
     }

}
0
 
mtcmediaAuthor Commented:
Thanks for that. But the first class you posted will work if I run it on two different machines? And provided I uncomment the run?
0
 
mtcmediaAuthor Commented:
Also why dont you have to run joinGroup in sender?
0
 
mtcmediaAuthor Commented:
Forget that last question about joinGroup - but answer the previous one if possible please :)
0
 
mtcmediaAuthor Commented:
OK I have it running using two seperate machines and the first Sender class. Can you please answer these final questions:

* socket = new DatagramSocket(port-1) Why do I need to create more than one DatagramSocket on different ports? Whenever the packet is sent, the socket is closed, so why cant I just re open that socket on the same port for the next packet - instead of using a different port everytime.

* how can I create the MulticastSocket and DatagramSocket on the same port number - surely this shouldnt work?

0
 
ozymandiasCommented:
>> But the first class you posted will work if I run it on two different machines? And provided I uncomment the run?

Yes, you would have to uncomment the run, but also change the send method because currently it creates and closes the socket so remove the first and last line of the code inside the try block.


>> socket = new DatagramSocket(port-1) Why do I need to create more than one DatagramSocket on different ports?

You don't. But you can't bind the server and the receiver to the same port.

>>  Whenever the packet is sent, the socket is closed, so why cant I just re open that socket on the same port for the next packet - instead of using a different port everytime.


Yes, whenever the packet is sent, the socket is closed, but it shouldn't be. The run method binds to the socket and then holds it until interrupted. The send method can then use the socket over and over again without having to recreate it each time.

>> how can I create the MulticastSocket and DatagramSocket on the same port number - surely this shouldnt work?

You can't, and as far as I can see you don't.
0
 
mtcmediaAuthor Commented:
>> how can I create the MulticastSocket and DatagramSocket on the same port number - surely this shouldnt work?

You can't, and as far as I can see you don't.
-------------------------------------------------

The above, it looks to me like i am?

MulticastSender msend = new MulticastSender ("224.123.111.101", 45000, 1);

 MulticastSniffer msniff=new MulticastSniffer("224.123.111.101",45000,1,cw.getOutput());

Sniffer and sender on the same port?
0
 
ozymandiasCommented:
Yes, but if you look at the implementation of sender, it does not just use port 45000. It "tries" to use it but if it can't it tries 45001 and then 45002 and so on until it finds a free port.
0
 
mtcmediaAuthor Commented:
I used the first class you posted... and it doesnt have the increasing port value... and I dont get any exception when I run it - it seems to work.
0
 
mtcmediaAuthor Commented:
I can see that the second class you gave me will keep checking for the next port to create the sender on BUT as I said, when I use the first class, it will just use the port number I give it.

Then, if I try to run another chat it wont work - as expected. BUT once the sender is setup, I then setup the sniffer on the same port. How can this work?
0
 
mtcmediaAuthor Commented:
ok :) I accept that
0
 
CleanupPingCommented:
mtcmedia:
This old question needs to be finalized -- accept an answer, split points, or get a refund.  For information on your options, please click here-> http:/help/closing.jsp#1 
EXPERTS:
Post your closing recommendations!  No comment means you don't care.
0
 
jimmackCommented:
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Accept ozymandias' comment as answer.

Please leave any comments here within the next seven days.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

jimmack
EE Cleanup Volunteer
0
All Courses

From novice to tech pro — start learning today.