|
Many of us have had to write code
that uses IPC (perhaps TCP/IP) to transfer data items
between processes. When the processes reside on the same
system, there are few issues to deal with. However, when
transferring data between systems that may have
different byte orders, there are suddenly some real
issues to tackle. How you decide to handle byte ordering
is critical. Which side does what to the data in order
to assure that the receiver ends up with the same
information that the sender sent?
If you've programmed much with the Sockets API,
you're familiar with the venerable "host-to-net" and
"net-to-host" conversion functions. These functions are
used to put data into "network byte order." Network
order is defined by the TCP/IP suite as "big endian."
Sun SPARC is big endian; x86 is little endian. The usual
way these functions are used is that the sender converts
everything to network byte order and sends it over the
network. The receiver(s) convert the received data to
their native host byte order and process it. Simple and
clean.
Now, let's throw in another wrinkle. Some hardware
architectures have alignment requirements. For example,
to access a 4-byte (32-bit) quantity (at least
efficiently) on many platforms, the datum must be 4-byte
aligned. Other architectures have different, or no,
restrictions. So when sending multiple items across a
network (say, a variable-length string, a 2-byte
integer, and a 8-byte double float) how the items are
arranged in the data stream is another level of issue
over the byte order. In order for applications written
by different organizations to interoperate, systems were
invented (such as Sun RPC encoding) to handle this
marshaling of data for transmission.
As network usage has grown over the years,
performance has become more and more important.
Applications sending lots of network data that's always
converting byte order can consume significant amounts of
CPU resources. When this ends up being a waste, such as
two x86 machines exchanging data with each end swapping
bytes, the byte order issue becomes a big target for
optimization.
Common Data Representation (CDR) was introduced in
CORBA. CORBA uses CDR to marshal (order, pack, and
align) data for transmission. It provides a way to
encode binary data for transmission in what's referred
to as "receiver makes right" fashion. CDR also defines
data packing, padding, and alignment rules for all data
sent in CDR form. Because CDR is flexible, portable, and
efficient, it's used in many applications outside of
CORBA. And since ACE contains a CDR implementation, ACE
users can use it as well.
The "receiver makes right" scheme
in CDR works thusly: The sender sends binary data in its
native byte order, whatever it is. To allow the
receiver(s) to know what byte order the data is using,
the sender must somehow inform receivers of the
transmission byte order. Usually, this is done by
sending a byte order indication byte at the start of a
session. When data is received, the receiver is
responsible for any byte order conversion that may be
needed. That's why it's called "receiver makes right."
If there's no need to swap bytes (such as in the case of
2 x86 machines exchanging information in little endian
order) then there's no need to use CPU time swapping
bytes.
The data alignment and packing rules in CDR are...
well... you don't need to care. It's all taken care of
in CDR and, thus, in ACE. That's the beauty of using
ACE's CDR facility. The players in a protocol session
simply agree (usually by protocol definition) what data
will be sent. The packing, ordering, and padding are all
taken care of on both the sending and receiving side.
C++NPv1 chapter 4 explains how the book's logging client
and server applications use CDR to transfer logging
records. It's a good starting place for your efforts to
design a portable, high-performance, data transmission
protocol on your next project. If you would like to
discuss how best to use CDR, let us know! We're here to
help you make the most of ACE's power and flexibility.
|