Home > Articles > Programming > Java

  • Print
  • + Share This
Like this article? We recommend

Like this article? We recommend

Working with Stream Sockets

Whenever you need a reliable connection for sending and receiving multiple messages between two network-aware programs, use a stream socket. A stream socket depends on TCP to ensure that a message arrives at its destination without errors. In practice, it is quite likely that IP packets will get lost on the network or that they will arrive with errors. In either case, the receiving TCP will contact the sending TCP to resend those IP packets. That is how a reliable connection is established between two stream sockets.

Stream sockets play a necessary role in client/server programs. A client program (that is, a network-aware program that needs access to some service) attempts to create a stream socket object with the IP address of a server program's host and the port number of the server program (that is, a network-aware program that provides a service to client programs).

The client program's stream socket initialization code passes the IP address and port number to the client host's network-management software. That software forwards the IP address and port number (via IP) through the NIC to the server host. The server host's network-management software reads that data (via IP) from the NIC and attempts to verify that the server program is listening for connection requests via its stream socket on the specified port. The server host's network-management software responds to the client host's network-management software with a positive acknowledgment if the server program is listening. In response, the client program's stream socket initialization code establishes a port number for the client program, passes that number (via the client and server hosts' network-management software) to the server program's stream socket (which uses that number to identify the client program to which messages will be sent), and completes initialization of the stream socket object.

If the server program is not listening on the port, the server host's network-management software responds to the client host's network-management software with a negative acknowledgment. In response, the client program's stream socket initialization code throws an exception object and does not establish a communication link (nor does it create a stream socket object). This scenario is analogous to a telephone call. A caller dials someone and the phone rings. A conversation ensues when someone picks up the phone. Otherwise, the caller hangs up.

This section works with stream sockets in the context of three classes: InetAddress, Socket, and ServerSocket. InetAddress objects represent 32-bit or 128-bit IP addresses, Socket objects represent client program stream sockets, and ServerSocket objects represent server program stream sockets. All three classes can be found in the java.net package.

The InetAddress Class

The InetAddress class plays a prominent role in the Network API's stream socket and datagram socket classes: Some arguments passed to various stream socket class/datagram socket class constructors and nonconstructor methods are of type InetAddress. InetAddress objects represent 32-bit or 128-bit IP addresses. To help it accomplish that task, InetAddress relies upon two support classes, Inet4Address and Inet6Address. Those three classes form a hierarchy in which InetAddress is the parent class and Inet4Address and Inet6Address (which extend InetAddress) are the child classes.

Because InetAddress has only one constructor, and because that no-argument constructor has package access, it is not possible to directly create an InetAddress object, as in InetAddress ia = new InetAddress ();. Instead, you need to call one of the following five factory methods to return either a single InetAddress object or an array of InetAddress objects:

  • The getAllByName(String host) method returns an array of references to InetAddress objects. Each object contains a single IP address that corresponds to the name of the host passed in the host argument. If no IP addresses exist for the specified host, the method throws an UnknownHostException object.

  • The getByAddress(byte [] addr) method returns a reference to an InetAddress object that contains an IP address corresponding to the IPv4 address specified in the 4-byte addr array or to the IPv6 address specified in the 16-byte addr array. If the array is neither 4 bytes nor 16 bytes long, the method throws an UnknownHostException object.

  • The getByAddress(String host, byte [] addr) method returns a reference to an InetAddress object that contains an IP address corresponding to the IPv4 address specified by a combination of the host and 4-byte addr array, or to the IPv6 address specified by a combination of the host and 16-byte addr array. If the array is neither 4 bytes nor 16 bytes long, the method throws an UnknownHostException object.

  • The getByName(String host) method returns a reference to an InetAddress object that contains an IP address corresponding to the name of the host passed in the host argument. Internally, getAllByName(String host) is called and the first entry in its array gets returned to the caller. If no IP addresses exist for the specified host, the called method throws an UnknownHostException object.

  • The getLocalHost() method returns a reference to an InetAddress object that contains the IP address of the local host. Think of the local host as the host on which the client program runs or server program runs. To eliminate confusion, the client program's local host is the client host and the server program's local host is the server host.

Each of the aforementioned methods mentions returning a reference to an InetAddress object or references to multiple InetAddress objects. In reality, each method returns one or more references to Inet4Address/Inet6Address objects. The caller doesn't need to know a reference's subclass. Instead, the caller makes calls to InetAddress's nonstatic methods using a returned reference, and inclusion (subtype) polymorphism ensures that the appropriate subclass overridden methods get called.

InetAddress and its subclasses handle the task of converting from a host's name (also known as a domain name) to the host's IPv4 or IPv6 address. To perform the conversion, the Domain Name System (or another name service, such as the Network Information Service), is used (behind the scenes). The following code fragment demonstrates obtaining a reference to an InetAddress subclass object by calling the getByName(String host) method. That object contains the IP address that corresponds to the host argument. Behind the scenes, a name service maps the hostname to the IP address.

InetAddress ia = InetAddress.getByName ("www.javajeff.com"));

