diff --git a/examples/src/UdpExamples/MulticastUdpChatKeyboardSender.java b/examples/src/UdpExamples/MulticastUdpChatKeyboardSender.java new file mode 100644 index 0000000000000000000000000000000000000000..79ad6716309c91b67c5e3dd64c79d48309b51cd9 --- /dev/null +++ b/examples/src/UdpExamples/MulticastUdpChatKeyboardSender.java @@ -0,0 +1,155 @@ +package UdpExamples; + +import static UdpExamples.MulticastUdpReceiver.BUFFER_LENGTH; +import edu.nps.moves.dis7.utilities.DisThreadedNetworkInterface; +import java.io.*; +import java.net.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Get keyboard input to send string packets on a UDP multicast group. + * The source looks a lot like MulticastUdpSender. + * TODO: Start this after launching MulticastUdpReceiver. + * Multicast must be enabled for the (wired or wireless) LAN that the system is connected too. + * Note that these paired programs can communicate within a remote LAN (such as a wireless + * home network) even if one or both machines are connected via a + * <a href="https://en.wikipedia.org/wiki/Virtual_private_network" target="_blank">Virtual Private Network (VPN)</a>. + * + * Privacy note: this sender advertises your user name as part of the multicast packet message + * + * @author mcgredo + * @author brutzman@nps.edu + */ +public class MulticastUdpChatKeyboardSender +{ + /** Default constructor */ + public MulticastUdpChatKeyboardSender() + { + // default constructor + } + // reserved range for all IPv4 multicast: 224.0.0.0 through 239.255.255.255 + // https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml + + /** Default multicast group address for send and receive connections. + * @see <a href="https://en.wikipedia.org/wiki/Multicast_address" target="_blank">https://en.wikipedia.org/wiki/Multicast_address</a> */ + public static final String MULTICAST_ADDRESS = "239.1.2.15"; // within reserved multicast address range + /** Default socket port used, matches Wireshark DIS capture default + * @see <a href="https://en.wikipedia.org/wiki/Port_(computer_networking)" target="_blank">https://en.wikipedia.org/wiki/Port_(computer_networking)</a> */ + public static final int DESTINATION_PORT = 1718; + + /** Time to live: how many router-decrement levels can be crossed */ + public static final int TTL = 10; + + /** How many packets to send prior to termination */ + public static final int MAXLOOPSIZE = 100; // or maybe 20000 + + /** How many packets to send prior to termination */ + public static final String LINE_TERMINATOR = "###;"; // do not begin with ; + + /** Receiving this message causes termination + * @see <a href="https://en.wikipedia.org/wiki/Sentinel_value" target="_blank">https://en.wikipedia.org/wiki/Sentinel_value</a> */ + public static final String QUIT_SENTINEL = "QUIT QUIT QUIT!"; + private static NetworkInterface ni; + + /** + * Program invocation, execution starts here. + * TODO: allow setting address/port group and provide help message. + * @param args command-line arguments + * @throws java.io.IOException execution error + */ + @SuppressWarnings("SleepWhileInLoop") + public static void main(String[] args) throws IOException + { + MulticastSocket multicastSocket = null; + InetSocketAddress group = null; + + // Put together a message with binary content. "ByteArrayOutputStream" + // is a java.io utility that lets us put together an array of binary + // data, which we put into the UDP packet. + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + + try + { + System.out.println("UdpExamples.MulticastUdpChatKeyboardSender started..."); + // https://stackoverflow.com/questions/18747134/getting-cant-assign-requested-address-java-net-socketexception-using-ehcache + System.setProperty("java.net.preferIPv4Stack", "true"); + + // multicast group we are sending to--not a single host + multicastSocket = new MulticastSocket(/*DESTINATION_PORT*/); + multicastSocket.setTimeToLive(TTL); // time to live reduces scope of transmission + InetAddress multicastAddress = InetAddress.getByName(MULTICAST_ADDRESS); + System.out.println("Multicast address/port: " + multicastAddress.getHostAddress() + "/" + DESTINATION_PORT); + + group = new InetSocketAddress(multicastAddress, DESTINATION_PORT); + // Join group useful on receiving side + multicastSocket.joinGroup(group, ni = DisThreadedNetworkInterface.findIpv4Interface()); + // You can join multiple groups here + + byte[] buffer = baos.toByteArray(); + DatagramPacket packet = new DatagramPacket(buffer, buffer.length, group/*, DESTINATION_PORT*/); + + String userName = System.getProperty("user.name"); + String newMessage = new String(); // from user via keyboard + + for (int messageIndex = 1; messageIndex < MAXLOOPSIZE; messageIndex++) + { + String spacer = new String(); // align console outputs + if (messageIndex < 10) + spacer = " "; + + // Put together an updated packet to send + if (messageIndex < MAXLOOPSIZE) + { + System.out.print ("type new message here: "); + newMessage = System.console().readLine(); // this line blocks, awaiting keyboard input from user +// System.out.println ("[trace] console return: " + newMessage); + + // avoid overrunning receive buffer + int maxStringLength = BUFFER_LENGTH - LINE_TERMINATOR.length() - userName.length() - 5; + if (newMessage.length() > maxStringLength) + newMessage = newMessage.substring(0, maxStringLength); + + // Put together an updated packet to send + dos.writeChars("[" + userName + " " + spacer + messageIndex + "] "); + dos.writeChars(newMessage + LINE_TERMINATOR); // string chars for readability, include ; semicolon as termination sentinel + } + else dos.writeChars(QUIT_SENTINEL + LINE_TERMINATOR); // note string must include ; semicolon as termination sentinel + + buffer = baos.toByteArray(); + packet.setData(buffer); + multicastSocket.send(packet); + System.out.print ("Sent packet " + spacer + (messageIndex) + " of " + MAXLOOPSIZE + ": "); + System.out.println("\"" + newMessage + "\""); + baos.reset(); + + // How fast does this go? Does UDP try to slow it down, or does + // this cause network problems? (hint: yes for an unlimited send + // rate, unlike TCP). How do you know on the receiving side + // that you haven't received a duplicate UDP packet, out of + // order packet, or dropped packet? Necessary considerations. + Thread.sleep(1000); // only send one per second + } + System.out.println("MulticastSender complete."); + } + catch(IOException | InterruptedException e) + { + System.err.println("Problem with MulticastSender, see exception trace:"); + System.err.println(e); + } finally { + + if (multicastSocket != null && !multicastSocket.isClosed()) { + try { + multicastSocket.leaveGroup(group, ni); + } catch (IOException ex) { + Logger.getLogger(MulticastUdpChatKeyboardSender.class.getName()).log(Level.SEVERE, null, ex); + } + multicastSocket.close(); + } + + dos.close(); + } + } + +}