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(); } } }