Earn Online (2) English (10) Java (7) Money (1) Money Online (1) Script (2) Trending (7)

Multicast with java


Multicast With Java

Multicast Overview
Multicast Overview
Multicast is a special feature of UDP protocol that enable programmer to send message to a group of receivers on a specific multicast IP address and port. Multicast has advantage in this scenario.
Let us say I want to send “Hello” message to 100 computers on my network. Perhaps, my first solution is to send the “Hello” message to each of them via UDP or TCP.
What a problem is this scenario?
There are 3 generic problems:
  • Consume a lot of processing power on sender as it needs to send to every receiver
  • Bandwidth flooding
  • The arrival time is not the same for every receiver
Seeing this problem, I propose my second solution by employing Multicast. Multicast runs over UDP protocol.

Multicast Principal

Multicast Network
Multicast Network

Multicast Characteristics

  • Multicast is using UDP under the hood. So sending and receiving data are much the same as UDP
  • The big noticeable from UDP
    • Sender should address packages to an IP number in the range between 224.0.0.1and 239.255.255.254. Please see the full range of Multicast IP Address
    • Receivers must join multicast group to receive packet
  • Several multicast sockets can be bound simultaneously to the same port (Contrary to UDP and TCP)
  • Multicast is viable for video conference, service discovery application, etc.

Multicast in Java

  • MulticastSocket: extension of DatagramSocket
    • MulticastSocket socket = new MulticastSocket(8888);
  • Join and Leave group
    • joinGroup(InetAddress group)
    • leaveGroup(InetAddress group)

Examples

Java Multicast Image Sender - ImageSender.java


import java.awt.AWTException;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MouseInfo;
import java.awt.PointerInfo;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;

import com.sun.image.codec.jpeg.ImageFormatException;

/**
 * Multicast Image Sender
 * Version: 0.1
 * 
 */
public class ImageSender {

/* Flags and sizes */
public static int HEADER_SIZE = 8;
public static int MAX_PACKETS = 255;
public static int SESSION_START = 128;
public static int SESSION_END = 64;
public static int DATAGRAM_MAX_SIZE = 65507 - HEADER_SIZE;
public static int MAX_SESSION_NUMBER = 255;

/*
* The absolute maximum datagram packet size is 65507, The maximum IP packet
* size of 65535 minus 20 bytes for the IP header and 8 bytes for the UDP
* header.
*/
public static String OUTPUT_FORMAT = "jpg";

public static int COLOUR_OUTPUT = BufferedImage.TYPE_INT_RGB;

/* Default parameters */
public static double SCALING = 0.5;
public static int SLEEP_MILLIS = 2000;
public static String IP_ADDRESS =  "225.4.5.6";
public static int PORT = 4444;
public static boolean SHOW_MOUSEPOINTER = true;

/**
* Takes a screenshot (fullscreen)

* @return Sreenshot
* @throws AWTException
* @throws ImageFormatException
* @throws IOException
*/
public static BufferedImage getScreenshot() throws AWTException,
ImageFormatException, IOException {
Toolkit toolkit = Toolkit.getDefaultToolkit();
Dimension screenSize = toolkit.getScreenSize();
Rectangle screenRect = new Rectangle(screenSize);

Robot robot = new Robot();
BufferedImage image = robot.createScreenCapture(screenRect);

return image;
}

/**
* Returns a random image from given directory

* @param dir Image directory
* @return Random Image
* @throws IOException
*/
public static BufferedImage getRandomImageFromDir(File dir) throws IOException {
String[] images = dir.list(new ImageFileFilter());
        int random = new Random().nextInt(images.length);

        String fileName = dir.getAbsoluteFile() + File.separator + images[random];
        File imageFile = new File(fileName);

return ImageIO.read(imageFile);
}

/**
* Converts BufferedImage to byte array

* @param image Image to convert
* @param format Image format (JPEG, PNG or GIF)
* @return Byte Array
* @throws IOException
*/
public static byte[] bufferedImageToByteArray(BufferedImage image, String format) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, format, baos);
return baos.toByteArray();
}

