Applications often need to access networks to acquire resources (such as images) or to communicate with remote executable entities (such as web services). A network is a group of interconnected nodes (computing devices such as tablets, and peripherals such as scanners or laser printers) that can be shared among the network’s users.
Intranets (networks within an organization) and internets often use TCP/IP (http://en.wikipedia.org/wiki/TCP/IP_model) to communicate between nodes. TCP/IP includes Transmission Control Protocol (TCP) , which is a connection-oriented protocol; User Datagram Protocol (UDP) , which is a connectionless protocol; and Internet Protocol (IP) , which is the basic protocol over which TCP and UDP perform their tasks.
The java.net package provides types that support TCP/IP between processes (executing applications) running on the same or different hosts (computer-based TCP/IP nodes). In this chapter, we first present the types for performing socket-based and URL-based communication. We then present the low-level network interface and interface address types and cookie-oriented types.
Accessing Networks via Sockets
Two processes communicate by way of sockets, which are endpoints in a communications link between these processes. Each endpoint is identified by an IP address that identifies the host and by a port number that identifies the process running on that host.
Network nodes are identified via IP addresses, and a port number specifying a communication channel identifier.
One process writes a message (a sequence of bytes) to its socket. The network management software portion of the underlying platform breaks the message into a sequence of packets (addressable message chunks that are often referred to as IP datagrams) and forwards them to the other process’s socket where they are recombined into the original message for processing.
In the context of Figure 13-1, suppose that Process A wants to send a message to Process B. Process A sends that message to its socket with the destination socket address of Process B. Host A’s network management software (often referred to as a protocol stack ) obtains this message and reduces it to a sequence of packets, with each packet including the destination host’s IP address and port number. The network management software then sends these packets through Host A’s network interface card (NIC) to Host B.
The NIC’s various network interfaces are connections between a computer and a network.
Host B’s protocol stack receives packets through the NIC and reassembles them into the original message (packets may be received out of order), which it then makes available to Process B via its socket. This scenario reverses when Process B communicates with Process A.
The network management software uses TCP to create an ongoing conversation between two hosts in which messages are sent back and forth. Before this conversation occurs, a connection is established between these hosts. After the connection has been established, TCP enters a pattern where it sends message packets and waits for a reply that they arrived correctly (or for a timeout to expire when the reply doesn’t arrive because of some network problem). This pattern repeats and guarantees a reliable connection. For detailed information on this pattern, check out http://en.wikipedia.org/wiki/Tcp_receive_window#Flow_control.
Because it can take time to establish a connection, and it also takes time to send packets (as it is necessary to receive reply acknowledgments and also because of timeouts), TCP is slow. On the other hand, UDP, which doesn’t require connections and packet acknowledgment, is much faster. The downside is that UDP isn’t as reliable (there’s no guarantee of packet delivery, ordering, or protection against duplicate packets, although UDP uses checksums to verify that data is correct) because there’s no acknowledgment. Furthermore, UDP is limited to single-packet conversations.
The java.net package provides Socket, ServerSocket, and other Socket-suffixed classes for performing TCP-based or UDP-based communications. Before investigating these classes, you need to understand socket addresses and socket options.
Socket Addresses
An instance of a Socket-suffixed class is associated with a socket address comprised of an IP address and a port number. These classes often rely on the InetAddress class to represent the IPv4 or IPv6 address portion of the socket address, and represent the port number separately.
InetAddress relies on its Inet4Address subclass to represent an IPv4 address and on its Inet6Address subclass to represent an IPv6 address.
InetAddress declares several class methods for obtaining an InetAddress instance. For details please consult the API documentation for class InetAddress.
The abstract class SocketAddress represents a socket address “with no protocol attachment.” (This class’s creator might have anticipated that Java would eventually support low-level communication protocols other than the widely popular Internet Protocol.)
SocketAddress is subclassed by the concrete InetSocketAddress class, which represents a socket address as an IP address and a port number. It can also represent a hostname and a port number and will make an attempt to resolve the hostname.
InetSocketAddress instances are created by invoking InetSocketAddress(InetAddress addr, int port) and other constructors. After an instance has been created, you can call methods such as InetAddress getAddress() and int getPort() to return socket address components.
Socket Options
IP_MULTICAST_IF specifies the outgoing network interface for multicast packets (on multihomed [multiple NIC] hosts). This option isn’t implemented by Android.
IP_MULTICAST_IF2 specifies the outgoing network interface for multicast packets using an interface index.
IP_MULTICAST_LOOP enables or disables local loopback of multicast datagrams.
IP_TOS sets the type-of-service (IPv4) or traffic class (IPv6) field in the IP header for a TCP or UDP socket.
SO_BINDADDR fetches the socket’s local address binding. This option isn’t implemented by Android.
SO_BROADCAST enables a socket to send broadcast messages.
SO_KEEPALIVE turns on socket keepalive.
SO_LINGER specifies the number of seconds to wait when closing a socket when there is still some buffered data to be sent.
SO_OOBINLINE enables inline reception of TCP urgent data.
SO_RCVBUF sets or gets the maximum socket receive buffer size (in bytes).
SO_REUSEADDR enables a socket’s reuse address.
SO_SNDBUF sets or gets the maximum socket send buffer size (in bytes).
SO_TIMEOUT specifies a timeout (in milliseconds) on blocking accept or read/receive (but not write/send) socket operations. (Don’t block forever!)
TCP_NODELAY disables Nagle’s algorithm (http://en.wikipedia.org/wiki/Nagle's_algorithm). Written data to the network is not buffered pending acknowledgment of previously written data.
void setOption(int optID, Object value)
Object getOption(int optID)
optID is one of the aforementioned constants and value is an object of a suitable class (such as java.lang.Boolean).
SocketOptions is implemented by the abstract SocketImpl and DatagramSocketImpl classes. Concrete instances of these classes are wrapped by the various Socket-suffixed classes. As a result, you cannot invoke these methods. Instead, you work with the typesafe setter and getter methods provided by the Socket-suffixed classes for setting and getting these options.
For example, Socket declares void setKeepAlive(boolean keepAlive) for setting the SO_KEEPALIVE option, and ServerSocket declares void setSoTimeout(int timeout) for setting the SO_TIMEOUT option. Check the documentation on the Socket-suffixed classes to learn about these and other socket option methods.
Socket option methods that apply to DatagramSocket also apply to its MulticastSocket subclass.
Socket and ServerSocket
The Socket and ServerSocket classes support TCP-based communications between client processes (such as an application running on a tablet) and server processes (such as an application running on one of your Internet service provider’s computers that provides access to the World Wide Web). Because Socket is associated with the java.io.InputStream and java.io.OutputStream classes, sockets based on the Socket class are commonly referred to as stream sockets.
After a Socket instance is created, it’s bound to an arbitrary local host socket address before a connection is made to the remote host socket address. Binding makes a client socket address available to a server socket so that a server process can communicate with the client process via the server socket.
After creating a Socket instance, and possibly invoking bind() and connect() on that instance, an application invokes Socket’s InputStream getInputStream() and OutputStream getOutputStream() methods to acquire an input stream for reading bytes from the socket and an output stream for writing bytes to the socket. Also, the application often calls Socket’s void close() method to close the socket when no longer needed for I/O.
ServerSocket supports the creation of server-side sockets. After a server socket is created, a server application enters a loop that first invokes ServerSocket’s Socket accept() method to listen for a connection request and return a Socket instance that lets it communicate with the associated client socket. It then communicates with the client socket to perform some kind of processing. When processing finishes, the server socket calls the client socket’s close() method to terminate its connection with the client.
ServerSocket declares a void close() method for closing a server socket before terminating the server application. An unclosed socket is automatically closed when an application terminates.
The accept() method call blocks until a connection request is available and then returns a Socket object so that the server application can communicate with its associated client. The socket is closed after this communication takes place. The server socket is automatically closed when the application exits.
Each time a connection request arrives, accept() returns a Socket instance, and then a java.lang.Thread object is created whose runnable accesses that socket for communicating with the socket on a worker thread.
Although this example uses the Thread class, you could use an executor (see Chapter 11) instead.
Echoing Data to and Receiving It Back from a Server
EchoClient first verifies that it has received a single command-line argument and then creates a socket that will connect to a process running on port 9999 of the local host.
After creating the socket, EchoClient obtains an output stream for writing a string to the socket. Because the output stream can only handle a sequence of bytes, the java.io.OutputStreamWriter and java.io.PrintWriter classes (see Chapter 12) are used to connect the writer that outputs characters to the byte-oriented output stream.
After instantiating PrintWriter, EchoClient invokes its void println(String str) method to write the string followed by a newline character. The void flush() method is subsequently called to ensure that all pending data is written to the server.
EchoClient now obtains an input stream for reading the string as a sequence of bytes. It then connects the reader (that inputs characters) to the byte-oriented input stream by instantiating java.io.InputStreamReader and java.io.BufferedReader (see Chapter 12).
Finally, EchoClient invokes BufferedReader’s String readLine() method to read the characters followed by a newline from the socket. (readLine() doesn’t include the newline character in the returned string.) These characters followed by a newline are then written to standard output.
In a long-running application, you would explicitly close the socket instance by invoking its void close() method when the socket is no longer needed. For brevity, we’ve chosen not to do so in this and most of the remaining Socket-suffixed class examples.
Receiving Data from and Echoing It Back to a Client
EchoServer first outputs an introductory message to standard output and then creates a server socket that listens for connections on port 9999. It then enters an infinite loop, where each iteration invokes ServerSocket’s Socket accept() method to block until a connection is received and then returns a Socket object representing this connection.
After obtaining the socket, EchoServer obtains an input stream for reading from the socket. Because the input stream can only handle a sequence of bytes, the InputStreamReader and BufferedReader classes are used to connect the reader that inputs characters to the byte-oriented input stream.
EchoServer now obtains an output stream for writing the string as a sequence of bytes. It then connects the writer that outputs characters to the byte-oriented output stream by instantiating OutputStreamWriter and PrintWriter.
After outputting the message to standard output, EchoServer calls flush() to flush the output to the client. The client socket is then closed.
You should observe “This is a test.” in both windows.
DatagramSocket and MulticastSocket
The DatagramSocket and MulticastSocket classes let you perform UDP-based communications between a pair of hosts (DatagramSocket) or between many hosts (MulticastSocket). With either class, you communicate one-way messages via datagram packets, which are arrays of bytes associated with instances of the DatagramPacket class .
Although you might think that Socket and ServerSocket are all that you need, DatagramSocket and its MulticastSocket subclass have their uses. For example, consider a scenario in which a group of machines need to occasionally tell a server that they’re alive. It shouldn’t matter when the occasional message is lost or even when the message doesn’t arrive on time. Another example is a low-priority stock ticker that periodically broadcasts stock prices. When a packet doesn’t arrive, odds are that the next packet will arrive and you’ll then receive notification of the latest prices. Timely rather than reliable or orderly delivery is more important in real-time applications.
DatagramPacket declares several constructors with DatagramPacket(byte[] buf, int length) being the simplest. This constructor requires you to pass byte array and integer arguments to buf and length, where buf is a data buffer that stores data to be sent or received and length (which must be less than or equal to buf.length) specifies the number of bytes (starting at buf[0]) to send/receive.
Additional constructors let you specify an offset into buf that identifies the storage location of the first outgoing or incoming byte, and/or let you specify a destination socket address.
DatagramSocket describes a socket for the client or server side of the UDP-communication link. Although this class declares several constructors, we find it convenient in this chapter to use the DatagramSocket() constructor for the client side and the DatagramSocket(int port) constructor for the server side. Either constructor throws SocketException when it cannot create the datagram socket or bind the datagram socket to a local port.
After an application instantiates DatagramSocket, it calls void send(DatagramPacket dgp) and void receive(DatagramPacket dgp) to send and receive datagram packets.
Receiving Datagram Packets from and Echoing Them Back to Clients
Listing 13-3’s main() method first creates a DatagramSocket object and binds the socket to port 10000 on the local host. It then invokes DatagramSocket’s int getSendBufferSize() and int getReceiveBufferSize() methods to get the values of the SO_SNDBUF and SO_RCVBUF socket options, which are then output.
Sockets are associated with underlying platform send and receive buffers, and their sizes are accessed by calling getSendBufferSize() and getReceiveBufferSize(). Similarly, their sizes can be set by calling DatagramSocket’s void setReceiveBufferSize(int size) and void setSendBufferSize(int size) methods. Although you can adjust these buffer sizes to improve performance, there’s a practical limit with regard to UDP. The maximum size of a UDP packet that can be sent or received is 65,507 bytes under IPv4—it’s derived from subtracting the 8-byte UDP header and 20-byte IP header values from 65,535. Although you can specify a send/receive buffer with a greater value, doing so is wasteful because the largest packet is restricted to 65,507 bytes. Also, attempting to send or receive a packet with a buffer length that exceeds 65,507 bytes results in IOException.
main() next instantiates DatagramPacket in preparation for receiving a datagram packet from a client and then echoing the packet back to the client. It assumes that packets will be 100 bytes or less in size.
Finally, main() enters an infinite loop that receives a packet, outputs packet content, and sends the packet back to the client—the client’s addressing information is stored in DatagramPacket.
Sending a Datagram Packet to and Receiving It Back from a Server
Listing 13-4 is similar to Listing 13-3, but there’s one big difference. We use the DatagramPacket(byte[] buf, int length, InetAddress address, int port) constructor to specify the server’s destination, which happens to be port 10000 on the local host, in the datagram packet. The send() method call routes the packet to this destination.
MulticastSocket describes a socket for the client or server side of a UDP-based multicasting session. Two commonly used constructors are MulticastSocket() (it creates a multicast socket not bound to a port) and MulticastSocket(int port) (it creates a multicast socket bound to the specified port). Either constructor throws IOException when an I/O error occurs.
Previous examples have demonstrated unicasting, which occurs when a server sends a message to a single client. However, it’s also possible to broadcast the same message to multiple clients (such as transmit a “school closed due to bad weather” announcement to all members of a group of parents who have registered with an online program to receive this announcement); this activity is known as multicasting.
A server multicasts by sending a sequence of datagram packets to a special IP address, which is known as a multicast group address , and a specific port (as specified by a port number). Clients wanting to receive those datagram packets create a multicast socket that uses that port number. They request to join the group through a join group operation that specifies the special IP address. At this point, the client can receive datagram packets sent to the group and can even send datagram packets to other group members. After the client has read all datagram packets that it wants to read, it removes itself from the group by applying a leave group operation that specifies the special IP address.
IPv4 addresses 224.0.0.1 to 239.255.255.255 (inclusive) are reserved for use as multicast group addresses.
Accessing Networks via URLs
A Uniform Resource Locator (URL) is a character string that specifies where a resource (such as a web page) is located on a TCP-/IP-based network (such as the Internet). Also, it provides the means to retrieve that resource. For example, http://some.domain.tld is a URL that locates some website’s main page. The http:// prefix specifies that HyperText Transfer Protocol (HTTP) , which is a high-level protocol on top of TCP/IP for locating HTTP resources (such as web pages), must be used to retrieve the web page located at some.domain.tld.
A Uniform Resource Name (URN) is a character string that names a resource and doesn’t provide a way to access that resource (the resource might not be available). For example, urn:isbn:9781430264545 identifies an Apress book named Learn Java for Android Development and that’s all.
URNs and URLs are examples of Uniform Resource Identifiers (URIs) , which are character strings for identifying names (URNs) and resources (URLs). Every URN and URL is also a URI.
The java.net package provides URL and URLConnection classes for accessing URL-based resources. It also provides URLEncoder and URLDecoder classes for encoding and decoding URLs as well as the URI class for performing URI-based operations (such as relativization) and returning URL instances containing the results.
URL and URLConnection
The URL class represents URLs and provides access to the resources to which they refer. Each URL instance unambiguously identifies an Internet resource.
This example creates a URL object that uses HTTP to access the web page at http://example.com. If we specified an illegal URL (such as foo), the constructor would throw MalformedURLException (an IOException subclass).
The jar: prefix indicates that you want to access a JAR file resource (such as a stored class file). The file:/// prefix identifies the local host’s resource location.
The path to the JAR file is followed by an exclamation mark (!) to separate the JAR file path from the JAR resource path, which happens to be the /some/package/SomeClass class file entry in this JAR file (the leading / character is required).
The URL class in Oracle’s Java reference implementation supports additional protocols, including ftp.
After creating a URL object, you can invoke various URL methods to access portions of the URL. For example, String getProtocol() returns the protocol portion of the URL (such as http). You can also retrieve the resource by calling the InputStream openStream() method.
For an HTTP connection, an internal socket is created that connects to HTTP port 80 on the server identified via the URL’s domain name/IP address, unless you append a different port number to the domain name/IP address (such as http://example.com:8080).
Listing the Contents of the Resource Identified via a URL Command-Line Argument
ListResource first verifies that it has received a single command-line argument and then attempts to instantiate URL with this argument. Assuming that the URL is valid, which means that MalformedURLException isn’t thrown, ListResource calls openStream() on the URL instance and proceeds to list the resource contents to standard output.
openStream() is a convenience method for invoking openConnection().getInputStream(). Each of URL’s URLConnection openConnection() and URLConnection openConnection(Proxy proxy) methods returns an instance of the URLConnection class, which represents a communications link between the application and a URL.
URLConnection gives you additional control over client/server communication. For example, you can use this class to output content to various resources that accept content. In contrast, URL only lets you input content via openStream().
URLConnection is subclassed by HttpURLConnection and JarURLConnection. These classes declare constants and/or methods that are specific to working with the HTTP protocol or interacting with JAR-based resources.
For example, HttpURLConnection declares void setRequestMethod(String method) for specifying the HTTP request command to be sent to a remote HTTP server. GET and POST are commonly specified commands.
URLEncoder and URLDecoder
HyperText Markup Language (HTML) lets you introduce forms into web pages that solicit information from page visitors. After filling out a form’s fields, the visitor clicks the form’s Submit button (which may specify something other than Submit), and the form content (field names and values) is sent to a server program. Before sending the form content, a web browser encodes this data by replacing spaces and other URL-illegal characters and sets the content’s Internet media type (also known as Multipurpose Internet Mail Extensions [MIME] type) to application/x-www-form-urlencoded.
The data is encoded for HTTP POST and HTTP GET operations. Unlike POST, GET requires a query string (a ?-prefixed string containing the encoded content) to be appended to the server program’s URL.
The java.net package provides URLEncoder and URLDecoder classes to assist you with the tasks of encoding and decoding form content.
URLEncoder applies the following encoding rules:
Alphanumeric characters (a–z, A–Z, and 0–9) remain the same.
Special characters “.”, “-”, “*”, and “_” remain the same.
The space character “ ” is converted into a plus sign “+”.
All other characters are unsafe and are first converted into 1 or more bytes using some encoding scheme. Each byte is then represented by the three-character string %xy, where xy is the two-digit hexadecimal representation of that byte. The recommended encoding scheme to use is UTF-8. However, for compatibility reasons, the platform’s default encoding is used when an encoding isn’t specified.
For example, using UTF-8 as the encoding scheme, the string "string ü@foo-bar" is converted to "string+%C3%BC%40foo-bar". In UTF-8, character ü is encoded as 2 bytes C3 (hex) and BC (hex); and character @ is encoded as 1 byte 40 (hex).
This method translates the String argument passed to s into application/x-www-form-urlencoded format using the encoding scheme specified by enc. It uses the supplied encoding scheme to obtain the bytes for unsafe characters and throws java.io.UnsupportedEncodingException when enc’s value isn’t supported.
Alphanumeric characters (a–z, A–Z, and 0–9) remain the same.
Special characters “.”, “-”, “*”, and “_” remain the same.
The plus sign “+” is converted into a space character “ ”.
A sequence of the form %xy will be treated as representing a byte, where xy is the two-digit hexadecimal representation of the 8 bits. Then, all substrings containing one or more of these byte sequences consecutively will be replaced by the character(s) whose encoding would result in those consecutive bytes. The encoding scheme used to decode these characters may be specified; when unspecified, the platform’s default encoding is used.
This method decodes an application/x-www-form-urlencoded string using the encoding scheme specified by enc. The supplied encoding is used to determine what characters are represented by any consecutive sequences of the form %xy. UnsupportedEncodingException is thrown when enc’s value isn’t supported.
There are two possible ways in which the decoder could deal with illegally encoded strings. It could either leave illegal characters alone or it could throw IllegalArgumentException. The approach the decoder takes is left to the implementation.
The World Wide Web Consortium recommends that UTF-8 should be used as the encoding scheme for encode() and decode(); see www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars. Not doing so may introduce incompatibilities.
Encoding and Decoding an Encoded String
Check out Wikipedia’s “Percent-encoding” topic (http://en.wikipedia.org/wiki/Percent-encoding) to learn more about URL encoding (and the more accurate percent-encoding term).
URI
The URI class represents URIs (such as URNs and URLs). It doesn’t provide access to a resource when the URI is a URL.
This syntax reveals that every URI optionally begins with a scheme followed by a colon character, where a scheme can be thought of as an application-level protocol for obtaining an Internet resource. However, this definition is too narrow because it implies that the URI is always a URL. A scheme can have nothing to do with resource location. For example, urn is the scheme for identifying URNs.
A scheme is followed by a scheme-specific-part that provides an instance of the scheme. For example, given the http://tutortutor.ca URI, tutortutor.ca is an instance of the http scheme. Scheme-specific-parts conform to the allowable syntax of their schemes and to the overall syntax structure of a URI (including what characters can be specified literally and what characters must be encoded).
A scheme concludes with an optional #-prefixed fragment level, which is a short string of characters that refers to a resource subordinate to another primary resource. The primary resource is identified by a URI; the fragment points to the subordinate resource. For example, http://example.com/document.txt#line=5,10 could identify lines 5 through 10 of a text document named document.txt on some website.
For more details, please consult the API documentation of class URI.
Accessing Network Interfaces and Interface Addresses
The NetworkInterface class represents a network interface in terms of a name (such as le0) and a list of IP addresses assigned to this interface. Although a network interface is often implemented on a physical NIC, it also can be implemented in software, for example, the loopback interface (which is useful for testing a client).
Enumerating All Network Interfaces
The java.util.Collections class’s ArrayList<T> list(Enumeration<T> enumeration) method is useful for converting a legacy enumeration to a modern array list.
The complete output reveals a different MTU size for a few network interfaces. Each size represents the maximum length of a message that can fit into an IP datagram without needing to fragment the message into multiple IP datagrams. This fragmentation has performance implications, especially in the context of networked games. For this reason alone, the getMTU() method is a valuable member of NetworkInterface.
The getInterfaceAddresses() method returns a list of InterfaceAddress objects, with each object containing a network interface’s IP address along with broadcast address and subnet mask (IPv4) or network prefix length (IPv6).
Enumerating All Network Interfaces and Interface Addresses
Managing Cookies
Server applications commonly use HTTP cookies (state objects)—cookies for short—to persist small amounts of information on clients. For example, the identifiers of currently selected items in a shopping cart can be stored as cookies. It’s preferable to store cookies on the client rather than on the server because of the potential for millions of cookies (depending on a website’s popularity). In that case, not only would a server require a massive amount of storage just for cookies, but also searching for and maintaining cookies would be time-consuming.
Check out Wikipedia’s “HTTP cookie” entry (http://en.wikipedia.org/wiki/HTTP_cookie) for a quick refresher on cookies.
A server application sends a cookie to a client as part of an HTTP response. A client (such as a web browser) sends a cookie to the server as part of an HTTP request. Before Java 5, applications worked with the URLConnection class (and its HttpURLConnection subclass) to get an HTTP response’s cookies and to set an HTTP request’s cookies. The String getHeaderFieldKey(int n) and String getHeaderField(int n) methods were used to access a response’s Set-Cookie headers, and the void setRequestProperty(String key, String value) method was used to create a request’s Cookie header.
“RFC 2109: HTTP State Management Mechanism” (www.ietf.org/rfc/rfc2109.txt) describes the Set-Cookie and Cookie headers.
Java 5 introduced the abstract CookieHandler class as a callback mechanism that connects HTTP state management to an HTTP protocol handler (think concrete HttpURLConnection subclass). An application installs a concrete CookieHandler subclass as the system-wide cookie handler via the CookieHandler class’s void setDefault(CookieHandler cHandler) class method. A companion CookieHandler getDefault() class method returns this cookie handler, which is null when a system-wide cookie handler hasn’t been installed.
An HTTP protocol handler accesses response and request headers. This handler invokes the system-wide cookie handler’s void put(URI uri, Map<String, List<String>> responseHeaders) method to store response cookies in a cookie cache and invokes the Map<String, List<String>> get(URI uri, Map<String, List<String>> requestHeaders) method to fetch request cookies from this cache. Unlike Java 5, Java 6 introduced a concrete implementation of CookieHandler so that HTTP protocol handlers and applications can work with cookies.
The concrete CookieManager class extends CookieHandler to manage cookies. This class does not interact with the web browser’s cookies (stored on the client computer). Instead, it represents a separate and distinct cookie manager.
With a cookie store for storing cookies. The cookie store is based on the CookieStore interface.
With a cookie policy for determining which cookies to accept for storage. The cookie policy is based on the CookiePolicy interface.
Listing All Cookies for a Specific Domain
Listing 13-9 describes a command-line application that obtains and lists all cookies from its single domain name argument. After creating a cookie manager and invoking setCookiePolicy() to set the cookie manager’s policy to accept all cookies, ListAllCookies installs the cookie manager as the system-wide cookie handler. It next connects to the domain identified by the command-line argument and reads the content (via URL’s Object getContent() method).
The cookie store is obtained via getCookieStore() and used to retrieve all nonexpired cookies via its List<HttpCookie> getCookies() method. For each of these HttpCookies, String getName(), String getValue(), and other HttpCookie methods are invoked to return cookie-specific information.
For more information about cookie management, including examples that show you how to create your own CookiePolicy and CookieStore implementations, check out The Java Tutorials’ “Working With Cookies” lesson (http://docs.oracle.com/javase/tutorial/networking/cookies/index.html).
- 1.
Define network.
- 2.
What is an intranet and what is an internet?
- 3.
What do intranets and internets often use to communicate between nodes?
- 4.
Define host.
- 5.
What is a socket?
- 6.
How is a socket identified?
- 7.
Define IP address.
- 8.
What is a packet?
- 9.
A socket address is comprised of what elements?
- 10.
Identify the InetAddress subclasses that are used to represent IPv4 and IPv6 addresses.
- 11.
What is the loopback interface?
- 12.
How is the local host represented?
- 13.
Why are sockets based on the Socket class commonly referred to as stream sockets?
- 14.
What does binding accomplish in the context of a Socket instance?
- 15.
Define proxy. How does Java represent proxy settings?
- 16.
True or false: The ServerSocket() constructor creates a bound sever socket.
- 17.
What is the difference between the DatagramSocket and MulticastSocket classes?
- 18.
What is the difference between unicasting and multicasting?
- 19.
What is a URL?
- 20.
What is a URN?
- 21.
True or false: URLs and URNs are also URIs.
- 22.
What is the equivalent of openStream()?
- 23.
True or false: You need to invoke URLConnection’s void setDoInput(boolean doInput) method with true as the argument before you can input content from a web resource.
- 24.
What does URLEncoder do when it encounters a space character?
- 25.
What is the purpose of the URI class?
- 26.
What does the NetworkInterface class accomplish?
- 27.
What is a MAC address?
- 28.
What does MTU stand for and what is its purpose?
- 29.
True or false: NetworkInterface’s getName() method returns a human-readable name.
- 30.
What does InterfaceAddress’s getNetworkPrefixLength() method return under IPv4?
- 31.
Define HTTP cookie.
- 32.
Why is it preferable to store cookies on the client rather than on the server?
- 33.
Identify the four java.net types that are used to work with cookies.
- 34.
Modify Listing 13-1’s EchoClient source code to explicitly close the socket.
- 35.
Modify Listing 13-2’s EchoServer source code to exit the while loop and explicitly close the server socket when a file named kill appears in the directory from which the server was started. After this file appears, the server will probably not die immediately because it’s most likely waiting (via the accept() call) for an incoming client connection. However, it should die after servicing the next incoming connection.
Summary
A network is a group of interconnected nodes that can be shared among the network’s users. An intranet is a network located within an organization and an internet is a network connecting organizations to each other. The Internet is the global network of networks.
The java.net package provides types that support TCP/IP between processes running on the same or different hosts. Two processes communicate by way of sockets, which are endpoints in a communications link between these processes. Each endpoint is identified by an IP address that identifies a host and by a port number that identifies the process running on that host.
One process writes a message to its socket, the network management software portion of the underlying operating system breaks the message into a sequence of packets that it forwards to the other process’s socket, and the other process recombines received packets into the original message for its own processing.
The network management software uses TCP to create an ongoing conversation between two hosts in which messages are sent back and forth. Before this conversation occurs, a connection is established between these hosts. After the connection has been established, TCP enters a pattern where it sends message packets and waits for a reply that they arrived correctly (or for a timeout to expire when the reply doesn’t arrive because of some network problem). This pattern repeats and guarantees a reliable connection.
Because it can take time to establish a connection, and it also takes time to send packets (as it is necessary to receive reply acknowledgments, and also because of timeouts), TCP is slow. On the other hand, UDP, which doesn’t require connections and packet acknowledgment, is much faster. The downside is that UDP isn’t as reliable (there’s no guarantee of packet delivery, ordering, or protection against duplicate packets, although UDP uses checksums to verify that data is correct) because there’s no acknowledgment. Furthermore, UDP is limited to single-packet conversations.
An instance of a Socket-suffixed class is associated with a socket address comprised of an IP address and a port number. These classes often rely on the InetAddress class to represent the IPv4 or IPv6 address portion of the socket address, and represent the port number separately.
An instance of a Socket-suffixed class shares the concept of socket options, which are parameters for configuring socket behavior. Socket options are described by constants that are declared in the SocketOptions interface.
The Socket and ServerSocket classes support TCP-based communications between client processes and server processes. Socket supports the creation of client-side sockets, whereas ServerSocket supports the creation of server-side sockets.
The DatagramSocket and MulticastSocket classes let you perform UDP-based communications between a pair of hosts (DatagramSocket) or between as many hosts as necessary (MulticastSocket). With either class, you communicate one-way messages via datagram packets.
Two processes communicating via sockets demonstrate low-level network access. Java also supports high-level access via URLs that identify resources and specify where they are located on TCP-/IP-based networks.
URLs are represented by the URL class, which provides access to the resources to which they refer. URLConnection gives you additional control over client/server communication. For example, you can use this class to output content to various resources that accept content. In contrast, URL only lets you input content via openStream().
HTML lets you introduce forms into web pages that solicit information from page visitors. The java.net package provides URLEncoder and URLDecoder classes to assist you with the tasks of encoding and decoding form content.
URLs are a form of URI, which is a character string that identifies a resource without providing access to the resource or identifies a name. URIs are represented by the URI class, which provides methods for extracting parts of a URI (such as the scheme) and for performing normalization, resolution, and relativization operations.
The NetworkInterface class represents a network interface in terms of a name (such as le0) and a list of IP addresses assigned to this interface. NetworkInterface’s getInterfaceAddresses() method returns a list of InterfaceAddress objects, with each object containing a network interface’s IP address along with broadcast address and subnet mask (IPv4) or network prefix length (IPv6).
Server applications commonly use HTTP cookies (state objects)—cookies, for short—to persist small amounts of information on clients. Java provides the CookieHandler and CookieManager classes and the CookiePolicy and CookieStore interfaces for working with cookies.
This chapter focused on I/O in a network context. New I/O lets you perform file-based and network-based I/O in a more performant manner. Chapter 14 introduces you to Java’s new I/O APIs.