I l @ ve RuBoard |
MotivationThe 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 CapabilitiesThe ACE_SOCK_Acceptor class is a factory [GHJV95] that establishes a new endpoint of communication passively . It provides the following capabilities:
The interface of the ACE_SOCK_Acceptor class is shown in Figure 3.8 on page 65 and its two key methods are outlined in the following table:
Figure 3.8. The ACE_SOCK_Acceptor Class Diagram
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 principles that underlie these and other ACE wrapper facade design choices are described in Appendix A. ExampleWe 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 :
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., 510) 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.
|
I l @ ve RuBoard |