NOTE

To resolve the name into an IP address, InetAddress requires a connection to the Internet. That connection is used to access the Domain Name System.

Once you obtain an InetAddress subclass object reference, you can call various InetAddress methods to obtain information about the IP address contained in the InetAddress subclass object. For example, you can call getCanonicalHostName() to retrieve the standardized hostname from a name service, getHostAddress() to obtain the IP address, getHostName() to retrieve the hostname passed as an argument to one of the earlier static get methods (or the standardized hostname, if a name was not specified), and isLoopbackAddress() to find out whether the IP address is the loopback address (a special IP address that allows network-management software to treat outgoing messages as incoming messages).

Listing 1 presents source code to InetAddressDemo. That program lets you experiment with the InetAddress class.

Listing 1: InetAddressDemo.java

// InetAddressDemo.java

import java.net.*;

class InetAddressDemo
{
   public static void main (String [] args) throws UnknownHostException
   {
      String host = "localhost";

      if (args.length == 1)
          host = args [0];

      InetAddress ia = InetAddress.getByName (host);

      System.out.println ("Canonical Host Name = " +
                          ia.getCanonicalHostName ());
      System.out.println ("Host Address = " +
                          ia.getHostAddress ());
      System.out.println ("Host Name = " +
                          ia.getHostName ());
      System.out.println ("Is Loopback Address = " +
                          ia.isLoopbackAddress ());
   }
}

When run with no command-line arguments, InetAddressDemo presents the following output:

Canonical Host Name = localhost
Host Address = 127.0.0.1
Host Name = localhost
Is Loopback Address = true

InetAddressDemo gives you the option of specifying a hostname as a command-line argument. If no hostname is specified, localhost (the client host) is used. InetAddressDemo obtains a reference to an InetAddress subclass object by calling getByName(String host). Using that reference, the canonical hostname, host address, hostname, and information on whether the IP address (in the InetAddress subclass object) is the loopback address are output. (127.0.0.1[md]localhost[md]is shown to be the loopback address.)

The Socket Class

When a client program needs to communicate with a server program, the client program creates a Socket object on the client host. A close look at the Socket class reveals several constructors. Two commonly used constructors are Socket(InetAddress addr, int port) and Socket(String host, int port). Both constructors create a Socket-based stream socket that connects to another stream socket on a server host. For the first constructor, the InetAddress subclass object referenced by addr contains the IP address of the server host. For the second constructor, the server host argument is resolved into an InetAddress. If no IP address associates with host, an UnknownHostException object is thrown. Both constructors obtain the server stream socket's port from the port argument. Assuming that a connection is established, the Network API binds the client host's IP address and an arbitrary unique port number to the client program's Socket-based stream socket. Otherwise, either constructor throws an IOException object.

If a Socket object is created, it's possible to obtain an input stream to read a message from the server program by calling the Socket's getInputStream() method, and to obtain an output stream to send a message to the server program by calling the Socket's getOutputStream() method. After the reading and writing activities have finished, the streams and the stream socket should be closed. That occurs when the client program calls the close() methods for the streams and the Socket. The following code fragment illustrates an attempt to create a Socket object that identifies the IP address of a server host as 198.163.227.6 and the port number of a server program as 13, obtain an input stream from the newly created stream socket, and close the stream and stream socket:

