The ACE_SOCK_Acceptor Class





The ACE_SOCK_Acceptor Class

Motivation

The ACE_SOCK_Connector and ACE_SOCK_Stream classes resolve complexity issues that arise from the mismatch of communication roles and Socket API functions. Although the Socket API defines a single set of functions to fill the passive connection establishment role, there's an additional set of complexities. The C functions in the Socket API are weakly typed, which makes it easy to apply them incorrectly.

For example, the accept() function can be called on a data-mode socket handle that's intended to transfer data via the recv() and send() I/O operations. Likewise, the I/O operations can be called on a passive-mode socket handle factory that's intended only to accept connections. Unfortunately, these mistakes can't be detected until run time. ACE resolves these complexities with the strongly typed ACE_SOCK_Acceptor class. As opposed to direct Socket API calls, the compiler can easily detect misuse of an ACE_SOCK_Acceptor at compile time.

Class Capabilities

The ACE_SOCK_Acceptor class is a factory [GHJV95] that establishes a new endpoint of communication passively. It provides the following capabilities:

  • It accepts a connection from a peer connector and then initializes an ACE_SOCK_Stream object after the connection is established.

  • Connections can be accepted in either a blocking, nonblocking, or timed manner.

  • C++ traits are used to support generic programming techniques that enable the wholesale replacement of functionality via C++ parameterized types, as described in Sidebar 5 on page 57.

The interface of the ACE_SOCK_Acceptor class is shown in Figure on page 65 and its two key methods are outlined in the following table:

Method Description
open() Initializes the passive-mode factory socket to listen passively at a designated ACE_INET_Addr address.
accept() Initializes the ACE_SOCK stream parameter with a newly accepted client connection.

Figure. The ACE_SOCK_Acceptor Class Diagram

graphics/03fig08.gif

The ACE_SOCK_Acceptor open() and accept() methods use the socket handle inherited from ACE_IPC_SAP. This design employs the C++ type system to protect application developers from the following sources of accidental misuse:

  • The low-level socket(), bind(), and listen() functions are always called in the right order by the ACE_SOCK_Acceptor's open() method.

  • These functions are called only on a socket handle that's been initialized as a passive-mode socket handle factory.

The principles that underlie these and other ACE wrapper facade design choices are described in Appendix A.

Example

We illustrate the ACE_SOCK_Acceptor by showing the passive connection establishment and content downloading portions of an iterative Web server, which processes client requests as follows:

  1. Accept a new connection from client on port 80.

  2. Read path name from GET request and download requested file.

  3. Close the connection.

  4. Go back to step 1.

To read the file efficiently we use an ACE_Mem_Map, which is described in Sidebar 7 on page 68. To use the ACE_Mem_Map capabilities, we include ace/Mem_Map.h along with the other ACE Socket wrapper facade header files needed to write our Web server.

#include "ace/Auto_Ptr.h"
#include "ace/INET_Addr.h"
#include "ace/SOCK_Acceptor.h"
#include "ace/SOCK_Stream.h"
#include "ace/Mem_Map.h"

// Return a dynamically allocated path name buffer.
extern char *get_url_pathname (ACE_SOCK_Stream *);

Our Web server supports HTTP version 1.0, so each client request will have a separate TCP connection. In the following Web server code, we first initialize our ACE_SOCK_Acceptor factory to listen for connections on port 80. We then run an event loop that iteratively accepts a new client connection, memory-maps the file, downloads it to the client, and closes the connection when it's finished transmitting the file.

int main ()
{
  ACE_INET_Addr server_addr;
  ACE_SOCK_Acceptor acceptor;
  ACE_SOCK_Stream peer;

  if (server_addr.set (80) == -1) return 1;
  if (acceptor.open (server_addr) == -1) return 1;

  for (;;) {
    if (acceptor.accept (peer) == -1) return 1;
    peer->disable (ACE_NONBLOCK); // Ensure blocking <recv>s.

    auto_ptr <char *> pathname = get_url_pathname (peer);
    ACE_Mem_Map mapped_file (pathname.get ());

    if (peer.send_n (mapped_file.addr (),
                     mapped_file.size ()) == -1) return 1;
    peer.close ();
  }

  return acceptor.close () == -1 ? 1 : 0;
}

The primary drawback with our iterative Web server will arise when many clients send it requests simultaneously. In this case, the OS Socket implementation will queue a small number (e.g., 5–10) of connection requests while the Web server processes the current one. In a production Web server, the OS can be overwhelmed quickly. When this happens, clients can encounter errors when the Web server's OS refuses their connection attempts. Chapters 8 and 9 describe patterns and ACE wrapper facades that address this drawback.

Sidebar 7: The ACE_Mem_Map Class

The ACE_Mem_Map wrapper facade encapsulates the memory-mapped file mechanisms available on Win32 and POSIX platforms. These calls use OS virtual memory mechanisms to map flies into the address space of a process. Mapped file contents can be accessed directly via a pointer, which Is more convenient and efficient than accessing blocks of data via read and write system I/O functions. In addition, the contents of memory-mapped files can be shared by multiple processes on the same machine, as described in Section 1.3 on page 29.

The native Win32 and POSIX memory-mapped file APIs are nonportable and complex. For instance, developers must perform many bookkeeping details manually, such as explicitly opening a file, determining its length, and performing multiple mappings. In contrast, the ACE_Mem_Map wrapper facade offers an interface that simplifies common memory-mapped file usage via default values and multiple constructors with several type signature variants, for example, "map from an open file handle" or "map from a filename."


     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows