![]() ![]() ![]() ![]() |
All about Datagrams |
The QuoteServer Class
The QuoteServer class contains a single method: themain()
method for the quote server application. Themain()
method simply creates a new QuoteServerThread object and starts it.The QuoteServerThread implements the main logic of the quote server.class QuoteServer { public static void main(String[] args) { new QuoteServerThread().start(); } }The QuoteServerThread Class
The QuoteServerThread is a Thread which runs continuously waiting for requests over a datagram socket.QuoteServerThread has two private instance variables. The first, named
socket
, is a reference to a DatagramSocket object. This variable is initialized to null. The second,qfs
, is a DataInputStream object that is opened onto an ASCII text file containing a list of quotes. Whenever a request for a quote arrives in the server, the server retrieves the next line from this input stream.When the main program creates the QuoteServerThread it uses the only constructor available:
The first line of this constructor calls the super class (Thread) constructor to initialize the Thread with the name "QuoteServer". The next section of code is the critical part of the QuoteServerThread constructor--it creates a DatagramSocket. The QuoteServerThread uses this DatagramSocket to listen for and respond to client requests for a quote.QuoteServerThread() { super("QuoteServer"); try { socket = new DatagramSocket(); System.out.println("QuoteServer listening on port: " + socket.getLocalPort()); } catch (java.net.SocketException e) { System.err.println("Could not create datagram socket."); } this.openInputFile(); }The socket is created using the DatagramSocket constructor that requires no arguments:
When created using this constructor, the new DatagramSocket binds to any locally available port. The DatagramSocket class has another constructor that allows you to specify the port that you want the new DatagramSocket to bind to. You should note that certain ports are dedicated to "well-known" services and you cannot use them. If you specify a port that is in use, the creation of the DatagramSocket will fail.socket = new DatagramSocket();After the DatagramSocket is successfully created the QuoteServerThread displays a message indicating which port the DatagramSocket is bound to. The QuoteClient needs this port number to construct datagram packets destined for this port. So, you must use this port number when running the QuoteClient.
The last line of the QuoteServerThread constructor calls a private method,
openInputFile()
, within QuoteServerThread to open a file namedone-liners.txt
that contains a list of quotes. Each quote in the file must be on a line by itself.Now for the interesting part of the QuoteServerThread--its
run()
method. (Therun()
method overridesrun()
in the Thread class and provides the implementation for the thread. For information about Threads, see Threads of Control.
QuoteServerThread's
run()
method first checks to verify that a valid DatagramSocket was created during construction. Ifsocket
is null, then the QuoteServerThread could not bind to the DatagramSocket. Without the socket, the server cannot operate, and therun()
method returns.Otherwise, the
run()
method enters into an infinite loop. The infinite loop is contiously waiting for requests from clients and responding to those requests. There are two critical sections of code within this loop: the section that listens for requests and the section that responds to them. Let's look at first at the section that receives requests:The first line of code creates a new DatagramPacket object intended to receive a datagram message over the datagram socket. You can tell that the new DatagramPacket is intended to receive data from the socket because of the constructor used to create it. This constructor requires only two arguments: a byte array which will contain client-specific data and the length of the byte array. When constructing a DatagramPacket to send over the DatagramSocket, you must also supply the internet address and port number of the destination of the packet. You'll see this later when we discuss how the server responds to a client request.packet = new DatagramPacket(buf, 256); socket.receive(packet); address = packet.getAddress(); port = packet.getPort();The second line of code in the above code snippet receives a datagram from the socket. The information contained within the datagram message gets copied into the packet created on the previous line. The
receive()
blocks forever until a packet is received. If no packet is received, the server makes no further progress and just waits.The next two lines gets the internet address and the port number from the datagram packet. The internet address and port number indicate where the datagram packet initiated. This is where the server must repond to. The byte array of this datagram packet contains no relevant information. Just the arrival of the packet itself indicates a request from a client who can be found at the internet address and port number attached to the datagram packet.
At this point, the server has received a request from a client for a quote. Now, the server must respond. The next six lines of code construct the response and send it.
If the quote file did not get opened for some reason, thenif (qfs == null) dString = new Date().toString(); else dString = getNextQuote(); dString.getBytes(0, dString.length(), buf, 0); packet = new DatagramPacket(buf, buf.length, address, port); socket.send(packet);qfs
will be null. If this is true, the quote server serves up the time of day instead. Otherwise, the quote server gets the next quote from the already opened file. The line of code following theif
statement converts the string to an array of bytes.The third line of code creates a new DatagramPacket object intended for sending a datagram message over the datagram socket. You can tell that the new DatagramPacket is intended to send data over the socket because of the constructor used to create it. This constructor requires four arguments. The first two arguments are the same required by the constructor used to create receiving datagrams: a byte array containing the mesage from the sender to the receiver, and the length of this array. The next two arguments are different: an internet address and a port number. These two arguments are the complete address of the destination of the datagram packet and must be supplied by the sender of the datagram.
The fourth line of code sends the DatagramPacket on its way. The
send()
method uses the destination address from the datagram packet to route the datagram packet correctly.The last method of interest in the QuoteServerThread is the
finalize()
method. This method cleans up when the QuoteServerThread is garbage collected by closing the DatagramSocket. Ports are limited resources and sockets bound to ports should be closed when not in use.The QuoteClient Class
The QuoteClient class implements a client application for the QuoteServer. This application simply sends a request to the QuoteServer, waits for the response, and when the response is received displays it to the standard output. Let's look at the code in detail.The QuoteClient class contains one method--the
main()
method for the client application. The top of themain()
declares several local variables for its use:The next section of code processes the command line arguments used to invoke the QuoteClient application.int port; InetAddress address; DatagramSocket socket; DatagramPacket packet; byte[] sendBuf = new byte[256];The QuoteClient application requires two command line arguments: the name of the machine that the QuoteServer is running on, and the port that the QuoteServer is listening to. When you start the QuoteServer it will display a port number. This is the port number you must use on the command line when starting up the QuoteClient.if (args.length != 2) { System.out.println("Usage: java DatagramClient <hostname> <port#>"); return; }Next, the
main()
method contains atry
block that contains the main logic of the client program. Thistry
block contains three main sections: a section that creates a DatagramSocket, a section that sends a request to the server, and a section that gets the response from the server.First, let's look at the code that creates a DatagramSocket:
The client uses the same constructor to create a DatagramSocket as the server. The DatagramSocket is bound to any available local port. Note that this is different than using Sockets. When communicating through sockets, connecting to the server at the other end is done by establishing a connection between the sockets at either end. When communicating through DatagramSockets the DatagramPacket contains the internet address and port number of the destination of the packet itself.socket = new DatagramSocket();Next, the QuoteClient program sends a request to the server:
The first line of code gets the internet address for the host named on the command line. The second line of code gets the port number from the command line. These two pieces of information are used to create a DatagramPacket destined for that internet address and port number. The internet address and port number should indicate the machine you started the server on and the port that the server is listening to.address = InetAddress.getByName(args[0]); port = Integer.parseInt(args[1]); packet = new DatagramPacket(sendBuf, 256, address, port); socket.send(packet); System.out.println("Client sent request packet.");The third line in the previous code snippet creates a DatagramPacket intended for sending data. The packet is constructed with an empty byte array, its length, and the internet address and port number for the destination of the packet. The byte array is empty because this datagram packet is simply a request to the server for information. All the server needs to know to reply, the address and port number to reply to, is automatically part of the packet.
Next, the client gets a response from the server:
To get a response from the server, the client creates a "receive packet" and uses the DatagramSocketpacket = new DatagramPacket(sendBuf, 256); socket.receive(packet); String received = new String(packet.getData(), 0); System.out.println("Client received packet: " + received);receive()
to get a reply from the server. Thereceive()
blocks forever until a datagram packet destined for the client comes through the socket. Note that if the server's reply is somehow lost the client will block forever because of the no guarantee policy of the datagram model. The client should probably set a timer so that it doesn't wait forever for a reply.When the client does receive a reply from the server, the client uses the
getData()
method to retrieve that data from the packet. The client converts the data to a string and displays it.Run the Server
After you've successfully compiled the server and the client programs you can run them. You have to run the server program first because you need the port number that it displays before you can start the client. When the server has successfully bound to its DatagramSocket, it will display a message similar to this one:QuoteServer listening on port: portNumberportNumber
is the number of the port that the server's DatagramSocket is bound to. Use this number to start the client.Run the Client
Once the server has started and displayed a message indicating which port its listening to, you can run the client program. Remember to run the client program with two command line arguments: the name of the host on which the QuoteServer is running, and the port number that it displayed on start up.After the client has sent a request and received a response from the server, you should see output similar to this:
Client sent request packet. Client received packet: Sun Feb 18 15:40:34 PST 1996Security Considerations
Please note that communications over a DatagramSocket are subject to approval by the current security manager. The two example programs are stand-alone applications that get the default security manager which implements a lenient security policy. If you were to convert these applications to applets they may be unable to communicate over a DatagramSocket depending on the browser or viewer they were running in.See Providing Your Own Security Manager
for general information about security managers. Also, see Understanding Applet Capabilities and Restrictions
for information about the security restrictions placed on applets.
See also
java.net.DatagramPacket
java.net.DatagramSocket
![]() ![]() ![]() ![]() |
All about Datagrams |