4.3 The ACE_InputCDR and ACE_OutputCDR Classes

I l @ ve RuBoard

Motivation

Networked applications that send and receive messages often require support for

  • Linearization to handle the conversion of richly typed data, such as arrays, linked lists, or graphs, to/from raw memory buffers

  • Marshaling/demarshaling to correctly interoperate in environments with heterogeneous compiler alignment constraints and hardware instructions with different byte-ordering rules

Since it's hard to manually perform linearization, marshaling, and de-marshaling correctly and efficiently , these operations are best encapsulated in reusable classes, which is why ACE provides ACE_OutputCDR and ACE_InputCDR .

Class Capabilities

The ACE_OutputCDR and ACE_InputCDR classes provide a highly optimized, portable, and convenient means to marshal and demarshal data using the standard CORBA Common Data Representation (CDR) format [Obj01]. ACE_ OutputCDR creates a CDR buffer from a data structure (marshaling) and ACE_InputCDR extracts data from a CDR buffer (demarshaling).

The ACE_OutputCDR and ACE_InputCDR classes support the following features:

  • They provide operations to (de)marshal the following types:

    - Primitive types, for example, booleans; 16-, 32-, and 64-bit integers; 8-bit octets; single and double precision floating point numbers ; characters ; and strings

    - Arrays of primitive types

  • The insertion ( << ) and extraction ( >> ) operators can be used to marshal and demarshal primitive types, using the same syntax as the C++ iostream components .

  • They use ACE_Message_Block chains internally to avoid expensive memory copies.

  • They take advantage of CORBA CDR alignment and byte-ordering rules to avoid expensive memory copying and byte-swapping operations, respectively.

  • They provide optimized byte swapping code that uses inline assembly language instructions for common hardware platforms, such as Intel x86, and the standard htons(), htonl (), ntohs() , and ntohl () macros/functions on other platforms.

  • They support zero copy marshaling and demarshaling of octet buffers.

  • Users can define custom character set translators for platforms that do not use ASCII or UNICODE as their native character sets.

The interfaces for the ACE CDR streaming classes are shown in Figure 4.3. The key methods in ACE_OutputCDR class are shown in the following table:

Method Description
ACE_OutputCDR() Creates an empty CDR stream for insertion.
write_*() Inserts a primitive into the stream, for example, write_ ushort() .
write_*_array() Inserts an array of primitives into the stream, for example, write_long_array() .
operator<<() An insertion operator is defined for each primitive type.
good_bit() Returns 0 if the stream has detected an error.
total_length() Returns the number of bytes in the stream.
begin() Returns a pointer to the first message block in the chain.
end() Returns a pointer to the last message block in the chain.
Figure 4.3. The ACE_InputCDR and ACE_OutputCDR Class Diagrams

Likewise, the key methods for the ACE_InputCDR class are shown in the following table:

Method Description
ACE_InputCDR() Creates an empty CDR stream for extraction.
read_*() Extracts a primitive from the stream, for example, read char() .
read_*_array() Extracts an array of primitives from the stream, for example, read octet_array() .
operator>>() An extraction operator is defined for each primitive type.
good bit() Returns 0 if the stream has detected an error.
steal_contents() Returns a copy of the underlying ACE_Message_Block containing the current CDR stream.

The ACE_InputCDR and ACE_OutputCDR classes transform typed data into untyped buffers and vice versa. As a result, programmers must be careful when using these classes to prevent type system violations. One way to avoid these problems altogether is to program using distribution middleware, such as CORBA [Obj01] and The ACE ORB (TAO) [SLM98] described in Section B.1.4 on page 264.

Example

The ACE CDR streaming classes predefine operators << and >> for primitive types and arrays. ACE applications are responsible for defining these operators for their own data types. [1] To illustrate these operators, we show the ACE CDR insertion and extraction operators for the ACE_Log_Record class that's used by both the client application and logging server. This C++ class contains several fields and a variable- sized message buffer. Our insertion operation therefore marshals each field into an ACE_OutputCDR object, as shown below:

[1] These operators can also be generated automatically by tools, such as the CORBA Interface Definition Language (IDL) compiler [AOSK00] provided by TAO.

 int operator<< (ACE_OutputCDR &cdr,                 const ACE Log Record &log_record) {   size_t msglen = log_record.msg_data_len ();   // Insert each <log_record> field into the output CDR stream.   cdr << ACE_CDR::Long (log_record.type ());   cdr << ACE_CDR::Long (log_record.pid ());   cdr << ACE_CDR::Long (log_record.time_stamp ().sec ());   cdr << ACE_CDR::Long (log_record.time_stamp ().usec ());   cdr << ACE_CDR::ULong (msglen);   cdr.write_char_array (log_record.msg_data (), msglen);   return cdr.good bit (); } 

Our extraction operator demarshals each field from an ACE_InputCDR object and fills in an ACE_Log_Record object accordingly :

 int operator>> (ACE_InputCDR &cdr,                 ACE_Log_Record &log_record) {   ACE_CDR::Long type;   ACE_CDR::Long pid;   ACE_CDR::Long sec, usec;   ACE_CDR::ULong buffer_len;   // Extract each field from input CDR stream into <log_record>.   if ((cdr >> type) && (cdr >> pid) && (cdr >> sec)      && (cdr >> usec) && (cdr >> buffer_len)) {     ACE_TCHAR log_msg[ACE_Log_Record::MAXLOGMSGLEN+1];     log_record.type (type);     log_record.pid (pid);     log_record.time_stamp (ACE_Time_Value (sec, usec));     cdr.read_char_array (log_msg, buffer_len);     log_msg [buffer_len] = ' 
 int operator>> (ACE_InputCDR &cdr, ACE_Log_Record &log_record) { ACE_CDR::Long type; ACE_CDR::Long pid; ACE_CDR::Long sec, usec; ACE_CDR::ULong buffer_len; // Extract each field from input CDR stream into <log_record>. if ((cdr >> type) && (cdr >> pid) && (cdr >> sec) && (cdr >> usec) && (cdr >> buffer_len)) { ACE_TCHAR log_msg[ACE_Log_Record::MAXLOGMSGLEN+1]; log_record.type (type); log_record.pid (pid); log_record.time_stamp (ACE_Time_Value (sec, usec)); cdr.read_char_array (log_msg, buffer_len); log_msg [buffer_len] = '\0'; log_record.msg_data (log_msg); } return cdr.good_bit (); } 
'; log_record.msg_data (log_msg); } return cdr.good_bit (); }

We'll use these two insertion and extraction operators to simplify our networked logging application shortly.

I l @ ve RuBoard


C++ Network Programming
C++ Network Programming, Volume I: Mastering Complexity with ACE and Patterns
ISBN: 0201604647
EAN: 2147483647
Year: 2001
Pages: 101

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net