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.
|Language:||English, Spanish, Portuguese|
|Distribution:||Free* [*Registration Required]|
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.
Options int getSoTimeout void setSoTimeout int timeoutMillis These methods return and set, respectively, the maximum amount of time that a receive call will block for this socket. If the timer expires before data is available, an InterruptedIOException is thrown. The timeout value is given in milliseconds. They are described more fully in Section 4.
The typical UDP server goes through three steps: Construct an instance of DatagramSocket, specifying the local port and, optionally, the local address. The server is now ready to receive datagrams from any client. Receive an instance of DatagramPacket using the receive method of DatagramSocket. Communicate by sending and receiving DatagramPackets using the send and receive methods of DatagramSocket.
The server is very simple: IOException; import java. DatagramPacket; import java. Create and set up datagram socket: Create datagram: This datagram will be used both to receive the echo request and to send the echo reply.
Basic Sockets 4. Iteratively handle incoming echo requests: If we do not reset the internal length before receiving again, the next message will be truncated if it is longer than the one just received. Each call to receive on a DatagramSocket returns data from at most one call to send. This is covered in more detail in Chapter 6.
This means that by the time a call to send returns, the message has been passed to the underlying channel for transmission and is or soon will be on its way out the door. With a connected TCP socket, all received-but-not-yet-delivered bytes are treated as one continuous sequence of bytes see Chapter 6. A call to receive will never return more than one message. The remaining bytes are quietly discarded, with no indication to the receiving program that information has been lost!
This technique will guarantee that no data will be lost. The maximum amount of data that can be transmitted in a DatagramPacket is 65, bytes—the largest payload that can be carried in a UDP datagram.
For example, suppose buf is a byte array of size 20, which has been initialized so that each byte contains its index in the array: The message is received into dg: One possibility is to copy the received data into a separate byte array, like this: Basic Sockets As of Java 1. We said that a socket must have a port for communication, yet we do not specify a port in TCPEchoClient.
What happens if a TCP server never calls accept? What happens if a TCP client sends data on a socket that has not yet been accept ed at the server? Servers are supposed to run for a long time without stopping—therefore, they must be designed to provide good service no matter what their clients do. What is happening? Note that the response could vary by OS.
What happens? Verify experimentally the size of the largest message you can send and receive using a DatagramPacket. There is no magic: This agreement regarding the form and meaning of information exchanged over a communication channel is called a protocol; a protocol used in implementing a particular application is an application protocol.
In our echo example from the earlier chapters, the application protocol is trivial: Because in most real applications the behavior of clients and servers depends upon the information they exchange, application protocols are usually somewhat more complicated. So from now on we consider messages to be sequences of bytes. Given this, it may be helpful to think of a transmitted message as a sequence or array of numbers, each between 0 and That corresponds to the range of binary values that can be encoded in 8 bits: Sending and Receiving Data When you build a program to exchange information via sockets with other programs, typically one of two situations applies: We have seen that bytes of information can be transmitted through a socket by writing them to an OutputStream associated with a Socket or encapsulating them in a DatagramPacket which is then sent via a DatagramSocket.
However, the only data types to which these operations can be applied are bytes and arrays of bytes. As a strongly typed language, Java requires that other types—int, String, and so on—be explicitly converted to byte arrays. Fortunately, the language has built-in facilities to help with such conversions. 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.
Morgan Kaufmann. Merlin Hughes, Java Network Programming, 2nd Edition. Manning Publications. The assessments address the living ciriculm main characterstics such as Creativity, Curiosity, Problem Solving, Collaboration, Self- efficacy and Reflection. This assessment will cover learning outcomes 1,2, 3 and 4.
The lecturers set up a page for the course and each student is required to contribute at least 10 questions on the website. It will cover learning outcomes 1,2 and 3.
Calvert is an associate professor at University of Kentucky, where he teaches and does research on the design and implementation of computer network protocols. He has been doing networking research since , and teaching since Michael J.
Donahoo teaches networking to undergraduate and graduate students at Baylor University, where he is an assistant professor. He received his Ph.
His research interests are in large-scale information dissemination and management. We are always looking for ways to improve customer experience on Elsevier.
We would like to ask you for a moment of your time to fill in a short questionnaire, at the end of your visit. If you decide to participate, a new browser tab will open so you can complete the survey after you have completed your visit to this website. Thanks in advance for your time. Skip to content. Search for books, journals or webpages All Webpages Books Journals.
View on ScienceDirect. Kenneth Calvert Michael Donahoo.
Paperback ISBN: Morgan Kaufmann. Published Date: Page Count: View all volumes in this series: The Practical Guides. Sorry, this product is currently out of stock.