I l @ ve RuBoard |
MotivationAn area of accidental complexity identified in Section 2.3 is the inability to detect socket misuse at compile-time. As described in Section 3.1, connection management involves three roles: active connection role, passive connection role, and communication role. The Socket API, however, defines only two socket modes: data mode and passive mode. Developers can therefore misuse sockets in ways that can't be detected during compilation. The ACE_SOCK_Connector class took the first step toward resolving this area of complexity; the ACE_SOCK_Stream class takes the next step. ACE_SOCK_Stream defines a data-mode "transfer-only" object. An ACE_SOCK_Stream object can't be used in any role other than data transfer without intentionally violating its interface. Class CapabilitiesThe ACE_SOCK_Stream class encapsulates the data transfer mechanisms supported by data-mode sockets. This class provides the following capabilities:
ACE_SOCK_Stream instances are initialized by the ACE_SOCK_Acceptor or ACE_SOCK_Connector factories. The interface of the ACE_SOCK_Stream and ACE_SOCK_IO classes are shown in Figure 3.7 on page 61. ACE_SOCK_ Stream derives from ACE_SOCK_IO , which itself derives from ACE_SOCK and defines basic data transfer methods that are reused by the ACE UDP wrapper facades. Figure 3.7. The ACE_SOCK_Stream and ACE_SOCK_IO Class Diagrams
The key methods exported through ACE_SOCK_Stream are outlined in the following table:
The ACE_SOCK_Stream class supports blocking, timed, and nonblocking I/O, where blocking I/O is the default. Timed I/O is useful when communicating with peers that can hang or block indefinitely. Two types of ACE_Time_Value values can be passed to the ACE_SOCK_Stream I/O methods to control their time-out behavior:
Nonblocking I/O is useful for applications that can't afford to block when data isn't sent or received immediately. Blocking versus nonblocking I/O can be controlled via the enable() and disable() methods inherited from ACE_IPC_SAP : peer.enable (ACE_NONBLOCK); // Enable nonblocking I/O. peer.disable (ACE_NONBLOCK); // Disable nonblocking I/O. If an I/O method is invoked on an instance of ACE_SOCK_Stream that's in nonblocking mode and the call would block, a “1 is returned and errno is Set to EWOULDBLOCK. ExampleNow that we've examined the capabilities of ACE_SOCK_Stream , we can show the data transfer portion of our Web client example begun on page 59 in Section 3.5. This code sends an HTTP GET request for a particular URL path name and then prints out the contents of the file that's downloaded from the Web server. // ...Connection code from example in Section 3.5 omitted... char buf [BUFSIZ]; iovec iov[3]; iov[0].iov_base = "GET "; iov[0].iov_len = 4; // Length of "GET ". iov[1].iov_base = pathname; iov[1].iov_len = strlen (pathname); iov[2] iov_base = " HTTP/1.0\r\n\r\n" ; iov[2].iov_len = 13; // Length of " HTTP/1.0\r\n\r\n"; if (peer.sendv_n (iov, 3) == -1) return 1; for (ssize_t n; (n = peer.recv (buf, sizeof buf)) > 0; ) ACE::write_n (ACE_STDOUT, buf, n); return peer, close (); } We use an array of iovec structures to transmit the HTTP GET request to the Web server efficiently using the ACE_SOCK_Stream: :sendv_n() gather-write method. This avoids performance issues with Nagle's algorithm [Ste93] described in Sidebar 6. On UNIX/POSIX platforms this method is implemented via writev () and on WinSock2 platforms it's implemented via WSASend() . The I/O methods in the client_download_file() function will block if they encounter TCP flow control or if the Web server misbehaves. To prevent the client from hanging indefinitely, we can add time-outs to these method calls. In the following code, for instance, if the server doesn't receive the data in 10 seconds, a “1 will be returned with errno set to ETIME: // Wait no more than 10 seconds to send or receive data. ACE_Time_Value timeout (10); peer.sendv_n (iov, 3, &timeout); while (peer.recv (buf, sizeof buf, &timeout) > 0) // ... process the contents of the downloaded file.
|
I l @ ve RuBoard |