BDE 4.14.0 Production release
Loading...
Searching...
No Matches
balb_pipecontrolchannel

Detailed Description

Outline

Purpose

Provide a mechanism for reading control messages from a named pipe.

Classes

See also
bdls_pipeutil

Description

This component provides a platform-independent mechanism, balb::PipeControlChannel, for establishing, monitoring, and shutting down a named pipe. It reads text messages (generally short operational commands) from the pipe and passes them to a callback function. Note that this component does not provide a general transport mechanism over a named pipe: it is specialized for the case that the messages to be read are relatively short newline-terminated strings.

Thread Safety

This component is thread-safe but not thread-enabled, meaning that multiple threads may safely use their own instances of PipeControlChannel, but may not manipulate the same PipeControlChannel simultaneously (except that shutdown may always be called safely). The start function creates a new thread which listens to the pipe for messages until shutdown is called.

Pipe Atomicity

Users that expect multiple concurrent writers to a single pipe must be aware that the message content might be corrupted (interleaved) unless:

  1. Each message is written to the pipe in a single write system call.
  2. The length of each message is less than PIPE_BUF (the limit for guaranteed atomicity).

The value PIPE_BUF depends on the platform:

+------------------------------+------------------+
| Platform | PIPE_BUF (bytes) |
+------------------------------+------------------+
| POSIX (minimum requirement)) | 512 |
| IBM | 32,768 |
| SUN | 32,768 |
| Linux | 65,536 |
| Windows | 65,536 |
+------------------------------+------------------+

Also note that Linux allows the PIPE_BUF size to be changed via the fcntl system call.

Pipe Names

This component requires a fully-qualified native pipe name. bdlsu::PipeUtil provides a portable utility method to generate such names.

Message Format

This component requires a trailing newline ('
') character at the end of each message. This trailing newline is stripped from the message before the message is passed to the control callback.

Platform-Specific Pipe Name Encoding Caveats

Pipe-name encodings have the following caveats for the following operating systems:

Usage

This section illustrates intended use of this component.

Example 1: Controlling a Simple Server

This example illustrates how to construct a simple server that records messages sent on a pipe control channel until "EXIT" is received, at which point the channel is closed and the server stops.

First, let's define the implementation of our server.

// ===================
// class ControlServer
// ===================
class ControlServer {
// DATA
// PRIVATE MANIPULATORS
void onMessage(const bslstl::StringRef& message)
{
if ("EXIT" != message) {
d_messages.push_back(message);
}
else {
shutdown();
}
}
private:
// NOT IMPLEMENTED
ControlServer(const ControlServer&); // = delete
ControlServer& operator=(const ControlServer&); // = delete
public:
// CREATORS
explicit ControlServer(bslma::Allocator *basicAllocator = 0)
: d_channel(bdlf::BindUtil::bind(&ControlServer::onMessage,
this,
bdlf::PlaceHolders::_1),
basicAllocator)
, d_messages(basicAllocator)
{}
// MANIPULATORS
int start(const bslstl::StringRef& pipeName)
{
return d_channel.start(pipeName);
}
void shutdown()
{
d_channel.shutdown();
}
void stop()
{
d_channel.stop();
}
// ACCESSORS
bsl::size_t numMessages() const
{
return d_messages.size();
}
const bsl::string& message(int index) const
{
return d_messages[index];
}
};
Definition balb_pipecontrolchannel.h:295
int start(const char *pipeName)
Definition bslstl_string.h:1281
size_type size() const BSLS_KEYWORD_NOEXCEPT
Return the number of elements in this vector.
Definition bslstl_vector.h:2664
Definition bslstl_vector.h:1025
void push_back(const VALUE_TYPE &value)
Definition bslstl_vector.h:3760
Definition bslma_allocator.h:457
Definition bslstl_stringref.h:372
const PlaceHolder< 1 > _1
Definition bdlf_bind.h:976

Now, construct and run the server using a canonical name for the pipe:

bsl::string pipeName;
"ctrl.pcctest");
assert(0 == rc);
ControlServer server;
rc = server.start(pipeName);
if (0 != rc) {
cout << "ERROR: Failed to start pipe control channel" << endl;
}
static int makeCanonicalName(bsl::string *pipeName, const bsl::string_view &baseName)

Once the server is started, clients can send messages to the server.

const char MSG0[] = "this is the first message";
const char MSG1[] = "this is the second message";
rc = bdls::PipeUtil::send(pipeName, bsl::string(MSG0) + "\n");
assert(0 == rc);
rc = bdls::PipeUtil::send(pipeName, bsl::string(MSG1) + "\n");
assert(0 == rc);
rc = bdls::PipeUtil::send(pipeName, "EXIT\n");
assert(0 == rc);
static int send(const bsl::string_view &pipeName, const bsl::string_view &message)

The server shuts down once it processes the "EXIT" control message.

server.stop(); // block until shutdown

Finally, let's ensure the server received each control message sent.

assert(2 == server.numMessages());
assert(bsl::string(MSG0) == server.message(0));
assert(bsl::string(MSG1) == server.message(1));