The term network programming can mean a lot of different things. Applets are a form of network programming-as are Java Server Pages and servlets. I cover these network programming features in detail in Book VII.
File and database programming can also be thought of as a form of network programming, as files and databases can be located on a server computer rather than on the computer where the application is run. Book VIII covers the networking aspects of file and database programming.
In this chapter, you discover how to use Java's sockets interface, which lets you set up input and output streams between programs on client and server computers. In fact, I show you how to create a simple server program that can be accessed over the Internet.
Along the way, you find out about the TCP/IP networking protocol, IP addresses and ports, and other useful networking topics.
Network programming usually involves two types of programs: client programs and server programs. A server program is a program that provides services to one or more users who run client programs to access those services. These client and server computers communicate with each other through well-established protocols, which dictate the nature of the communications between clients and servers.
Examples of client and server programs abound:
I could go on and on.
An IP address is a number that uniquely identifies every computer on an IP network. IP addresses are 32-bit binary numbers, which means that, theoretically, a maximum of something in the neighborhood of 4 billion unique host addresses can exist throughout the Internet.
IP addresses are usually represented in a format known as dotted-decimal notation. In dotted-decimal notation, each group of eight bits, known as an octet, is represented by its decimal equivalent. For example:
192.168.136.28
You usually see IP addresses represented in this format.
Besides an IP address, you must also use a port to access data from a computer over the Internet. The various services that a server computer might provide are assigned well-known port numbers. For example, the port number for the Web protocol HTTP is 80. As a result, a computer that wants to access a Web server HTTP must do so over port 80.
Port numbers are often specified with a colon following an IP address. For example, the HTTP service on a server whose IP address is 192.168.10.133 is 192.168.10.133:80.
Tip |
Literally thousands of established ports are in use. If you need to make up a port number for an application, pick a number that's greater than 49151. Those numbers are available for private use. |
A host name is a name that's associated with a particular IP address. Host names are created using a naming standard called DNS, which stands for Domain Name System. If it weren't for DNS, you'd buy books from 207.171.166.48 instead of from http://www.amazon.com, you'd sell your used furniture at 66.135.192.87 instead of on http://www.ebay.com, and you'd search the Web at 216.239.57.99 instead of at http://www.google.com.
The Internet has an entire network of DNS server computers throughout the world that look up host names and provide the corresponding IP address. For example, when you enter http://www.dummies.com into the address bar of a Web browser, your browser consults a DNS server to find out the IP address for http://www.dummies.com. Then it displays the home page for that address.
Closely related to DNS is URL, which stands for Uniform Resource Locator. URL is a naming scheme that can uniquely identify any resource on the Internet. By resource, I usually mean file. Thus, URL turns the DNS naming system into a huge file system that lets you access any file that's available anywhere on the Internet. It does this by appending filepath information to the end of a host name, like this:
ftp.someserver.com/pub/myfile.txt
This URL refers to a file named myfile.txt in a directory named pub on a computer identified by the host name http://www.ftp.someserver.com. I won't deal with URLs in this chapter, but they play a big role in Web programming. So be prepared to revisit them in Book VII.
Tip |
Every computer has a special host name and IP address that's used to identify itself to itself. This host name is localhost, and the IP address is 127.0.0.1. This it's-all-about-me address is sometimes called the loopback address. localhost is an invaluable testing feature because it lets you test networking programs without requiring that you use separate computers. In other words, you can run a client and server program on the same computer by having them both use localhost to refer to each other. |
Telnet is a handy debugging tool that can let you check out network programs interactively. It comes free with just about every operating system, though it may or may not be installed automatically. So if you don't have it, you may have to retrieve it from your operating system disks.
Using telnet is easy. From a command prompt, just type telnet followed by the name of the host (or its IP address) and the port number you want to connect to. Here's an example:
telnet somecomputer.com 80
This command connects to port 80 of http://www.somecomputer.com.
To connect to a network server program running on the same computer you're running telnet on, just use localhost as the host name. For example, here's a command that connects to a server program using port 1234:
telnet localhost 1234
After telnet fires up, anything you type is sent to the port, and anything received from the port is displayed in the telnet window.
TECHNICAL STAUFF |
You may have to configure telnet to echo characters you type so you can see what you're typing. Each telnet program has a different way to do this, so you have to consult the program's help to find out. (Try running telnet -? from the command prompt to get help.) |
Tip |
The telnet command is a command-based telnet client. Windows XP also comes with a Windows-based telnet client named Hyperterminal. You can run it by choosing Start Programs Accessories Communications Hyperterminal. With Windows Vista you have to download Hyperterminal. To do so, visit http://www.hilgraeve.com/htpe/download.html. |
One of the most useful Java API classes for network programming is the InetAddress class. In the following sections, you discover what this class does and how to use it in a simple program that displays the IP address used for any domain name.
As you know, an IP address is simply a number that corresponds to a particular host computer on the Internet. The designers of Java could have simply represented IP addresses as long numbers. But instead, they created a powerful class called InetAddress that represents an IP address.
The InetAddress includes a number of useful methods that let you create InetAddress objects from strings that represent IP addresses or host names or perform useful lookups to find out the IP address for a given host name or vice versa. Table 2-1 lists the most commonly used methods.
Method |
Description |
---|---|
byte[] getAddress() |
Returns the raw IP address as an array of bytes. |
static InetAddress[] getAllByName(String host) |
Returns an array of Internet addresses for the specified host name. This method performs a DNS query to get the addresses. Throws UnknownHostException if the specified host doesn't exist. |
static InetAddress getByName(String host) |
Returns the Internet address for the specified host name or IP address. This method performs a DNS query to get the address. Throws UnknownHostException if the specified host doesn't exist. |
String getCannonicalHostName() |
Returns the fully qualified host name for this IP address. |
String getHostAddress() |
Returns the IP address as a formatted string. |
String getHostName() |
Performs a reverse DNS lookup to get the host name for this IP address. |
boolean isReachable(int timeout) |
Determines if the IP address can be reached. The attempt fails if no response is reached before the timeout period (in milliseconds) elapses. |
String toString() |
Converts the IP address to a string. The result includes both the host name and the IP address. |
Here are a few additional points about this class:
Listing 2-1 presents a program that uses the InetAddress class to look up the IP addresses associated with any given host name. This program uses the getAllByName method of the InetAddress class to do this lookup. Here's a sample of what this handy little program can do:
Welcome to the IP lookup application. Enter a host name: Www.Wiley.Com www.wiley.com/208.215.179.146 Look up another? (Y or N) y Enter a host name: www.dummies.com www.dummies.com/208.215.179.139 Look up another? (Y or N) y Enter a host name: amazon.com amazon.com/207.171.166.48 amazon.com/207.171.166.102 amazon.com/207.171.163.30 amazon.com/207.171.163.90 Look up another? (Y or N) n
As you can see, this program prompts the user for a host name. It then looks up the IP address or addresses for the host name, displays the results, and asks the user if he or she wants to look up another host.
DESIGN PATTERN |
The Façade pattern The InetAddress class is an example of a commonly used design pattern called the Façade pattern. In this pattern, you use a single class to hide the details of a complex object or set of related classes. The InetAddress class combines the representation of an IP address with a variety of tasks that are commonly associated with IP addresses, such as using DNS to get the IP address based on a host name. (An even better example of the Façade pattern is the URL class, which provides a single class to access the complex features of URLs.) The Façade pattern is commonly used in Java programming, especially in systems that need to incorporate access to complicated existing systems. For example, suppose you have a fully integrated order-handling system already in place, and you want to provide a way for Web users to order directly from your company via this system. Unfortunately, the existing system is way too complicated for your customers to use directly-it's designed to be used by trained sales personnel, and provides access to many different sales features that your customers don't need and shouldn't be exposed to. One way to do this is to create a facade for the ordering system. This facade includes an interface that provides just the classes and methods needed to implement your ordering system online, hiding as much of the complexity of the real ordering system as possible. |
Listing 2-1: The HostLookup Application
import java.util.Scanner; import java.net.*; → 2 public class HostLookup { static Scanner sc = new Scanner(System.in); public static void main(String[] args) { System.out.println( "Welcome to the IP lookup application."); String host; do → 11 { System.out.print(" Enter a host name: "); host = sc.nextLine(); → 14 try { InetAddress[] addresses → 17 = InetAddress.getAllByName(host); for (InetAddress ip : addresses) → 19 System.out.println(ip.toString()); → 20 } catch (UnknownHostException e) { System.out.println("Unknown host."); } } while (doAgain()); → 26 } private static boolean doAgain() { System.out.println(); String s; while (true) { System.out.print("Look up another? " + "(Y or N) "); s = sc.nextLine(); if (s.equalsIgnoreCase("Y")) return true; else if (s.equalsIgnoreCase("N")) return false; } } }
The following paragraphs describe the key lines in this program:
→ 2 |
The InetAddress class lives in the java.net package, so an import statement is required to use it. |
→ 11 |
This do loop lets the user look up as many host names as he or she wants. The loop ends in line 26, which calls the doAgain method to ask the user if he or she wants to look up another host. |
→ 14 |
This line gets the host name the user wants to look up and saves it in the string variable host. |
→ 17 |
This statement creates an array variable named addresses whose type is InetAddress. In other words, this variable holds an array of Internet addresses. Then it calls the static getAllByName method of the InetAddress class, passing the host name entered in line 14 as the parameter. This method performs a DNS lookup on the host name and returns an array that contains all the Internet addresses for the name. |
→ 19 |
An enhanced for loop is used to process each InetAddress object in the addresses array. |
→ 20 |
This line calls the toString method to convert an Internet address to a string. The string returned by the toString method includes both the host name and the IP address. |
Open table as spreadsheet
One popular form of network programming is creating client and server programs that work together to perform specific tasks. These programs communicate with each other by sending information over the network. The format of this information is governed by a protocol, which is merely an agreement on the types of messages the clients and servers can send and receive.
A few hundred well-established protocols already exist for such things as sending e-mail and Web pages, looking up DNS names, sharing files, and so on. However, for specialized networking applications, you may find yourself developing your own protocol to coordinate your clients and servers.
Each protocol usually has a unique port assigned to it. For example, port 80 is reserved for the HTTP protocol used to exchange Web pages, and port 25 is used for the SMTP protocol used to exchange e-mail messages. If you end up creating your own protocol, you need to pick a port that doesn't conflict with any of the known ports or with any ports that the users of your application may already be using for other purposes.
Client and server computers establish a connection on a port by means of a special object called a socket. In the following sections, I talk about two Java classes that are designed to work with sockets. Then you see an example of a simple server program and a client that's designed to work with the server.
In this section, I look at two classes that are designed for communicating through sockets. The first, Socket, represents a basic socket object. The second, ServerSocket, is used to help servers establish socket connections with clients.
The Socket class represents a socket connection between two programs. Although the programs can be running on the same computer, they don't have to be. In fact, any two computers that are connected to the Internet can communicate with each other via a socket. Table 2-2 lists the most commonly used constructors and methods of this class.
Table 2-2: Constructors and Methods of the Socket Class
Open table as spreadsheet
Constructor |
Description |
---|---|
Socket() |
Creates an unconnected socket. |
Socket(InetAddress address, int port) |
Creates a socket and connects it to the specified address and port. |
Socket(String host, int port) |
Creates a socket and connects it to the specified host and port. |
Open table as spreadsheet
Method |
Description |
---|---|
void Close() |
Closes the socket. |
void connect(InetSocketAddress endpoint) |
Connects the socket to the specified address. |
InetAddress getInetAddress() |
Gets the address to which the socket is connected. |
InputStream getInputStream() |
Gets an input stream that can be used to receive data sent through this socket. |
OutputStream getOutputstream() |
Gets an output stream that can be used to send data through this socket. |
int getPort() |
Gets the port to which this socket is connected. |
boolean isBound() |
Indicates whether the socket is bound to a port. |
boolean isClosed() |
Indicates whether the socket is closed. |
Here are a few important details about the Socket class:
Tip |
Although the Socket class has constructors that let you connect to a specific address, the normal way to create a socket is to use the attach method of the ServerSocket class. |
A server socket is a socket that lets clients connect with your application. When a client connects, the server socket creates a Socket object, which the application can then use to communicate with the client. Table 2-3 lists the most commonly used constructors and methods of this class.
Table 2-3: Constructors and Methods of the ServerSocket Class
Open table as spreadsheet
Constructor |
Description |
---|---|
ServerSocket() |
Creates a server socket that isn't bound to any port. |
ServerSocket(int port) |
Creates a server socket and binds it to the specified port. The server socket then listens for connection attempts on this port. |
Open table as spreadsheet
Method |
Description |
---|---|
Socket attach() |
Listens for connection attempts via the port this socket is bound to. The thread that calls this method waits until a connection is made. Then, this method returns, passing a Socket object that can be used to communicate with the client. |
void bind(InetSocketAddress endpoint) |
Binds this server socket to the specified address. |
void close() |
Closes the server socket. |
InetAddress getInetAddress() |
Gets the address to which the server socket is connected. |
boolean isBound() |
Indicates whether the server socket is bound to a port. |
boolean isClosed() |
Indicates whether the server socket is closed. |
Here are some important points to remember about the ServerSocket class:
In this section, I create a simple network-server program that provides clients with a randomly selected quote from a well-known television program called the Shrimpsons. It seems that a certain young boy on this program, whose name shall remain unknown, frequently has to write sentences on the blackboard as punishment. The sentences that he has been known to write have some minor amusement value.
I call the server the BartServer, and the protocol used to communicate with the BartServer BART, short for Blackboard Assignment Retrieval Transaction, because it allows you to randomly retrieve blackboard assignments. The protocol itself is simple:
The BartServer communicates over port 1234. After you get the BartServer up and running on your computer, you can test it out by running the telnet command from a command prompt. Type the command telnet localhost 1234, and you're greeted with a message indicating that you have successfully connected. Here's a typical telnet session with the BartServer:
Welcome to BartServer 1.0 Enter GET to get a quote or BYE to exit. get I will not waste chalk. get I will not instigate a revolution. get I will not conduct my own fire drills. gte Huh? bye So long, suckers! Connection to host lost.
Tip |
Don't forget, it's the Shrimp- sons. We don't want to get sued, now, do we? |
Before you roll up your sleeves and look at the network programming required to implement the BartServer, take a look first at the supporting class, named BartQuote. This class has a single method named getQuote that returns one of 20 randomly selected blackboard sentences. The code for this class is shown in Listing 2-2.
Note that the sentences are hard-coded into this program. That's not the way you'd do it if you really wanted to use the BartServer. Instead, you'd put the sentences in a file and read the file each time you start up the server. (I don't cover File I/O until Book VIII, though, and I don't want to introduce any code here you couldn't follow, because the network programming in the rest of this chapter is complicated enough. Don't have a cow, man.)
Listing 2-2: The BartQuote Class
import java.util.ArrayList; public class BartQuote { ArrayList q = new ArrayList(); → 5 public BartQuote() → 7 { q.add("I will not waste chalk."); q.add("I will not skateboard in the halls."); q.add("I will not burp in class."); q.add("I will not instigate a revolution."); q.add("It's potato, not potatoe."); q.add("I will not encourage others to fly."); q.add("Tar is not a plaything."); q.add("I will not sell school property."); q.add("I will not get very far with this " + "attitude."); q.add("I will not sell land in Florida."); q.add("I will not grease the monkey bars."); q.add("I will not hide behind the Fifth " + "Amendment."); q.add("I am not a dentist."); q.add("I will finish what I sta"); q.add("Hamsters cannot fly."); q.add("I will not aim for the head."); q.add("I will not expose the ignorance " + "of the faculty."); q.add("I will not conduct my own fire " + "drills."); q.add("I will not fake seizures."); q.add("This punishment is not boring " + "and meaningless."); } public String getQuote() →33 { int i = (int)(Math.random() * q.size()); return q.get(i); } }
Here are the key points of this class:
→ 5 |
The sentences are kept in an ArrayList object named q. If you haven't read about the ArrayList class, run (don't walk) to Book IV, Chapter 3. |
→ 7 |
The BartQuote constructor uses the add method of the ArrayList class to add 20 sentences to the array list. |
→ 33 |
The getQuote method returns a sentence randomly selected from the array list. Math.random is used to calculate the random number. (For more information about Math.random, refer to Book II, Chapter 3.) |
Open table as spreadsheet
The BartServer program is the program you run on a server computer to provide randomly selected blackboard sentences for clients that want them. This program is shown in Listing 2-3.
Listing 2-3: The BartServer Program
import java.net.*; → 1 import java.util.*; import java.io.*; public class BartServer { public static void main(String[] args) { int port = 1234; → 9 BartQuote bart = new BartQuote(); → 11 try { System.out.println("BartServer 1.0"); System.out.println("Listening on port " + port); ServerSocket ss; → 17 ss = new ServerSocket(port); Socket s; → 20 s = ss.accept(); String client; client = s.getInetAddress().toString(); → 24 System.out.println("Connected to " + client); Scanner in; in = new Scanner(s.getInputStream()); → 28 PrintWriter out; out = new PrintWriter(s.getOutputStream(), true); → 31 out.println("Welcome to BartServer 1.0"); → 33 out.println("Enter GET to get a quote " + "or BYE to exit."); while (true) → 37 { String input = in.nextLine(); → 39 if (input.equalsIgnoreCase("bye")) break; else if (input.equalsIgnoreCase("get")) { out.println(bart.getQuote()); System.out.println("Serving " + client); } else out.println("Huh?"); } out.println("So long, suckers!"); s.close(); → 51 System.out.println( "Closed connection to " + client); } catch (Exception e) →55 { e.printStackTrace(); } } }
The following paragraphs walk you through the key parts of this program:
→ 1 |
This program begins with an import statement to import the java.net package. Notice also that the java.io package is imported. Later in this program, you'll see that this program uses the PrintWriter class. You're already familiar with this class-System.out is a PrintWriter object. |
→ 9 |
The port variable stores the port that the server communicates on. This is hard-coded with the value 1234, but you could just as easily ask the user to enter the port number or read it from a configuration file. |
→ 11 |
This line creates a new instance of the BartQuote class and assigns it to a variable named bart. |
→ 17 |
This line and the next line declare a ServerSocket variable and create a new ServerSocket object using the port variable. As a result, this ServerSocket object can be used to establish client connections on port 1234. |
→ 20 |
This line declares a Socket variable. Then the next line uses the accept method of the ServerSocket object to wait for a client to connect to port 1234. When a client connects, a Socket object is created and assigned to the variable s. |
→ 24 |
This statement uses the getInetAddress method of the Socket object to get an InetAddress object that represents the client's IP address. Then, it uses the InetAddress object's toString method to create a string that shows the client's address. This string is saved to the client variable. |
→ 28 |
The BartServer program uses a Scanner object to read data sent from the client over the socket. In this line, it uses the socket's getInputStream method to get a standard input stream for the socket. Then it uses this input stream as a parameter to the Scanner constructor, which in turn creates a Scanner object that works over the socket's input stream. You can then use the Scanner object referenced by the in variable to get commands sent to the server from clients. |
→ 31 |
Next you do a similar thing to get a PrintWriter object that can send data to a client through the socket. The getOutputStream method gets a standard output stream, which is then used as a parameter to the PrintWriter constructor. This PrintWriter is then assigned to a variable named out. |
→ 33 |
These lines send the greeting messages to the client. |
→ 37 |
The while loop processes commands from the client until the bye command is entered. That way, the client can request as many blackboard sentences as it wants. |
→ 39 |
The Scanner object is used to get a line of input from the client. The client input is then checked with nested if statements. If the client sent bye, the break statement breaks the while loop. If the client sent get, the getQuote method of the BartQuote object is called to get a random quote. Then the quote is sent to the client via a println command. If the user enters anything else, the server sends back Huh?. |
→ 51 |
When the loop ends, the program displays a farewell message and closes the socket connection. |
→ 55 |
Most of the Socket class methods throw an exception if something goes wrong with the socket connection. That's why most of the statements for the main method are contained in a try block. If an exception is thrown, e.printStackTrace is called to print detailed information about the exception on the console. |
Open table as spreadsheet
You may have noticed that the BartServer program displays various status messages in its console window as it runs. For example, when a client connects, it displays a message showing the IP address of the client. And when a client requests a quote, a message is displayed on the console. Here's a typical console screen for BartServer where a client connected, requested three quotes, and then disconnected:
BartServer 1.0 Listening on port 1234 Connected to /127.0.0.1 Serving /127.0.0.1 Serving /127.0.0.1 Serving /127.0.0.1 Closed connection to /127.0.0.1
Tip |
This program is pretty simple as network-server programs go. Still, it illustrates the basic techniques of network-server programming. Many server programs consist mostly of a big while loop that gets input from the client, inspects the input to see what the client wants to do, does what the client asks, and then sends some output back to the client. |
The preceding section shows you how to connect to the BartServer program with telnet to interact with the server. Now, this section presents a client program that communicates with a BartServer server. This program starts by asking the user for a host name. Then it connects to BartServer at that host, requests a quote, and displays that result on the computer's console 20 times (as if the console were a blackboard).
Figure 2-1 shows a typical execution of this program. Here I entered localhost as the BartServer host. localhost is useful for testing clients and servers together on the same computer system. The Java code for this program is shown in Listing 2-4.
Figure 2-1: Running the BartClient program.
Listing 2-4: The BartClient Program
import java.net.*; import java.util.*; import java.io.*; public class BartClient { public static void main(String[] args) { int port = 1234; System.out.println("Welcome to the Bart Client "); Socket s = getSocket(port); →13 try { System.out.println("Connected on port " + port); Scanner in = new Scanner(s.getInputStream()); → 20 PrintWriter out; out = new PrintWriter(s.getOutputStream(), true); → 23 // discard the welcome message in.nextLine(); → 26 // discard the exit instructions in.nextLine(); → 29 // get a quote out.println("get"); → 32 String quote = in.nextLine(); → 33 // disconnect from the server out.println("bye"); → 36 s.close(); → 37 // write the quote on the chalkboard for (int i = 0; i < 20; i++) → 41 System.out.println(quote); } catch (Exception e) { e.printStackTrace(); → 46 } } private static Socket getSocket(int port) → 50 { Socket s; String host; InetAddress ip; Scanner sc = new Scanner(System.in); while (true) { System.out.print( "What server do you want to connect to?"); host = sc.nextLine(); → 62 try { ip = InetAddress.getByName(host); → 65 s = new Socket(ip, port); → 66 return s; → 67 } catch (UnknownHostException e) → 69 { System.out.println("The host is unknown."); } catch (IOException e) { System.out.println("Network error."); } } } }
Here's an explanation of the more confusing aspects of this program:
→ 13 |
Connecting to a server is a complicated enough procedure that I placed it in a separate method named getSocket. This method prompts the user for a host name and doesn't return until the user enters one that the program can connect to. The port number is passed as a parameter, and the return value is a Socket object that's connected to the server. (The nitty-gritty details about how this method works start with line 50.) |
→ 20 |
This statement gets a Scanner object that can be used to read data from the client via the socket's input stream. |
→ 23 |
This statement gets a PrintWriter object that can be used to send data to the client via the socket's output stream. |
→ 26 |
After it's connected, the server sends a welcome message. This message is helpful to users connected via telnet, but it isn't very useful to a client program such as this one. So this statement simply uses the Scanner object to read the line from the input stream and discards it. |
Open table as spreadsheet
Tip |
Because the welcome message includes the version number for the server, the program could read the line and check it to make sure you're connected to a current version of the server. I don't think there will be much demand for additional features in BartServer, though, so you don't have to worry about version checking. |
→ 29 |
The server also sends a line of helpful instructions that you need to read from the stream and discard. |
→ 32 |
This line sends the word get to the server. That's how the client program asks the server to send back a randomly selected sentence. |
→ 33 |
After sending the get request, the client reads the next line of data from the socket input stream. Note that if delays occur because the network is slow, the nextLine method simply waits until the line has been sent. |
→ 36 |
Having got what it came for (a blackboard sentence), the client program sends a bye command to the server. The server sends back a rude farewell message, but the client program isn't interested in it, so it doesn't even bother to read it. |
→ 37 |
The connection to the server is closed. |
→ 41 |
Now that the client program has its blackboard-sentence-writing assignment, it uses a for loop to write it on the board 20 times. |
→ 46 |
Any of the socket I/O statements can throw exceptions. They are all caught here as a generic exception, and the diagnostic information is sent to the console so you can debug any problems that might arise. |
→ 50 |
The getSocket method accepts a port number as a parameter and returns a socket that's connected via the specified port. This method doesn't give up until the user enters the name of a host the program can connect to. |
→ 62 |
The host name is read from the console. |
→ 65 |
The static getByName method of the InetAddress class is called to get an IP address for the host name entered by the user. Note that if the user enters a host name that doesn't exist, UnknownHostException is thrown. This exception is caught in line 69. |
→ 66 |
Now that you have an IP address, this line tries to create a Socket object using the specified address and port. This method throws IOException if it isn't able to connect to the IP address and port. |
→ 67 |
If you make it to this line, you can assume the socket has been created and you're connected. So the return statement passes the socket back to the caller, in line 13. |
Open table as spreadsheet
The BartServer program presented in the previous section works fine, but it has one major deficiency: It handles connections for only one client. To make matters worse, it quits when that client disconnects. That's not much of a server.
So after much user feedback, I decided to release BartServer 2.0, with new and improved features. BartServer 2.0 uses threads to allow multiple clients to connect to the server at the same time. Each time a client connects, a thread is started to process any requests for that client. The main thread continues to run, waiting for other clients to connect. Figure 2-2 shows the multithreading features of BartServer 2.0 in action. Listing 2-5 shows the code for version 2.0 of BartServer.
Figure 2-2: BartClients galore!
Listing 2-5: BartServer 2.0
import java.net.*; import java.io.*; import java.util.*; public class BartServer2 { public static void main(String[] args) { int port = 1234; BartQuote bart = new BartQuote(); try { System.out.println("BartServer 2.0"); System.out.println("Listening on port " + port); ServerSocket ss = new ServerSocket(port); while (true) → 19 { Socket s = ss.accept(); System.out.println( "Connection established!"); Thread t = new Thread( new BartThread(s, bart)); → 25 t.start(); } } catch (Exception e) { System.out.println("System exception!"); } } } class BartThread implements Runnable → 36 { private Socket s; private BartQuote bart; public BartThread(Socket socket, BartQuote bart) → 41 { this.s = socket; this.bart = bart; } public void run() → 47 { String client = s.getInetAddress().toString(); System.out.println("Connected to " + client); try { Scanner in = new Scanner(s.getInputStream()); PrintWriter out; out = new PrintWriter(s.getOutputStream(), true); out.println("Welcome to the Bart Server"); out.println("Enter BYE to exit."); while (true) { String input = in.nextLine(); if (input.equalsIgnoreCase("bye")) break; else if (input.equalsIgnoreCase("get")) { out.println(bart.getQuote()); System.out.println("Serving " + client); } else out.println("Huh?"); } out.println("So long, suckers!"); s.close(); } catch (Exception e) { e.printStackTrace(); } System.out.println("Closed connection to " + client); } }
Most of this code is the same as the code in version 1.0, so I just highlight the key changes:
→ 19 |
A while loop is used to service connection requests through the accept method of the ServerSocket object. |
|||
→ 25 |
Each time a new client connects, a thread is created using the BartThread class to create the thread's Runnable object. Then, this thread is started. In the meantime, the main thread stays in the while loop, waiting for other clients to connect.
|
|||
→ 36 |
The BartThread handles the processing required for each connected client. This class implements Runnable, which means it must define a run method. The run method is called each time a new thread is created. |
|||
→ 41 |
The constructor for the BartThread class initializes the two class fields with values passed as parameters from the main thread. These parameters are the Socket object the client is connected to and a shared copy of the BartQuote object that was created by the main thread.
|
|||
→ 47 |
The run method services the requests for a single client connected to the BartServer. Most of the code in this method was simply copied straight from the previous version, so you shouldn't have any trouble understanding how this method works. |
Book I - Java Basics
Book II - Programming Basics
Book III - Object-Oriented Programming
Book IV - Strings, Arrays, and Collections
Book V - Programming Techniques
Book VI - Swing
Book VII - Web Programming
Book VIII - Files and Databases
Book IX - Fun and Games