Socket s = new Socket ("198.163.227.6", 13);
InputStream is = s.getInputStream ();
// Read from the stream.
is.close ();
s.close ();

To put the aforementioned concepts into perspective, I've written a stream socket client program. That program attempts to create a Socket object that contacts a server program running on port 10,000 of a specific host. If successful, the client program sends a series of commands to the server program and prints the server program's responses. The source code to the SSClient program appears in Listing 2.

Listing 2: SSClient.java

// SSClient.java

import java.io.*;
import java.net.*;

class SSClient
{
   public static void main (String [] args)
   {
      String host = "localhost";

      // If user specifies a command-line argument, that argument
      // represents the host name.

      if (args.length == 1)
          host = args [0];

      BufferedReader br = null;
      PrintWriter pw = null;
      Socket s = null;

      try
      {
          // Create a socket that attempts to connect to the server
          // program on the host at port 10000.

          s = new Socket (host, 10000);

          // Create an input stream reader that chains to the socket's
          // byte-oriented input stream. The input stream reader
          // converts bytes read from the socket to characters. The
          // conversion is based on the platform's default character
          // set.

          InputStreamReader isr;
          isr = new InputStreamReader (s.getInputStream ());

          // Create a buffered reader that chains to the input stream
          // reader. The buffered reader supplies a convenient method
          // for reading entire lines of text.

          br = new BufferedReader (isr);

          // Create a print writer that chains to the socket's byte-
          // oriented output stream. The print writer creates an
          // intermediate output stream writer that converts
          // characters sent to the socket to bytes. The conversion
          // is based on the platform's default character set.

          pw = new PrintWriter (s.getOutputStream (), true);

          // Send the DATE command to the server.

          pw.println ("DATE");

          // Obtain and print the current date/time.

          System.out.println (br.readLine ());

          // Send the PAUSE command to the server. This allows several
          // clients to start and verifies that the server is spawning
          // multiple threads.

          pw.println ("PAUSE");

          // Send the DOW command to the server.

          pw.println ("DOW");

          // Obtain and print the current day of week.

          System.out.println (br.readLine ());

          // Send the DOM command to the server.

          pw.println ("DOM");

          // Obtain and print the current day of month.

          System.out.println (br.readLine ());

          // Send the DOY command to the server.

          pw.println ("DOY");

          // Obtain and print the current day of year.

          System.out.println (br.readLine ());
      }
      catch (IOException e)
      {
          System.out.println (e.toString ());
      }
      finally
      {
          try
          {
              if (br != null)
                  br.close ();

              if (pw != null)
                  pw.close ();

              if (s != null)
                  s.close ();
          }
          catch (IOException e)
          {
          }
      }
   }
}

When run, SSClient produces output similar to the following:

Tue Jan 29 18:11:51 CST 2002
TUESDAY
29
29

SSClient attempts to create a Socket object to communicate with a server program running on port 10,000 of a host whose IP address is identified by the host variable. If successful, SSClient obtains the Socket's input and output streams, wraps the input stream in a BufferedReader, and wraps the output stream in a PrintWriter to facilitate the reading and writing of String objects. Using PrintWriter and BufferedReader, SSClient sends various date/time commands to the server program and obtains responses (for most of the commands). Each response prints; once the final response has printed, the Finally clause of the Try/Catch/Finally construct executes. That clause closes both the BufferedReader and the PrintWriter before closing the socket.

Once you compile SSClient's source code, you can run that program by typing java SSClient. If an appropriate server program is running on a different host than SSClient, specify the server host's name/IP address as an argument to java SSClient. For example, if www.javajeff.com is the name of the server program's host, type java SSClient www.javajeff.com. (An appropriate server program appears in the next section.)

TIP

The Socket class contains many useful methods. For example, getLocalAddress() returns a reference to an InetAddress subclass object containing the client host's IP address, getLocalPort() returns the port number that identifies the client program, getInetAddress() returns a reference to an InetAddress subclass object containing the server host's IP address, and getPort() returns the port number that identifies the server program.

The ServerSocket Class