/**
* Scales a bufferd image 

* @param source Image to scale
* @param w Image widht
* @param h Image height
* @return Scaled image
*/
public static BufferedImage scale(BufferedImage source, int w, int h) {
Image image = source
.getScaledInstance(w, h, Image.SCALE_AREA_AVERAGING);
BufferedImage result = new BufferedImage(w, h, COLOUR_OUTPUT);
Graphics2D g = result.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return result;
}

/**
* Shrinks a BufferedImage

* @param source Image to shrink
* @param factor Scaling factor
* @return Scaled image
*/
public static BufferedImage shrink(BufferedImage source, double factor) {
int w = (int) (source.getWidth() * factor);
int h = (int) (source.getHeight() * factor);
return scale(source, w, h);
}

/**
* Copies a BufferedImage

* @param image Image to copy
* @return Copied image
*/
public static BufferedImage copyBufferedImage(BufferedImage image) {
BufferedImage copyOfIm = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
        Graphics2D g = copyOfIm.createGraphics();
        g.drawRenderedImage(image, null);
        g.dispose();
        return copyOfIm;
    }

/*

*/
/**
* Sends a byte array via multicast
* Multicast addresses are IP addresses in the range of 224.0.0.0 to
* 239.255.255.255.

* @param imageData Byte array
* @param multicastAddress IP multicast address
* @param port Port
* @return <code>true</code> on success otherwise <code>false</code>
*/
private boolean sendImage(byte[] imageData, String multicastAddress,
int port) {
InetAddress ia;

boolean ret = false;
int ttl = 2;

try {
ia = InetAddress.getByName(multicastAddress);
} catch (UnknownHostException e) {
e.printStackTrace();
return ret;
}

MulticastSocket ms = null;

try {
ms = new MulticastSocket();
ms.setTimeToLive(ttl);
DatagramPacket dp = new DatagramPacket(imageData, imageData.length,
ia, port);
ms.send(dp);
ret = true;
} catch (IOException e) {
e.printStackTrace();
ret = false;
} finally {
if (ms != null) {
ms.close();
}
}

return ret;
}

