We have been discussing connection-oriented, streams-based transmission. Now we consider connectionless transmission with datagrams.
Connection-oriented transmission is like the telephone system in which you dial and are given a connection to the telephone of the person with whom you wish to communicate. The connection is maintained for the duration of your phone call, even when you are not talking.
Connectionless transmission with datagrams is more like the way mail is carried via the postal service. If a large message will not fit in one envelope, you break it into separate message pieces that you place in separate, sequentially numbered envelopes. Each of the letters is then mailed at the same time. The letters could arrive in order, out of order or not at all (the last case is rare, but it does happen). The person at the receiving end reassembles the message pieces into sequential order before attempting to make sense of the message. If your message is small enough to fit in one envelope, you need not worry about the "out-of-sequence" problem, but it is still possible that your message might not arrive. One difference between datagrams and postal mail is that duplicates of datagrams can arrive at the receiving computer.
Figure 24.9Fig. 24.12 use datagrams to send packets of information via the User Datagram Protocol (UDP) between a client application and a server application. In the Client application (Fig. 24.11), the user types a message into a textfield and presses Enter. The program converts the message into a byte array and places it in a datagram packet that is sent to the server. The Server (Fig. 24.9) receives the packet and displays the information in it, then echoes the packet back to the client. Upon receiving the packet, the client displays the information it contains.
Figure 24.9. Server side of connectionless client/server computing with datagrams.
(This item is displayed on pages 1132 - 1134 in the print version)
1 // Fig. 24.9: Server.java 2 // Server that receives and sends packets from/to a client. 3 import java.io.IOException; 4 import java.net.DatagramPacket; 5 import java.net.DatagramSocket; 6 import java.net.SocketException; 7 import java.awt.BorderLayout; 8 import javax.swing.JFrame; 9 import javax.swing.JScrollPane; 10 import javax.swing.JTextArea; 11 import javax.swing.SwingUtilities; 12 13 public class Server extends JFrame 14 { 15 private JTextArea displayArea; // displays packets received 16 private DatagramSocket socket; // socket to connect to client 17 18 // set up GUI and DatagramSocket 19 public Server() 20 { 21 super( "Server" ); 22 23 displayArea = new JTextArea(); // create displayArea 24 add( new JScrollPane( displayArea ), BorderLayout.CENTER ); 25 setSize( 400, 300 ); // set size of window 26 setVisible( true ); // show window 27 28 try // create DatagramSocket for sending and receiving packets 29 { 30 socket = new DatagramSocket( 5000 ); 31 } // end try 32 catch ( SocketException socketException ) 33 { 34 socketException.printStackTrace(); 35 System.exit( 1 ); 36 } // end catch 37 } // end Server constructor 38 39 // wait for packets to arrive, display data and echo packet to client 40 public void waitForPackets() 41 { 42 while ( true ) 43 { 44 try // receive packet, display contents, return copy to client 45 { 46 byte data[] = new byte[ 100 ]; // set up packet 47 DatagramPacket receivePacket = 48 new DatagramPacket( data, data.length ); 49 50 socket.receive( receivePacket ); // wait to receive packet 51 52 // display information from received packet 53 displayMessage( " Packet received:" + 54 " From host: " + receivePacket.getAddress() + 55 " Host port: " + receivePacket.getPort() + 56 " Length: " + receivePacket.getLength() + 57 " Containing: " + new String( receivePacket.getData(), 58 0, receivePacket.getLength() ) ); 59 60 sendPacketToClient( receivePacket ); // send packet to client 61 } // end try 62 catch ( IOException ioException ) 63 { 64 displayMessage( ioException.toString() + " " ); 65 ioException.printStackTrace(); 66 } // end catch 67 } // end while 68 } // end method waitForPackets 69 70 // echo packet to client 71 private void sendPacketToClient( DatagramPacket receivePacket ) 72 throws IOException 73 { 74 displayMessage( " Echo data to client..." ); 75 76 // create packet to send 77 DatagramPacket sendPacket = new DatagramPacket( 78 receivePacket.getData(), receivePacket.getLength(), 79 receivePacket.getAddress(), receivePacket.getPort() ); 80 81 socket.send( sendPacket ); // send packet to client 82 displayMessage( "Packet sent " ); 83 } // end method sendPacketToClient 84 85 // manipulates displayArea in the event-dispatch thread 86 private void displayMessage( final String messageToDisplay ) 87 { 88 SwingUtilities.invokeLater( 89 new Runnable() 90 { 91 public void run() // updates displayArea 92 { 93 displayArea.append( messageToDisplay ); // display message 94 } // end method run 95 } // end anonymous inner class 96 ); // end call to SwingUtilities.invokeLater 97 } // end method displayMessage 98 } // end class Server |
Figure 24.10. Class that tests the Server.
(This item is displayed on pages 1134 - 1135 in the print version)
1 // Fig. 24.10: ServerTest.java 2 // Tests the Server class. 3 import javax.swing.JFrame; 4 5 public class ServerTest 6 { 7 public static void main( String args[] ) 8 { 9 Server application = new Server(); // create server 10 application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); 11 application.waitForPackets(); // run server application 12 } // end main 13 } // end class ServerTest Server window after packet of data is received from Client |
Figure 24.11. Client side of connectionless client/server computing with datagrams.
(This item is displayed on pages 1135 - 1137 in the print version)
1 // Fig. 24.11: Client.java 2 // Client that sends and receives packets to/from a server. 3 import java.io.IOException; 4 import java.net.DatagramPacket; 5 import java.net.DatagramSocket; 6 import java.net.InetAddress; 7 import java.net.SocketException; 8 import java.awt.BorderLayout; 9 import java.awt.event.ActionEvent; 10 import java.awt.event.ActionListener; 11 import javax.swing.JFrame; 12 import javax.swing.JScrollPane; 13 import javax.swing.JTextArea; 14 import javax.swing.JTextField; 15 import javax.swing.SwingUtilities; 16 17 public class Client extends JFrame 18 { 19 private JTextField enterField; // for entering messages 20 private JTextArea displayArea; // for displaying messages 21 private DatagramSocket socket; // socket to connect to server 22 23 // set up GUI and DatagramSocket 24 public Client() 25 { 26 super( "Client" ); 27 28 enterField = new JTextField( "Type message here" ); 29 enterField.addActionListener( 30 new ActionListener() 31 { 32 public void actionPerformed( ActionEvent event ) 33 { 34 try // create and send packet 35 { 36 // get message from textfield 37 String message = event.getActionCommand(); 38 displayArea.append( " Sending packet containing: " + 39 message + " " ); 40 41 byte data[] = message.getBytes(); // convert to bytes 42 43 // create sendPacket 44 DatagramPacket sendPacket = new DatagramPacket( data, 45 data.length, InetAddress.getLocalHost(), 5000 ); 46 47 socket.send( sendPacket ); // send packet 48 displayArea.append( "Packet sent " ); 49 displayArea.setCaretPosition( 50 displayArea.getText().length() ); 51 } // end try 52 catch ( IOException ioException ) 53 { 54 displayMessage( ioException.toString() + " " ); 55 ioException.printStackTrace(); 56 } // end catch 57 } // end actionPerformed 58 } // end inner class 59 ); // end call to addActionListener 60 61 add( enterField, BorderLayout.NORTH ); 62 63 displayArea = new JTextArea(); 64 add( new JScrollPane( displayArea ), BorderLayout.CENTER ); 65 66 setSize( 400, 300 ); // set window size 67 setVisible( true ); // show window 68 69 try // create DatagramSocket for sending and receiving packets 70 { 71 socket = new DatagramSocket(); 72 } // end try 73 catch ( SocketException socketException ) 74 { 75 socketException.printStackTrace(); 76 System.exit( 1 ); 77 } // end catch 78 } // end Client constructor 79 80 // wait for packets to arrive from Server, display packet contents 81 public void waitForPackets() 82 { 83 while ( true ) 84 { 85 try // receive packet and display contents 86 { 87 byte data[] = new byte[ 100 ]; // set up packet 88 DatagramPacket receivePacket = new DatagramPacket( 89 data, data.length ); 90 91 socket.receive( receivePacket ); // wait for packet 92 93 // display packet contents 94 displayMessage( " Packet received:" + 95 " From host: " + receivePacket.getAddress() + 96 " Host port: " + receivePacket.getPort() + 97 " Length: " + receivePacket.getLength() + 98 " Containing: " + new String( receivePacket.getData(), 99 0, receivePacket.getLength() ) ); 100 } // end try 101 catch ( IOException exception ) 102 { 103 displayMessage( exception.toString() + " " ); 104 exception.printStackTrace(); 105 } // end catch 106 } // end while 107 } // end method waitForPackets 108 109 // manipulates displayArea in the event-dispatch thread 110 private void displayMessage( final String messageToDisplay ) 111 { 112 SwingUtilities.invokeLater( 113 new Runnable() 114 { 115 public void run() // updates displayArea 116 { 117 displayArea.append( messageToDisplay ); 118 } // end method run 119 } // end inner class 120 ); // end call to SwingUtilities.invokeLater 121 } // end method displayMessage 122 } // end class Client |
Figure 24.12. Class that tests the Client.
(This item is displayed on pages 1137 - 1138 in the print version)
1 // Fig. 24.12: ClientTest.java 2 // Tests the Client class. 3 import javax.swing.JFrame; 4 5 public class ClientTest 6 { 7 public static void main( String args[] ) 8 { 9 Client application = new Client(); // create client 10 application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); 11 application.waitForPackets(); // run client application 12 } // end main 13 } // end class ClientTest Client window after sending packet to Server and receiving packet back from Server |
Server Class
Class Server (Fig. 24.9) declares two DatagramPackets that the server uses to send and receive information and one DatagramSocket that sends and receives the packets. The Server constructor (lines 1937) creates the graphical user interface in which the packets of information will be displayed. Line 30 creates the DatagramSocket in a TRy block. Line 30 uses the DatagramSocket constructor that takes an integer port number argument (5000 in this example) to bind the server to a port where it can receive packets from clients. Clients sending packets to this Server specify the same port number in the packets they send. A SocketException is thrown if the DatagramSocket constructor fails to bind the DatagramSocket to the specified port.
Common Programming Error 24.2
Specifying a port that is already in use or specifying an invalid port number when creating a DatagramSocket results in a SocketException. |
Server method waitForPackets (lines 4068) uses an infinite loop to wait for packets to arrive at the Server. Lines 4748 create a DatagramPacket in which a received packet of information can be stored. The DatagramPacket constructor for this purpose receives two argumentsa byte array in which the data will be stored and the length of the array. Line 50 uses DatagramSocket method receive to wait for a packet to arrive at the Server. Method receive blocks until a packet arrives, then stores the packet in its DatagramPacket argument. The method throws an IOException if an error occurs while receiving a packet.
When a packet arrives, lines 5358 call method displayMessage (declared at lines 8697) to append the packet's contents to the textarea. DatagramPacket method getAddress (line 54) returns an InetAddress object containing the host name of the computer from which the packet was sent. Method getPort (line 55) returns an integer specifying the port number through which the host computer sent the packet. Method getLength (line 56) returns an integer representing the number of bytes of data sent. Method getData (line 57) returns a byte array containing the data. Lines 5758 initialize a String object using a three-argument constructor that takes a byte array, the offset and the length. This String is then appended to the text to display.
After displaying a packet, line 60 calls method sendPacketToClient (declared at lines 7183) to create a new packet and send it to the client. Lines 7779 create a DatagramPacket and pass four arguments to its constructor. The first argument specifies the byte array to send. The second argument specifies the number of bytes to send. The third argument specifies the client computer's Internet address, to which the packet will be sent. The fourth argument specifies the port where the client is waiting to receive packets. Line 81 sends the packet over the network. Method send of DatagramSocket throws an IOException if an error occurs while sending a packet.
Client Class
Class Client (Fig. 24.11) works similarly to class Server, except that the Client sends packets only when the user types a message in a textfield and presses the Enter key. When this occurs, the program calls method actionPerformed (lines 3257), which converts the string the user entered into a byte array (line 41). Lines 4445 create a DatagramPacket and initialize it with the byte array, the length of the string that was entered by the user, the IP address to which the packet is to be sent (InetAddress.getLocalHost() in this example) and the port number at which the Server is waiting for packets (5000 in this example). Line 47 sends the packet. Note that the client in this example must know that the server is receiving packets at port 5000otherwise, the server will not receive the packets.
Note that the DatagramSocket constructor call (line 71) in this application does not specify any arguments. This no-argument constructor allows the computer to select the next available port number for the DatagramSocket. The client does not need a specific port number, because the server receives the client's port number as part of each DatagramPacket sent by the client. Thus, the server can send packets back to the same computer and port number from which it receives a packet of information.
Client method waitForPackets (lines 81107) uses an infinite loop to wait for packets from the server. Line 91 blocks until a packet arrives. This does not prevent the user from sending a packet, because the GUI events are handled in the event-dispatch thread. It only prevents the while loop from continuing until a packet arrives at the Client. When a packet arrives, line 91 stores it in receivePacket, and lines 9499 call method displayMessage (declared at lines 110121) to display the packet's contents in the textarea.
Introduction to Computers, the Internet and the World Wide Web
Introduction to Java Applications
Introduction to Classes and Objects
Control Statements: Part I
Control Statements: Part 2
Methods: A Deeper Look
Arrays
Classes and Objects: A Deeper Look
Object-Oriented Programming: Inheritance
Object-Oriented Programming: Polymorphism
GUI Components: Part 1
Graphics and Java 2D™
Exception Handling
Files and Streams
Recursion
Searching and Sorting
Data Structures
Generics
Collections
Introduction to Java Applets
Multimedia: Applets and Applications
GUI Components: Part 2
Multithreading
Networking
Accessing Databases with JDBC
Servlets
JavaServer Pages (JSP)
Formatted Output
Strings, Characters and Regular Expressions
Appendix A. Operator Precedence Chart
Appendix B. ASCII Character Set
Appendix C. Keywords and Reserved Words
Appendix D. Primitive Types
Appendix E. (On CD) Number Systems
Appendix F. (On CD) Unicode®
Appendix G. Using the Java API Documentation
Appendix H. (On CD) Creating Documentation with javadoc
Appendix I. (On CD) Bit Manipulation
Appendix J. (On CD) ATM Case Study Code
Appendix K. (On CD) Labeled break and continue Statements
Appendix L. (On CD) UML 2: Additional Diagram Types
Appendix M. (On CD) Design Patterns
Appendix N. Using the Debugger
Inside Back Cover