Because SSClient uses a stream socket, you need to use a stream socket for the server program. That requires you to create an object from the ServerSocket class. A close look at ServerSocket reveals several constructors. One of the simpler constructors is ServerSocket(int port). When you create a ServerSocket object with that constructor, pass the port number in the port argument of the port to which the server listens for connection requests. If there is a problem, the constructor throws an IOException object. Otherwise, a ServerSocket object is created and ready to accept connections.

At this point, server programs typically enter infinite loops. An infinite loop begins with a call to ServerSocket's accept() method. When called, accept() causes the calling thread to block until a connection occurs. When there is a connection, accept() returns a reference to a newly created Socket object. That Socket object is bound to the client program's IP address/port number.

Because it is possible for a single server program to communicate with multiple client programs, it shouldn't take much time for the server program to respond to a client program. Otherwise, some client programs might wait a long time until they get serviced. However, a conversation between a server program and a client program across a stream socket can become lengthy. (Think of a telephone conversation as an analogy.) To rapidly respond to client program connection requests, the server program typically starts a background thread. That thread handles communication between the server program and the client program associated with the Socket that accept() returns.

To illustrate the aforementioned concepts and to complement the SSClient program, I've created an SSServer program. That program attempts to create a ServerSocket object that listens for incoming connection requests on port 10,000. If successful, the server program waits for incoming connections, starts a thread to handle each connection, and responds (in the thread) to commands sent from the client program. Listing 3 presents that program's source code.

Listing 3: SSServer.java

// SSServer.java

import java.io.*;
import java.net.*;
import java.util.*;

class SSServer
{
   public static void main (String [] args) throws IOException
   {
      System.out.println ("Server starting...\n");    

      // Create a server socket that listens for incoming connection
      // requests on port 10000.

      ServerSocket server = new ServerSocket (10000);

      while (true)
      {
         // Listen for incoming connection requests from client
         // programs, establish a connection, and return a Socket
         // object that represents this connection.

         Socket s = server.accept ();

         System.out.println ("Accepting Connection...\n");

         // Start a thread to handle the connection.

         new ServerThread (s).start ();
      }
   }
}

class ServerThread extends Thread
{
   private Socket s;

   ServerThread (Socket s)
   {
      this.s = s;
   }

   public void run ()
   {
      BufferedReader br = null;
      PrintWriter pw = null;

      try
      {
          // Create an input stream reader that chains to the socket's
          // byte-oriented input stream. The input stream reader
          // converts bytes read from the socket to characters. The
          // conversion is based on the platform's default character
          // set.

          InputStreamReader isr;
          isr = new InputStreamReader (s.getInputStream ());

          // Create a buffered reader that chains to the input stream
          // reader. The buffered reader supplies a convenient method
          // for reading entire lines of text.

          br = new BufferedReader (isr);

          // Create a print writer that chains to the socket's byte-
          // oriented output stream. The print writer creates an
          // intermediate output stream writer that converts
          // characters sent to the socket to bytes. The conversion
          // is based on the platform's default character set.

          pw = new PrintWriter (s.getOutputStream (), true);

          // Create a calendar that makes it possible to obtain date
          // and time information.

          Calendar c = Calendar.getInstance ();

          // Because the client program may send multiple commands, a
          // loop is required. Keep looping until the client either
          // explicitly requests termination by sending a command
          // beginning with letters BYE or implicitly requests
          // termination by closing its output stream.

          do
          {
              // Obtain the client program's next command.

              String cmd = br.readLine ();

              // Exit if client program has closed its output stream.

              if (cmd == null)
                  break;

              // Convert command to uppercase, for ease of comparison.

              cmd = cmd.toUpperCase ();

              // If client program sends BYE command, terminate.

              if (cmd.startsWith ("BYE"))
                  break;

              // If client program sends DATE or TIME command, return
              // current date/time to the client program.

              if (cmd.startsWith ("DATE") || cmd.startsWith ("TIME"))
                  pw.println (c.getTime ().toString ());

              // If client program sends DOM (Day Of Month) command,
              // return current day of month to the client program.

              if (cmd.startsWith ("DOM"))
                  pw.println ("" + c.get (Calendar.DAY_OF_MONTH));

              // If client program sends DOW (Day Of Week) command,
              // return current weekday (as a string) to the client
              // program.

              if (cmd.startsWith ("DOW"))
                  switch (c.get (Calendar.DAY_OF_WEEK))
                  {
                     case Calendar.SUNDAY   : pw.println ("SUNDAY");
                                              break;

                     case Calendar.MONDAY   : pw.println ("MONDAY");
                                              break;

                     case Calendar.TUESDAY  : pw.println ("TUESDAY");
                                              break;

                     case Calendar.WEDNESDAY: pw.println ("WEDNESDAY");
                                              break;

                     case Calendar.THURSDAY : pw.println ("THURSDAY");
                                              break;

                     case Calendar.FRIDAY   : pw.println ("FRIDAY");
                                              break;

                     case Calendar.SATURDAY : pw.println ("SATURDAY");
                  }

              // If client program sends DOY (Day of Year) command,
              // return current day of year to the client program.

              if (cmd.startsWith ("DOY"))
                  pw.println ("" + c.get (Calendar.DAY_OF_YEAR));

              // If client program sends PAUSE command, sleep for three
              // seconds.

              if (cmd.startsWith ("PAUSE"))
                  try
                  {
                      Thread.sleep (3000);
                  }
                  catch (InterruptedException e)
                  {
                  }
          }
          while (true);
      }
      catch (IOException e)
      {
          System.out.println (e.toString ());
      }
      finally
      {
          System.out.println ("Closing Connection...\n");

          try
          {
              if (br != null)
                  br.close ();

              if (pw != null)
                  pw.close ();

              if (s != null)
                  s.close ();
          }
          catch (IOException e)
          {
          }
      }
   }
}