/**
* @param args
*/
public static void main(String[] args) {
ImageSender sender = new ImageSender();
int sessionNumber = 0;
boolean multicastImages = false;


// Create Frame
JFrame frame = new JFrame("Multicast Image Sender");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel();
frame.getContentPane().add(label);
frame.setVisible(true);


/* Handle command line arguments */
switch (args.length) {
case 5:
IP_ADDRESS = args[4];
case 4:
PORT = Integer.parseInt(args[3]);
case 3:
SHOW_MOUSEPOINTER = Integer.parseInt(args[2]) == 1 ? true : false;
case 2:
SLEEP_MILLIS = Integer.parseInt(args[1]) * 1000;
case 1:
SCALING = Double.parseDouble(args[0]);
}

/* Check weather to multicast screenshots or images */
if(new File("images").exists() && new File("images").isDirectory()) {
label.setText("Multicasting images...");
multicastImages = true;
}
else {
label.setText("Multicasting screenshots...");
}

frame.pack();

try {
/* Continuously send images */
while (true) {
BufferedImage image;

/* Get image or screenshot */
if(multicastImages) {
image = getRandomImageFromDir(new File("images"));
}
else {
image = getScreenshot();

/* Draw mousepointer into image */
if(SHOW_MOUSEPOINTER) {
PointerInfo p = MouseInfo.getPointerInfo();
int mouseX = p.getLocation().x;
int mouseY = p.getLocation().y;
 
Graphics2D  g2d = image.createGraphics();
g2d.setColor(Color.red);
Polygon polygon1 = new Polygon(new int[] { mouseX, mouseX+10, mouseX, mouseX},
                                      new int[] { mouseY, mouseY+10, mouseY+15, mouseY}
         , 4);
 
Polygon polygon2 = new Polygon(new int[] { mouseX+1, mouseX+10+1, mouseX+1, mouseX+1},
                            new int[] { mouseY+1, mouseY+10+1, mouseY+15+1, mouseY+1}
, 4);
g2d.setColor(Color.black);
g2d.fill(polygon1);
 
g2d.setColor(Color.red);
g2d.fill(polygon2);
g2d.dispose();
}
 
 
}

/* Scale image */
image = shrink(image, SCALING);
byte[] imageByteArray = bufferedImageToByteArray(image, OUTPUT_FORMAT);
int packets = (int) Math.ceil(imageByteArray.length / (float)DATAGRAM_MAX_SIZE);

/* If image has more than MAX_PACKETS slices -> error */
if(packets > MAX_PACKETS) {
System.out.println("Image is too large to be transmitted!");
continue;
}

/* Loop through slices */
for(int i = 0; i <= packets; i++) {
int flags = 0;
flags = i == 0 ? flags | SESSION_START: flags;
flags = (i + 1) * DATAGRAM_MAX_SIZE > imageByteArray.length ? flags | SESSION_END : flags;

int size = (flags & SESSION_END) != SESSION_END ? DATAGRAM_MAX_SIZE : imageByteArray.length - i * DATAGRAM_MAX_SIZE;

/* Set additional header */
byte[] data = new byte[HEADER_SIZE + size];
data[0] = (byte)flags;
data[1] = (byte)sessionNumber;
data[2] = (byte)packets;
data[3] = (byte)(DATAGRAM_MAX_SIZE >> 8);
data[4] = (byte)DATAGRAM_MAX_SIZE;
data[5] = (byte)i;
data[6] = (byte)(size >> 8);
data[7] = (byte)size;

/* Copy current slice to byte array */
System.arraycopy(imageByteArray, i * DATAGRAM_MAX_SIZE, data, HEADER_SIZE, size);
/* Send multicast packet */
sender.sendImage(data, IP_ADDRESS, PORT);

/* Leave loop if last slice has been sent */
if((flags & SESSION_END) == SESSION_END) break;
}
/* Sleep */
Thread.sleep(SLEEP_MILLIS);

/* Increase session number */
sessionNumber = sessionNumber < MAX_SESSION_NUMBER ? ++sessionNumber : 0;
}
} catch (Exception e) {
e.printStackTrace();
}
}

}

/**
 * File filter class
 * 
 *
 */
class ImageFileFilter implements FilenameFilter
{
    /* (non-Javadoc)
     * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
     */
    public boolean accept( File dir, String name )
    {
      String nameLc = name.toLowerCase();
      return nameLc.endsWith(".jpg") ? true : false;
    }
}



Java Multicast Image Receiver - ImageReceiver.java


import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JWindow;

/**
 * Multicast Image Receiver
 * Version: 0.1
 * 
 *  
 */
