Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Professional C++ [eng].pdf
Скачиваний:
284
Добавлен:
16.08.2013
Размер:
11.09 Mб
Скачать

Chapter 24

You could imagine such a game that actually was implemented in a distributed manner. Instead of one machine sending an event to the other machine and processing the result independently, the processing could be performed once, spread across the two machines. As shown in Figure 24-2, Machine A might send the event and let Machine B determine what the outcome is. From the point of view of Machine A, some of the data processing occurs externally, which is a good indication that it is running a distributed application.

Machine 1

Machine 2

Machine A

Machine B

Player A shoots gun

Machine A sends event Machine B receives event

Machine B calculates result

Machine A receives result Machine B sends result

Figure 24-2

Distributed Objects

Distributed computing existed before object-oriented programming (OOP) became popular, so the two ideas are definitely distinct. However, the application of OOP concepts to distributed computing yields powerful new abstractions. If you imagine calling a method on an object that actually exists on a computer thousands of miles away, or passing an object between hosts on a network, you start to see how nicely OOP meshes with distributed computing.

Serialization and Marshalling

Fundamentally, transmitting raw data is all that a network knows how to do. Networks don’t know anything about C++, objects, or code execution. They simply move data from one place to another. This simplicity is one of the greatest features of networks. A heterogeneous collection of computers, with various architectures and operating systems, can participate on the same network because the network makes few assumptions about the environments of its participants.

For distributed applications, the simplicity of networking presents a slight problem. It would be nice if you could send an object from one machine to another simply by calling a function that puts that object on the network, but it’s more complicated than that because the network doesn’t know about objects.

Instead, you need to convert the object into raw bytes. Instead of sending the actual object, you must send data that describes the object. The recipient needs to interpret the raw bytes to reconstruct what will hopefully be a duplicate of the original.

696

Exploring Distributed Objects

The process of converting an in-memory object to a flattened raw representation is known as serialization or marshalling. The process of reconstructing the object is called deserialization or unmarshalling. You may be familiar with marshalling from Chapter 14, which showed an example of using a string to represent an object. Marshalling is useful for more than just networking. If you want to save an object to disk, you will most likely marshal it into a flattened format first.

Serialization in Action

Consider the following function declarations, which provide the ability to send data to another computer over the network and receive data from another computer. As explained in Chapter 18, networking isn’t a built-in capability of C++, so the actual networking library provided by your operating system will certainly be different from that in this extremely simple version.

/**

* Sends data to another host on the network

*

* @param inHostName

the

name of the other machine

* @param inData

the

data you want to send

*/

 

 

void send(const string& inHostName, const string& inData);

/**

* Receives incoming data from the network

*

* @return the data that was received */

string read();

Imagine that you are writing an inventory control application for a company that has warehouses throughout the United States. Each warehouse location will run a copy of the program, but the program needs to be able to fulfill orders for any location. In other words, you can use the program running in Pittsford, New York to order an item at the warehouse in Onion Creek, Washington.

Because all of the programs at all of the locations use the same Order class to represent an order, what you really want to do is send orders over the network from Pittsford to Onion Creek. Here is a class definition for the Order class:

// Order.h

class Order

{

public:

Order();

int getItemNumber() const;

void setItemNumber(int inItemNumber);

int getQuantity() const;

void setQuantity(int inQuantity);

int getCustomerNumber() const;

void setCustomerNumber(int inCustomerNumber);

697

Chapter 24

protected:

int mItemNumber; int mQuantity;

int mCustomerNumber;

};

At this point, there is a mismatch between the data you want to send (an object) and the capabilities of the network functions, which only process strings. The solution is to add serialization and deserialization capabilities to the Order class. The new class definition is shown here:

// Order.h

#include <string>

class Order

{

public:

Order();

int getItemNumber() const;

void setItemNumber(int inItemNumber);

int getQuantity() const;

void setQuantity(int inQuantity);

int getCustomerNumber() const;

void setCustomerNumber(int inCustomerNumber);

/**

*Converts the object into raw data that can be sent over the

*network

*

* @return a string representing this object */

std::string serialize();

/**

* Adjusts this object to represent the data in inData

*

* @param inData a string representing Order data */

void deserialize(const std::string& inData);

protected:

int mItemNumber; int mQuantity;

int mCustomerNumber;

};

The implementation of the Order class follows. Only the serialization methods are highlighted because the rest of the class implementation is remarkably uninteresting.

698

Exploring Distributed Objects

// Order.cpp

#include “Order.h” #include <iostream> #include <sstream> #include <string>

using namespace std;

Order::Order() : mItemNumber(-1), mQuantity(-1), mCustomerNumber(-1)

{

}

int Order::getItemNumber()

{

return mItemNumber;

}

void Order::setItemNumber(int inItemNumber)

{

mItemNumber = inItemNumber;

}

int Order::getQuantity()

{

return mQuantity;

}

void Order::setQuantity(int inQuantity)

{

mQuantity = inQuantity;

}

int Order::getCustomerNumber()

{

return mCustomerNumber;

}

void Order::setCustomerNumber(int inCustomerNumber)

{

mCustomerNumber = inCustomerNumber;

}

string serialize()

{

// Use a stream to output all the values, separated by tabs. ostringstream outStream;

outStream << getItemNumber() << “\t” << getQuantity() << “\t” << getCustomerNumber();

return outStream.str();

}

699