Netzwerk (UDP): Multicast(-Socket), Pakete empfangen

DarthShader

Erfahrenes Mitglied
Hallo,

ich hätte da eine Frage bezüglich den Stichworten Netzwerk, Multicast/MulticastSocket:

Meine Anwendung kann einen Multicast ausführen - dieser kommt auch bei allen Clients in derselben Gruppe an. Diese schicken nun von sich aus eine Antwort an das Programm, von dem der Multicast kam - und hier setzt meine Frage an:

Wie muss ich dieses Empfangen umsetzen? Meine Gedanken dazu sind: Ich bräuchte nach dem Versenden ja z.B. eine while Schleife, in der vom MulticastSocket die receive Methode ausgeführt wird. Die Schleife muss sein, da ich nicht weiß, von wie vielen anderen Rechnern eine Antwort kommt. Dann müsste man ja einen Timeout haben, sodass z.B. nach ein paar Sekunden nicht mehr auf eine Antwort gewartet wird, aber wie kann ich dies machen? Theoretisch könnte man das Multicast Empfangen ja in einen eigenen Thread packen, und ein weiterer Thread stellt den Timeout dar, der nach eine gewissen Zeit den ersten Thread beendet... das kommt mir aber sehr "fummelig" vor, gibt es da eine bessere Vorgehensweise?

Vielen Dank
 
Naja, low level ist das für mich nicht wirklich =) Ich finde eher, dass JGroups einen so heftig an die Hand nimmt, dass man so gar nicht checkt, was da eigentlich passiert :)

Kennst Du denn die Vorgehensweise, wie man mein "Problem" lösen kann? So viel wird das ja nicht sein, ich frage mich halt nur, ob man das auch ohne 2 Threads zu erstellen lösen kann.
 
Hallo!

Schau mal hier:
Java:
/**
 * 
 */
package de.tutorials;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author Tom
 * 
 */
public class MulticastCommunicationExample {

	static final String MULTICAST_GROUP = "224.59.10.1";

	static final int PORT = 2000;

	static final String EXIT_COMMAND = "QUIT";

	static final InetAddress GROUP_ADDRESS;
	static {
		try {
			GROUP_ADDRESS = InetAddress.getByName(MULTICAST_GROUP);
		} catch (UnknownHostException e) {
			throw new RuntimeException(e);
		}
	}

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

		Participant clientA = new Participant("A");
		Participant clientB = new Participant("B");
		Participant clientC = new Participant("C");
		Participant clientD = new Participant("D");

		final ExecutorService executorService = Executors.newFixedThreadPool(5);
		executorService.execute(clientA);
		executorService.execute(clientB);
		executorService.execute(clientC);
		executorService.execute(clientD);

		Timer pingTimer = new Timer(true);
		pingTimer.schedule(new TimerTask() {
			MulticastSocket multicastSocket;
			{
				try {
					multicastSocket = new MulticastSocket(PORT);
					multicastSocket.joinGroup(GROUP_ADDRESS);
					multicastSocket.setSoTimeout(30000);
				} catch (SocketException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			public void run() {
				try {
					sendMessageToGroup("timer ping: "
							+ System.currentTimeMillis(), multicastSocket);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}, 1000L, 10000L);

		Timer shutdownTimer = new Timer(true);
		shutdownTimer.schedule(new TimerTask() {
			MulticastSocket multicastSocket;
			{
				try {
					multicastSocket = new MulticastSocket(PORT);
					multicastSocket.joinGroup(GROUP_ADDRESS);
					multicastSocket.setSoTimeout(30000);
				} catch (SocketException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			public void run() {
				try {
					sendMessageToGroup(EXIT_COMMAND, multicastSocket);
					executorService.shutdown();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}, 30000L);

	}

	static class Participant implements Runnable {

		MulticastSocket multicastSocket;

		String id;

		boolean quit;

		public Participant(String id) {
			this.id = id;
			try {
				multicastSocket = new MulticastSocket(PORT);
				multicastSocket.joinGroup(GROUP_ADDRESS);
				multicastSocket.setSoTimeout(30000);
			} catch (SocketException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		public void run() {
			try {
				sendMessageToGroup(this.id + " joins group", multicastSocket);
				byte[] buffer = new byte[2048];
				while (!quit) {
					DatagramPacket packet = new DatagramPacket(buffer,
							buffer.length);
					multicastSocket.receive(packet);

					byte[] payLoad = new byte[packet.getLength()];
					System.arraycopy(packet.getData(), 0, payLoad, 0,
							payLoad.length);
					String receivedMessage = new String(payLoad, "UTF-8");
					if (receivedMessage.equals(EXIT_COMMAND)) {
						quit = true;
					}
					System.out.println(this.id + " received "
							+ packet.getLength() + "bytes: " + receivedMessage);
				}
				System.out.println(this.id + " leaves the group");
				multicastSocket.leaveGroup(GROUP_ADDRESS);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static void sendMessageToGroup(String message,
			MulticastSocket multicastSocket) throws Exception {
		byte[] data = message.getBytes("UTF-8");
		DatagramPacket packet = new DatagramPacket(data, 0, data.length);
		packet.setAddress(GROUP_ADDRESS);
		packet.setPort(PORT);
		multicastSocket.send(packet);
	}
}
Musste das Beispiel unter Linux testen, dass man scheinbar mit einem ordinären Windows 2000/XP nicht so ohne weiteres einen Multicast Adapter installieren kann :(
Die Beispielimplementierung ist so natürlich nur als Proof-of-Concept und Basis für eigene Experimente zu verstehen.

Mit JGroups / JXTA (http://www.jxta.org/) würde das ganze natürlich viiiiiiiel hübscher aussehen ;-)

Gruß Tom
 
Zurück