public class ImageReceiver implements KeyListener {
/* Flags and sizes */
public static int HEADER_SIZE = 8;

public static int SESSION_START = 128;

public static int SESSION_END = 64;

/*
* The absolute maximum datagram packet size is 65507, The maximum IP packet
* size of 65535 minus 20 bytes for the IP header and 8 bytes for the UDP
* header.
*/
private static int DATAGRAM_MAX_SIZE = 65507;

/* Default values */
public static String IP_ADDRESS = "225.4.5.6";

public static int PORT = 4444;

JFrame frame;

boolean fullscreen = false;

JWindow fullscreenWindow = null;

/**
* Revceive method

* @param multicastAddress
*            IP multicast adress
* @param port
*            Port
*/
private void receiveImages(String multicastAddress, int port) {
boolean debug = true;

InetAddress ia = null;
MulticastSocket ms = null;

/* Constuct frame */
JLabel labelImage = new JLabel();
JLabel windowImage = new JLabel();

frame = new JFrame("Multicast Image Receiver");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(labelImage);
frame.setSize(300, 10);
frame.setVisible(true);
frame.addKeyListener(this);

/* Construct full screen window */
fullscreenWindow = new JWindow();
fullscreenWindow.getContentPane().add(windowImage);
fullscreenWindow.addKeyListener(this);

try {
/* Get address */
ia = InetAddress.getByName(multicastAddress);

/* Setup socket and join group */
ms = new MulticastSocket(port);
ms.joinGroup(ia);

int currentSession = -1;
int slicesStored = 0;
int[] slicesCol = null;
byte[] imageData = null;
boolean sessionAvailable = false;

/* Setup byte array to store data received */
byte[] buffer = new byte[DATAGRAM_MAX_SIZE];

/* Receiving loop */
while (true) {
/* Receive a UDP packet */
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
ms.receive(dp);
byte[] data = dp.getData();

/* Read header infomation */
short session = (short) (data[1] & 0xff);
short slices = (short) (data[2] & 0xff);
int maxPacketSize = (int) ((data[3] & 0xff) << 8 | (data[4] & 0xff)); // mask
// the
// sign
// bit
short slice = (short) (data[5] & 0xff);
int size = (int) ((data[6] & 0xff) << 8 | (data[7] & 0xff)); // mask
// the
// sign
// bit

if (debug) {
System.out.println("------------- PACKET -------------");
System.out.println("SESSION_START = "
+ ((data[0] & SESSION_START) == SESSION_START));
System.out.println("SSESSION_END = "
+ ((data[0] & SESSION_END) == SESSION_END));
System.out.println("SESSION NR = " + session);
System.out.println("SLICES = " + slices);
System.out.println("MAX PACKET SIZE = " + maxPacketSize);
System.out.println("SLICE NR = " + slice);
System.out.println("SIZE = " + size);
System.out.println("------------- PACKET -------------\n");
}

/* If SESSION_START falg is set, setup start values */
if ((data[0] & SESSION_START) == SESSION_START) {
if (session != currentSession) {
currentSession = session;
slicesStored = 0;
/* Consturct a appropreately sized byte array */
imageData = new byte[slices * maxPacketSize];
slicesCol = new int[slices];
sessionAvailable = true;
}
}

/* If package belogs to current session */
if (sessionAvailable && session == currentSession) {
if (slicesCol != null && slicesCol[slice] == 0) {
slicesCol[slice] = 1;
System.arraycopy(data, HEADER_SIZE, imageData, slice
* maxPacketSize, size);
slicesStored++;
}
}

/* If image is complete dispay it */
if (slicesStored == slices) {
ByteArrayInputStream bis = new ByteArrayInputStream(
imageData);
BufferedImage image = ImageIO.read(bis);
labelImage.setIcon(new ImageIcon(image));
windowImage.setIcon(new ImageIcon(image));

frame.pack();
}

if (debug) {
System.out.println("STORED SLICES: " + slicesStored);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ms != null) {
try {
/* Leave group and close socket */
ms.leaveGroup(ia);
ms.close();
} catch (IOException e) {
}
}
}
}

/**
* @param args
*/
public static void main(String[] args) {

/* Handle command line arguments */
switch (args.length) {
case 2:
IP_ADDRESS = args[1];
case 1:
PORT = Integer.parseInt(args[0]);
}

ImageReceiver receiver = new ImageReceiver();
receiver.receiveImages(IP_ADDRESS, PORT);
}

/*
* (non-Javadoc)

* @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
*/
public void keyPressed(KeyEvent keyevent) {
GraphicsDevice device = GraphicsEnvironment
.getLocalGraphicsEnvironment().getDefaultScreenDevice();

/* Toggle full screen mode on key press */
if (fullscreen) {
device.setFullScreenWindow(null);
fullscreenWindow.setVisible(false);
fullscreen = false;
} else {
device.setFullScreenWindow(fullscreenWindow);
fullscreenWindow.setVisible(true);
fullscreen = true;
}

}

public void keyReleased(KeyEvent keyevent) {
}

public void keyTyped(KeyEvent keyevent) {
}

}




Multicast with java Multicast with java Reviewed by Yogesh Choudhry on November 11, 2013 Rating: 5

Popular Posts