Quick Links: |
Provide a mechanism for reading control messages from a named pipe. More...
Namespaces | |
namespace | balb |
balb::PipeControlChannel | Mechanism for reading messages from a named pipe |
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. shutdown
may always be called safely). The start
function creates a new thread which listens to the pipe for messages until shutdown
is called. bdlsu::PipeUtil
provides a portable utility method to generate such names. \n
) character at the end of each message. This trailing newline is stripped from the message before the message is passed to the control callback. On Windows, methods of balb::PipeControlChannel
that take or return a pipe name as bsl::string
(or a reference to it) type assume that the name is encoded in UTF-8. The routines attempt to convert the name to a UTF-16 wchar_t
string via bdlde::CharConvertUtf16::utf8ToUtf16
, and if the conversion succeeds, call the Windows wide-character W
APIs with the UTF-16 name. If the conversion fails, the method fails.
utf8ToUtf16
nor the Windows W
APIs do any normalization of the UTF-16 strings resulting from UTF-8 conversion, and it is therefore possible to have sets of pipe names that have the same visual representation but are treated as different names by the system. balb::PipeControlChannel
as bsl::string
type is passed unchanged to the underlying system file APIs. Because the pipe names are passed unchanged, balb::PipeControlChannel
methods will work correctly on Posix with any encoding, but will interoperate only with processes that use the same encoding as the current process. // =================== // class ControlServer // =================== class ControlServer { // DATA balb::PipeControlChannel d_channel; bsl::vector<bsl::string> d_messages; // 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]; } };
bsl::string pipeName; int rc = bdls::PipeUtil::makeCanonicalName(&pipeName, "ctrl.pcctest"); assert(0 == rc); ControlServer server; rc = server.start(pipeName); if (0 != rc) { cout << "ERROR: Failed to start pipe control channel" << endl; }
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);
server.stop(); // block until shutdown
assert(2 == server.numMessages()); assert(bsl::string(MSG0) == server.message(0)); assert(bsl::string(MSG1) == server.message(1));