When run, SSServer produces output similar to the following:

Server starting...

Accepting Connection...

Closing Connection...

SSServer's source code declares a pair of classes: SSServer and ServerThread. SSServer's main() method attempts to create a ServerSocket object that listens for connection requests on port 10,000. If successful, SSServer enters an infinite loop that alternately calls ServerSocket's accept() method, to wait for a connection request, and starts a background thread to handle the connection (returned by accept() as a Socket object). The thread starts as a result of a call to ServerThread's inherited start() method and begins executing code in ServerThread's run() method.

Once in the run() method, the thread creates BufferedReader, PrintWriter, and Calendar objects and enters a loop. The loop begins by reading a line of text (via BufferedReader's readLine() method) from the client program's socket. That text (a command) is stored in a String object that cmd references. What happens if the client program prematurely closes its output stream? The answer: null assigns to cmd. (SSClient does not prematurely close its output stream, but defensive programming is a good idea.)

CAUTION

Care is needed to deal with situations in which the client program might close its output stream while the server program is reading from that stream. If this is not dealt with, exceptions can occur.

The thread continues executing the loop by discovering which command was entered, BYE, DATE, DOM (Day Of Month), DOW (Day Of Week), DOY (Day Of Year), PAUSE, or TIME. To facilitate that task, the thread uppercases the contents of the String object and uses String's startsWith(String prefix) method. If cmd's text begins with BYE, DATE, DOM, DOW, DOY, PAUSE, or TIME, equivalent code is executed. Usually, that involves calling a Calendar method and sending its response to the client program. However, if the command is BYE, the loop terminates. If it is PAUSE, the server program sleeps for three seconds, to give you time to start more than one client program to observe multiple server threads. At some point, the thread closes the reader, writer, and socket.

NOTE

Many standardized Internet programs, such as Post Office Protocol 3 (POP3), Simple Mail Transfer Protocol (SMTP), and Hypertext Transfer Protocol (HTTP), follow a command-response pattern.

Once you compile SSServer's source code, you can run that program by typing java SSServer. After you start SSServer, you can then run one or more copies of SSClient.

TIP

The accept() method blocks until a connection request arrives. If that behavior is unacceptable for certain programs, call ServerSocket's setSoTimeout(int timeout) method. When called with a nonzero value in timeout, accept() blocks for the specified amount of time. When that time expires before a connection request arrives, that method throws an exception.

  • + Share This
  • 🔖 Save To Your Account

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020