TCP/IP Sockets in Java. Practical Guide for Programmers. A volume in The Morgan Kaufmann Series in Data Management Systems. Book • 2nd Edition • TCP/IP Sockets in Java Second Edition The Morgan Kaufmann Practical Guides destPort); // Create a voting message (2nd param false = vote) VoteMsg vote. The networking capabilities of the Java platform have been extended considerably since the first edition of the book. This new edition covers version 1.
|Language:||English, Spanish, Hindi|
|Genre:||Academic & Education|
|ePub File Size:||21.39 MB|
|PDF File Size:||13.73 MB|
|Distribution:||Free* [*Sign up for free]|
OLD - various codes, samples etc. Contribute to chrisbst35/various-codes development by creating an account on GitHub. TCP/IP Sockets in Java, Second Edition: Practical Guide for Programmers edition (February 22, ); Paperback pages; eBook PDF ( pages, MB). TCP/IP Sockets in Java. 2nd Edition. Practical Guide for Programmers. 0 star rating Write a review. Authors: Kenneth Calvert Michael Donahoo. eBook ISBN.
Please Note: Deliveries of items with this status cannot be tracked. When will my order arrive? The Estimate Delivery Date is when your order is expected to arrive at your chosen delivery location. Once you have submitted your order you will receive confirmation and status update emails. If you order multiple items and they are not all in stock, we will advise you of their anticipated arrival times.
We saw one of these in Section 2. Using that ability, we can encode the values of other larger primitive integer types. One is the size in bytes of each integer to be transmitted.
For example, an int value in a Java program is represented as a bit quantity. We can therefore transmit the value of any variable or constant of type int using four bytes.
Values of type short, on the other hand, are represented using 16 bits and so only require two bytes to transmit, while longs are 64 bits or eight bytes. We need a total of 15 bytes: Not quite.
For types that require more than one byte, we have to answer the question of which order to send the bytes in. There are two obvious choices: Note that the ordering of bits within bytes is, fortunately, handled by the implementation in a standard way. Consider the long value L. Its bit representation in hexadecimal is 0xFB1. If we transmit the bytes in big-endian order, the sequence of decimal byte values will look like this: One last detail on which the sender and receiver must agree: Chapter 5 contains further details about this class.
Sending and Receiving Data it represents 4, , , Because Java does not support unsigned integer types, encoding and decoding unsigned numbers in Java requires a little care. Assume for now that we are dealing with signed integer types. So how do we get the correct values into the byte array of the message? The program BruteForceCoding. If we encode at the sender, we must be able to decode at the receiver.
SIZE; Short. SIZE; Integer. SIZE; Long. Untested preconditions e. Data items to encode: Numbers of bytes in Java integer primitives: BYTEMASK keeps the byte value from being sign-extended when it is converted to an int in the call to append , thus rendering it as an unsigned integer. Sending and Receiving Data 4. The resulting value is then cast to the type byte, which throws away all but the low-order eight bits, and placed in the array at the appropriate location.
This is iterated over size bytes of the given value, val. Demonstrate methods: If we place the return value into a long, it simply becomes the last byte of a long, producing a value of Which answer is correct depends on your application. If you expect a signed value from decoding N bytes, you must place the long result in a primitive integer type that uses exactly N bytes.
Can you name any others? Running the program produces output showing the following decimal byte values: It would be even worse if the encodeIntBigEndian method were not factored out as a separate method. For that reason, it is not the recommended approach, because Java provides some built-in mechanisms that are easier to use. Note that it does have 3. The ByteArrayOutputStream class takes the sequence of bytes written to a stream and converts it to a byte array.
The code for building our message looks like this: So much for the sending side. How does the receiver recover the transmitted values?
Finally, essentially everything in this subsection applies also to the BigInteger class, which supports arbitrarily large integers.
However, this defeats the purpose of using a BigInteger, which can be arbitrarily large. Text is convenient because humans are accustomed to dealing with all kinds of information represented as strings of characters in books, newspapers, and on computer displays.
Thus, once we know how to encode text for transmission, we can send almost any other kind of data: Obviously we can represent numbers and boolean values as Strings—for example "", "6.
Alas, there is more to it than that. In fact every String instance corresponds to a sequence array of characters type char[ ]. A char value in Java is represented internally as an integer.
The character "X" corresponds to 88, and the symbol "! A mapping between a set of symbols and a set of integers is called a coded character set. ASCII maps the letters of the English alphabet, digits, punctuation and some other special non-printable symbols to integers between 0 and It has been used for data transmission since the s, and is used extensively in application protocols such as HTTP the protocol used for the World Wide Web , even today.
Java therefore uses an international standard coded character set called Unicode to represent values of type char and String.
So sender and receiver have to agree on a mapping from symbols to integers in order to communicate using text messages. Is that all they need to agree on? It depends. For a small set of characters with no integer value larger than , nothing more is needed because each character can be encoded as a single byte. For a code that may use larger integer values that require more than a single byte to represent, there is more than one way to encode those values on the wire.
Thus, sender and receiver need to agree on how those integers will be represented as byte sequences—that is, an encoding scheme. The combination of a coded character set and a character encoding scheme is called a charset see RFC Java provides support for the use of arbitrary charsets, and every implementation is required to support at least the following: When you invoke the getBytes method of a String instance, it returns a byte array containing the String encoded according to the default charset for the platform.
To ensure that a string is encoded using a particular charset, you simply supply the name of the charset as a String argument to the getBytes method. The resulting byte array contains the representation of the string in the given encoding. If you call "Test! From "Test! The easiest way for them to do that is to simply specify one of the standard charsets.
Encoding Booleans Bitmaps are a very compact way to encode boolean information, which is often used in protocols. The idea of a bitmap is that each of the bits of an integer type can encode one boolean value— typically with 0 representing false, and 1 representing true. In general, the int value that has a 1 in bit position i, and a zero in all other bit positions, is just 2i.
So bit 5 is represented by 32, bit 12 by , etc. Here are some example mask declarations: Sending and Receiving Data To clear a particular bit, bitwise-AND it with the bitwise complement of the mask for that bit which has ones everywhere except the particular bit, which is zero.
We can then wrap that instance in a DataOutputStream to send primitive data types. We would code this composition as follows: Stream composition. Table 3. Framing refers to the problem of enabling the receiver to locate the beginning and end of a message. Whether information is encoded as text, as multibyte binary numbers, or as some combination of the two, the application protocol must specify how the receiver of a message can determine when it has received all of the message.
Of course, if a complete message is sent as the payload of a DatagramPacket, the problem is trivial: For messages sent over TCP sockets, however, the situation can be more complicated because TCP has no notion of message boundaries. However, when the message can vary in length—for example, if it contains some variable-length arbitrary text strings—we do not know beforehand how many bytes to read. If a receiver tries to receive more bytes from the socket than were in the message, one of two things can happen.
If no other message is in the channel, the receiver will block and be prevented from processing the message; if the sender is also blocked waiting for a reply, the result will be deadlock. Therefore framing is an important consideration when using TCP sockets. However, it is simplest, and also leads to the cleanest code, if you deal with these two problems separately: Here we focus on framing complete messages. The end of the message is indicated by a unique marker, an explicit byte sequence that the sender transmits immediately following the data.
The marker must be known not to occur in the data. A special case of the delimiter-based method can be used for the last message sent on a TCP connection: After the receiver reads the last byte of the message, it receives an end-of-stream indication i.
The delimiter-based approach is often used with messages encoded as text: The receiver simply scans the input as characters looking for the delimiter sequence; it returns the character string preceding the delimiter.
The downside of such techniques is that both sender and receiver have to scan the message. The upper bound on the message length determines the number of bytes required to encode the length: It has two methods: The nextMsg method scans the stream until it reads the delimiter, then returns everything up to the delimiter; null is returned if the stream is empty. ByteArrayOutputStream; java. EOFException; java. The class LengthFramer.
The sender determines the length of the given message and writes it to the output stream as a two-byte, big-endian integer, followed by the complete message. On the receiving side, we use a DataInputStream to be able to read the length as an integer; the readFully method blocks until the given array is completely full, which is exactly what we need here.
Note that, with this framing method, the sender does not have to inspect the content of the message being framed; it needs only to check that the message does not exceed the length limit. DataInputStream; java. Note that this value is too big to store in a short, so we write it a byte at a time. RMI lets you invoke methods on different Java virtual machines, hiding all the messy details of argument encoding and decoding. Serialization handles conversion of actual Java objects to byte sequences for you, so you can transfer actual instances of Java objects between virtual machines.
These capabilities might seem like communication Nirvana, but in reality they are not always the best solution, for several reasons. For example, the serialized form of an object generally includes information that is meaningless outside the context of the Java Virtual Machine JVM. Voting protocol. Sending and Receiving Data a candidate ID, which is an integer between 0 and Two types of requests are supported. An inquiry asks the server how many votes have been cast for the given candidate.
The server sends back a response message containing the original candidate ID and the vote total as of the time the request was received for that candidate.
A voting request actually casts a vote for the indicated candidate. The server again responds with a message containing the candidate ID and the vote total which now includes the vote just cast. For our simple example, the messages sent by client and server are very similar.
In this case, we can get away with a single class for both kinds of messages. The VoteMsg. A VoteMsgCoder provides the methods for vote message serialization and deserialization. Our purpose here is to emphasize that the abstract representation is independent of the details of the encoding.
Then comes the candidate ID, followed by the vote count, both encoded as decimal strings. ByteArrayInputStream; java. InputStreamReader; java. This illustrates a very important point about implementing protocols: In this case, the fromWire method throws an exception if the expected string is not present.
This little bit of redundancy provides the receiver with a small degree of assurance that it is receiving a proper voting message. The second byte of the message always contains zeros, and the third and fourth bytes contain the candidateID. DataOutputStream; java. The encoding method takes advantage of the fact that the high-order two bytes of a valid candidateID are always zero.
Note also the use of bitwise-or operations to encode the booleans using a single bit each. Receiving, of course, does things in the opposite order. We begin by implementing a service for use by vote servers.
When a vote server receives a vote message, it handles the request by calling the handleRequest method of VoteService. HashMap; import java.
Create map of candidate ID to vote count: For votes, the incremented vote count is stored back in the map. If the candidate ID does not already exist in the map, set the count to 0. OutputStream; import java. Socket; 3. Process arguments: Create socket, get output stream: Create binary coder and length-based framer: We elect to use a binary encoder for our protocol. Next, since TCP is a stream-based service, we need to provide our own framing.
Create and send messages: Get and parse responses: Here the server repeatedly accepts a new client connection and uses the VoteService to generate responses to the client vote messages. ServerSocket; import java. Establish coder and vote service for server: Repeatedly accept and handle client connections: Encode, frame, and send the returned response message. For UDP, we use the text encoding for our messages; however, this can be easily changed, as long as client and server agree. Setup DatagramSocket and connect: Create vote and coder: Send request to the server: Receive, decode, and print server response: Of course, when we decode the datagram, we only use the actual bytes from the datagram so we use Arrays.
Repeatedly accept and handle client vote messages: We saw examples of both text-oriented and binary-encoded protocols. It is probably worth reiterating something we said in the Preface: That takes a great deal of experience. But the code from this chapter can be used as a starting point for further explorations.
Write a method to write such an integer to a stream. It should take a long and an OutputStream as parameters. Extend the DelimFramer class to handle arbitrary multiple-byte delimiters.
See any decent networking text for the algorithm. Modify the method to test for these preconditions and throw an exception if any are violated. This page intentionally left blank cha pter 4 Beyond the Basics T he client and server examples in Chapter 2 demonstrate the basic model for programming with sockets in Java.
This type of server is known as an iterative server. They work best for applications where each client requires a small, bounded amount of server connection time; however, if the time to handle a client can be long, the wait experienced by subsequent clients may be unacceptable. To demonstrate the problem, add a second sleep using Thread.
Note that a new client must wait for all already-connected clients to complete before it gets service. What we need is some way for each connection to proceed independently, without interfering with other connections. Java threads provide exactly that: Beyond the Basics allowing servers to handle many clients simultaneously. Using threads, a single application can work on several tasks concurrently, as if multiple copies of the Java Virtual Machine were running.
In our echo server, we can give responsibility for each client to an independently executing thread. All of the examples we have seen so far consist of a single thread, which simply executes the main method. In this section we describe two approaches to coding concurrent servers, namely, threadper-client, where a new thread is spawned to handle each client connection, and thread pool, where connections are assigned to a prespawned set of threads.
We shall also describe the built-in Java facilities that simplify the use of these strategies for multithreaded servers. In either case, the new thread does not begin execution until its start method is invoked. The Runnable interface contains a single method prototype: Meanwhile, the original thread returns from its call to start and continues its execution independently.
In the following example, ThreadExample. Declaration of implementation of the Runnable interface: If ThreadExample fails to provide a run method, the compiler will complain.
Member variables and constructor: Our example does not include an interrupt call, so the exception will not happen in this application.
Beyond the Basics 4. Each thread independently executes the run method of ThreadExample, while the main thread terminates.
Upon execution, an interleaving of the three greeting messages is printed to the console. The exact interleaving of the numbers depends upon various factors that in general are not observable. A full treatment of techniques and facilities for concurrency would require a book of its own.
The book by Goetz et al. The code for the echo protocol is given in the class EchoProtocol. This class encapsulates the per-client processing in the static method handleEchoClient. Alternatively, the server-side protocol processing can be invoked by calling the static method directly passing it the Socket and Logger references.
OutputStream; java. Level; java. Beyond the Basics Each instance of EchoProtocol contains a socket for the connection and a reference to the logger instance. Your server is up and running with thousands of clients per minute. Now a user reports a problem. How do you determine what happened? Is the problem at your server? Perhaps the client is violating the protocol. To deal with this scenario, most servers log their activities.
This practice is so common that Java now includes built-in logging facilities in the java. We provide a very basic introduction to logging here; however, be aware that there are many more features to enterprise-level logging. We begin with the Logger class, which represents a logging facility that may be local or remote.
Through an instance of this class, we can record the various server activities as shown in EchoProtocol. For example, you may have separate loggers for operations, security, and error messages.
To get an instance of Logger, call the static factory method Logger. If a logger by that name does not exist, a new logger is created; otherwise, the existing logger instance is returned. Now that you have logging, what should you log? Well, it depends on what you are doing. If the server is operating normally, you may not want to log every single step the server takes because logging consumes resources such as space for storing log entries and server processor time for writing each entry.
On the other hand, if you are trying to debug, you may want to log each and every step. To deal with this, logging typically includes the notion of the level, or severity, of log entries.
The Level class encapsulates the notion of the importance of messages. Each level has an associated integer value, so that levels are comparable and can be ordered. By default, a logger has a single ConsoleHandler that prints messages to System.
You can change the handler or add additional handlers to a logger e. Once we have the logger, we need to … well … log. Beyond the Basics The severe , warning , etc. The entering and exiting methods log entering and exiting the given method from the given class. Note that you may optionally specify additional information such as parameters and return values. The log methods provide a generic logging method where level, message, and optionally exception can be logged.
Note that many other logging methods exist; we are only noting the major types here. We may want to customize our logger by setting the minimum logging level or the handlers for logging messages.
The isLoggable method returns true if the given level will be logged by the logger. It is very similar to the iterative server, using a single loop to receive and process client requests. This is possible because EchoProtocol implements the Runnable interface. Thus, when several 4. Instead, they all appear to receive service albeit at a somewhat slower rate at the same time.
ServerSocket; java. Loop forever, handling incoming connections: Beyond the Basics Since EchoProtocol implements the Runnable interface, we can give our new instance to the Thread constructor, and the new thread will execute the run method of EchoProtocol which calls handleEchoClient when start is invoked. Thread Pool Every new thread consumes system resources: In addition, when one thread blocks, the JVM saves its state, selects another thread to run, and restores the state of the chosen thread in what is called a context switch.
As the number of threads increases, more and more system resources are consumed by thread overhead. Eventually, the system is spending more time dealing with context switching and thread management than with servicing connections. At that point, adding an additional thread may actually increase client service time.
We can avoid this problem by limiting the total number of threads and reusing threads. When a new client connection arrives at the server, it is assigned to a thread from the pool. Connection requests that arrive when all threads in the pool are busy are queued to be serviced by the next available thread. Like the thread-per-client server, a thread-pool server begins by creating a ServerSocket.
Then it spawns N threads, each of which loops forever, accepting connections from the shared ServerSocket instance. When multiple threads simultaneously call accept on the same ServerSocket instance, they all block until a connection is established. Then the system selects one thread, and the Socket instance for the new connection is returned only in that thread. The other threads remain blocked until the next connection is established and another lucky winner is chosen.
Since each thread in the pool loops forever, processing connections one by one, a thread-pool server is really like a set of iterative servers. Instead, it starts over again, blocking on accept. Logger; 4. After parsing them we create the ServerSocket and Logger instances. Note that both have to be declared final, because they are referenced inside the anonymous class instance created below. Create and start threadPoolSize new threads: When the start method of this instance is called, the thread executes the run method 84 Chapter 4: Beyond the Basics of this anonymous class.
The run method loops forever, accepting a connection and then giving it to EchoProtocol for service. The system ensures that only one thread gets a Socket for any particular connection. If no threads are blocked on accept when a client connection is established that is, if they are all busy servicing other connections , the new connection is queued by the system until the next call to accept see Section 6.
Since we control the maximum number of simultaneously executing threads, we can control scheduling and resource overhead. Of course, if we spawn too few threads, we can still have clients waiting a long time for service; therefore, the size of the thread pool needs to be tuned to the load, so that client connection time is minimized.
The ideal would be a dispatching facility that expands the thread pool up to a limit when the load increases, and shrinks it to minimize overhead during times when the load is light. It turns out that Java has just such a facility; we describe it in the next section. The Executor Interface In the previous subsections, we have seen that encapsulating the details of the client-server protocol as in EchoProtocol. In fact the same thing is true for the dispatching methods themselves. The interface Executor part of the java.
For example, if a thread stops because of an uncaught exception or other failure, they automatically spawn a new thread to replace it. ExecutorService also allows for tasks to return a result, through the Callable interface, which is like Runnable, only with a return value. Instances of ExecutorService can be obtained by calling various static factory methods of the convenience class Executors.
Executor; java. Executors; java. Beyond the Basics 1. We create the ServerSocket and Logger instances as before; they need not be declared final here, because we do not need an anonymous Thread subclass.
Get an Executor: When its execute method is invoked with a Runnable instance, the executor service creates a new thread to handle the task if necessary. When a thread has been idle for at least 60 seconds, it is removed from the pool. Loop forever, accepting connections and executing them: Once we have a server designed to use Executor for dispatching clients, we can change dispatching strategies simply by changing the kind of Executor we instantiate.
Also, tasks are queued inside the Executor, instead of being queued inside the networking system, as they were in our original server. Data input methods read and receive block if data is not available.
The accept method of ServerSocket and the Socket constructor both block until a connection has been established see Section 6. Meanwhile, long roundtrip times, high error rate connections, and slow or deceased servers may cause connection 4.
Of course, a blocked method call halts progress of the application and makes the thread that is running it useless. What about a program that has other tasks to perform while waiting for call completion e. These programs may have no time to wait on a blocked method call.
What about lost UDP datagrams? Here we explore the various blocking methods and approaches for limiting blocking behavior. Unfortunately, the system-imposed timeout is long, and Java does not provide any means of shortening it. To establish a connection, call the connect method on the newly constructed socket and specify both a remote endpoint and timeout milliseconds.
Thus, the amount of time that a write may block is ultimately controlled by the receiving application. Unfortunately, Java currently does not provide any way to cause a write to time out, nor can it be interrupted by another thread. Therefore, any protocol that sends a large enough amount of data over a Socket instance can block for an unbounded amount of time. The protocol instance keeps track of the amount of time remaining, and uses setSoTimeout to ensure that 88 Chapter 4: Beyond the Basics no read call blocks for longer than that time.
Since there is no way to bound the duration of a write call, we cannot really guarantee that the time limit will hold. Nevertheless, TimelimitEchoProtocol. At the time the handleEchoClient method is invoked, a deadline is computed using the current time and the time bound. After each read , the time between the current time and the deadline is computed, and the socket timeout is set to the remaining time. Such one-to-one communication is sometimes called unicast. Some information is of interest to multiple recipients.
Unicasting multiple copies over a single network connection wastes bandwidth by sending the same information multiple times.
For example, if our video server sends 1Mbps streams and its network connection is only 3Mbps a healthy connection rate , we can only support three simultaneous users. Instead of making the sender responsible for duplicating packets, we can give this job to the network.
In our 90 Chapter 4: With this model of duplication, the server uses only 1Mbps across its connection to the network, irrespective of the number of clients. There are two types of one-to-many service: With broadcast, all hosts on the local network receive a copy of the message. With multicast, the message is sent to a multicast address, and the network delivers it only to those hosts that have indicated that they want to receive messages sent to that address.
In general, only UDP sockets are allowed to broadcast or multicast. Note that IPv6 does not explicitly provide broadcast addresses; however, there is a special all-nodes, link-local-scope multicast address, FFO The IPv4 local broadcast address Local broadcast messages are never forwarded by routers.
A host on an Ethernet network can send a message to all other hosts on that same Ethernet, but the message will not be forwarded by a router. There is no networkwide broadcast address that can be used to send a message to all hosts. To see why, consider the impact of a broadcast to every host on the Internet. Sending a single datagram would result in a very, very large number of packet duplications by the routers, and bandwidth would be consumed on each and every network.
The consequences of misuse malicious or accidental are too great, so the designers of IP left such an Internetwide broadcast facility out on purpose. Even so, local broadcast can be very useful.
Often, it is used in state exchange for network games where the players are all on the same local broadcast network. In Java, the code for unicasting and broadcasting is the same. There is one problem. You cannot use connect with broadcast. Some operating systems do not give regular users permission to broadcast, in which case this will not work.
The designers of IP allocated a 4. With the exception of a few reserved multicast addresses, a sender can send datagrams addressed to any address in this range. In Java, multicast applications generally communicate using an instance of MulticastSocket, a subclass of DatagramSocket. Our next examples implement a multicast sender and receiver of vote messages.
Beyond the Basics System. Every IP datagram contains a TTL, initialized to some default value and decremented usually by one by each router that forwards the packet. When the TTL reaches zero, the packet is discarded. By setting the initial value of the TTL, we limit the distance a packet can travel from the sender.
Receivers need some mechanism to notify the network of their interest in receiving data sent to a particular multicast address, so that the network can forward packets to them. MulticastSocket; java. Multicast datagrams can, in fact, be sent from a DatagramSocket by simply using a multicast address. A multicast receiver, on the other hand, must use a MulticastSocket because it needs the ability to join a group. Beyond the Basics MulticastSocket: If we wish to receive any datagrams, we need to join a multicast group.
A socket may be a member of multiple groups simultaneously. Joining a group of which this socket is already a member or leaving a group of which this socket is not a member may generate an exception.
A socket with loopback mode enabled will receive the datagrams it sends. The getLoopbackMode and setLoopbackMode methods set the loopback mode 4. The getInterface , setInterface , getNetworkInterface , setNetworkInterface methods set the outgoing interface used in sending multicast packets.
This is primarily used on hosts with multiple interfaces. The default multicast interface is platform dependent. The decision to use broadcast or multicast depends on several factors, including the network location of receivers and the knowledge of the communicating parties.
The scope of a broadcast on the Internet is restricted to a local broadcast network, placing severe restrictions on the location of the broadcast receivers. Multicast communication may include receivers anywhere in the network,2 so multicast has the advantage that it can cover a distributed set of receivers. The disadvantage of IP multicast is that receivers must know the address of a multicast group to join. Knowledge of an address is not required to receive broadcast.
In some contexts, this makes broadcast a better mechanism than multicast for discovery. The semantics of most implementations are such that a UDP datagram will be delivered to all sockets bound to the destination port of the packet. A receiver can use connect to limit the datagram source address and port. Also, a DatagramSocket can specify the local unicast address, which prevents delivery of multicast and broadcast packets.
We have already seen an example in our UDP echo client. Multicast should work if the sender and receivers are on the same LAN. TCP provides a keep-alive mechanism where, after a certain time of inactivity, a probe message is sent to the other endpoint. If the endpoint is alive and well, it sends an acknowledgment.
Note that the application only sees keep-alive working if the probes fail. Call the setKeepAlive method with true to enable keep-alive. We talk about this in much greater detail in Section 6. Socket, DatagramSocket: Why can you only set the 4.
Unfortunately, the blocking time is not bounded. We can specify a maximum blocking time for the various operations. Socket, ServerSocket, DatagramSocket: A timeout of 0 means the operation never times out. If the timeout expires, an exception is thrown. In the case of UDP multicast, you may have multiple applications on the same host participating in the same multicast group.
Unfortunately, you may not be able to wait for the Time-Wait to expire. To enable this, you must allow address reuse. A value of true means that address reuse is enabled. Fortunately, you can disable this behavior. If you send the data in the output stream, it gets queued up behind all of the regular data, and who knows when the receiver will see it? To deal with this TCP includes the concept of urgent data that can theoretically skip ahead.
Such data is called out-of-band because it bypasses the normal stream. To receive this byte, the receiver must enable out-of-band data by passing true to setOOBInline. The byte is received in the input stream of the receiver. If reception of out-of-band data is not enabled, the urgent byte is silently discarded. Note that Java can get little use from urgent data because urgent bytes are mixed in with regular bytes in the order of transmission.
The problem is that your host could then fail at a later time without sending all of the data. If the timeout expires, the TCP connection is forceably closed. You can control broadcast permissions. As you already know, DatagramSockets provide broadcast service. A value of true means that broadcast is permitted. By default, Java permits broadcast. The number and meaning of the bits depend on the version of IP you are using.
Socket, ServerSocket: Specifying Protocol Preferences void setPerformancePreferences int connectionTime, int latency, int bandwidth The performance preference for the socket is expressed by three integers representing connection time, delay, and bandwith. For example, if connectionTime and latency both equal 0 and bandwidth equals 1, the protocol maximizing bandwidth will be selected. In phone conversations, either side can start the process of terminating the call.
It typically goes something like this: In the echo protocol, Figure 4. The server then calls close on its socket. Section 6. Once an endpoint client or server closes the socket, it can no longer send or receive data. Echo a and HTTP b protocol termination. Beyond the Basics Shutdown Figure 4. Compression protocol termination. Closed Compression Server Compression Client immediately closes. HTTP works the same way, except that the server is the terminator.
Suppose you want a compression server that takes a stream of bytes, compresses them, and sends the compressed stream back to the client. Which endpoint should close the connection? Since the stream of bytes from the client is arbitrarily long, the client needs to close the connection so that the server knows when the stream of bytes to be compressed ends.
When should the client call close? If the client calls close on the socket immediately after it sends the last byte of data, it will not be able to receive the last bytes of compressed data.
Perhaps the client could wait until it receives all of the compressed data before it closes, as the echo protocol does. Unfortunately, neither the server nor the client knows how many bytes to expect, so this will not work either.
Fortunately, sockets provide a way to do this. Attempts to write to the stream throw an IOException.
Any data written before the call to shutdownOutput may be read by the remote socket. An application calling shutdownOutput can continue to read from the socket and, similarly, data can be written after calling shutdownInput. In the compression protocol see Figure 4. The server then closes the connection and exits. Our compression client, CompressClient.
We discuss and correct this shortcoming in Section 6. FileInputStream; java. Invoke sendBytes to transmit bytes: Receive the compressed data stream: To implement the compression server, we simply write a protocol for our threaded server architecture.
Our protocol implementation, CompressProtocol. Logger; java. Variables and constructors: The sequence of bytes written to this stream is compressed, using the GZIP algorithm, before being written to the underlying output stream. Without such restrictions, unsuspecting Web browsers might execute malicious applets that could, for example, send fake email, attempt to hack other systems while the browser user gets the blame, and so on.
These security restrictions are enforced by the Java security manager, and violations by the applet result in a SecurityException. Typically, browsers only allow applets to communicate with the host that served the applet.
This means that applets are usually restricted to communicating with applications executing on that host, usually a Web server originating the applet. The list of security restrictions and general applet programming is beyond the scope of this book. It is worth noting, however, that the default security restrictions can be altered, if allowed by the browser user.
Suppose that you wanted to implement an applet that allowed users to type and save notes to themselves on their browser. The server must execute on the Web server that serves the applet to the browser.
In addition to these facilities, Java provides several mechanisms not discussed here that operate on top of TCP or UDP and attempt to hide the complexity of protocol development.
The URL class and associated classes provide a framework for developing Web-related programs.
Many other standard Java library Chapter 4: Beyond the Basics mechanisms exist, providing an amazing range of services. State precisely the conditions under which an iterative server is preferable to a multiprocessing server. Would you ever need to implement a timeout in a client or server that uses TCP?
Determine the minimums for your system. There are two important parts: These are fairly advanced features, with a number of subtle details related to their usage. In Section 5. Then we go back and cover the details of usage of the main abstractions, each in its own section. Finally, Section 5. Basic Java Sockets work well for small-scale systems.
But when it comes to servers that have to deal with many thousands of clients simultaneously, certain issues arise. We saw signs of this in Chapter 4: Using a thread Chapter 5: NIO pool saves on that kind of overhead while still allowing an implementor to take advantage of parallel hardware, but for protocols with long-lived connections, the size of the thread pool still limits the number of clients that can be handled simultaneously.
Consider an instant messaging server that relays messages between clients. Clients must be continuously connected to receive messages, so the thread pool size limits the total number of clients that can be served.
Increasing the thread pool size increases the thread-handling overhead without improving performance, because most of the time clients are idle. If this were all there is to it, NIO might not be needed.
Unfortunately, there are other, more subtle challenges involved with using threads for scalability. One is that the programmer has very little control over which threads receive service when. Think of a service that allows citizens to reserve parking spaces for one-hour blocks in a big city, for example.
The schedule of who gets which space for which time blocks must be kept consistent; the server may also need to ensure that the same user does not reserve more than one space at a time. These constraints require that some state information i.
This in turn requires that access to that state be carefully synchronized through the use of locks or other mutual exclusion mechanisms. Because of these complications, some programmers prefer to stick with a single-threaded approach, in which the server has only one thread, which deals with all clients—not sequentially, but all at once. We saw an example of this in Chapter 4, where we set a timeout on the accept operation via the setSoTimeout method of ServerSocket.
This allows a single thread to handle multiple connections. Channels can register an instance of class Selector. The other major feature introduced in NIO is the Buffer class. The bad thing is that implementing that illusion may require either lots of memory allocation or lots of context-switching, or both.
As with threads, this overhead is buried in the implementation, and is therefore not controllable or predictable. That approach makes it easy to write programs, but harder to tune their performance. There are two main advantages to using Buffer. This represents extra work, but you the programmer control how, whether, and when it happens. A smart programmer, who knows the application requirements well, can often reduce overhead by tweaking these choices.
There are other types of channels for other devices e. For example, a call to accept can block waiting for a client to connect; a call to read can block until data arrives from the other end of a connection. A slow, lossy, or just plain broken network can cause an arbitrary delay. The return value of such a call indicates the extent to which the requested operation was achieved. With a nonblocking channel, these operations return immediately.
InetSocketAddress; java. ByteBuffer; java. NIO clntChan. Get and convert arguments: Create nonblocking SocketChannel: Connect to server: The print operation demonstrates that we can perform other tasks while waiting for the connection to complete.
Such a busy wait is generally wasteful; we do it here to illustrate the use of the methods. Loop until we have sent and received all the bytes: The call to read does not block but rather returns 0 when no data is available to return.
Again, the print operation demonstrates that we can perform other tasks while waiting for the communication to complete. Print the received data: Close the channel: Consider an Instant Messaging server, for example. Thousands of clients may be connected, but only a few possibly none have messages waiting to be read and relayed at any time. NIO selectors do all of this. To use a selector, create it using the static factory method open and register it with the channels that you wish to monitor note that this is done via a method of the channel, not the selector.
Suppose we want to implement an echo server using channels and a selector without using multiple threads or busy waiting. The API application programming interface reference sections in each chapter, which describe the relevant parts of each class, have been replaced with i a summary section that lists the classes and methods used in the code, and ii a gotchas section that mentions nonobvious or poorly-documented aspects of the objects.
In addition, the book covers several new classes and capabilities introduced in the last few revisions of the Java platform. The example code is also modified to take advantage of new language features such as annotations, enumerations, as well as generics and implicit iterators where appropriate. Book Site. Practical Guide for Programmers. What's the current weather of a particular airport? Click here to find out.
Calvert, Michael J. Donahoo Publisher: English ISBN Book Description Most Internet applications use sockets to implement network communication protocols. About the Authors Kenneth L. Calvert is an associate professor at University of Kentucky, where he teaches and does research on the design and implementation of computer network protocols. Michael J. Donahoo teaches networking to undergraduate and graduate students at Baylor University, where he is an assistant professor.
Reviews and Rating: site Related Book Categories: Read and Download Links: Practical Guide for Programmers Kenneth L.