Why I cannot create queue in rabbitmq in Windows? - c++

I'm new to RabbitMQ.
I installed RabbitMQ server on Windows 10. I can login to the server in web browser. When I run the client code below (uses AMQP-CPP library), neigther channel.onSuccess nor channel.onError are called. And, I don't see my declared my-queue queue and my-exchange exchange in the web browser.
If I understood correctly, I need to add some event loop (?). But, I cannot find any example for Windows. Can you explain what can be the issue?
int main()
{
// create an instance of your own tcp handler
MyTcpHandler myHandler;
// address of the server
//AMQP::Address address("amqp://guest:guest#localhost:5672/");
AMQP::Address address("localhost", 15672, AMQP::Login("guest", "guest"), "");
// create a AMQP connection object
AMQP::TcpConnection connection(&myHandler, address);
// and create a channel b
AMQP::TcpChannel channel(&connection);
// use the channel object to call the AMQP method you like
channel.declareExchange("my-exchange", AMQP::fanout)
.onSuccess([]()
{
std::cout << "declared exchange " << std::endl;
}).onError([](const char *message)
{
std::cout << "error: " << message << std::endl;
});
channel.declareQueue("my-queue");
channel.bindQueue("my-exchange", "my-queue", "my-routing-key");
std::cout << "Press Enter..." << std::endl;
std::getchar();
return 0;
}
MyTcpHandler
class MyTcpHandler : public AMQP::TcpHandler
{
public:
virtual void onConnected(AMQP::TcpConnection *connection) {}
virtual void onError(AMQP::TcpConnection *connection, const char *message) {}
virtual void onClosed(AMQP::TcpConnection *connection) {}
virtual void monitor(AMQP::TcpConnection *connection, AMQP::tcp::Socket fd, int flags) {}
};

came across same issue myself today.
The problem is you have to implement your own hanlder, or nothing will be sent.
The bundled TcpHandler is based on boost asio tcpHandler which is posix only, and will not compile on windows. see this link
Too shame it's doesn't have internal built-in handler, this is so "basic"...

You are connecting on the wrong port 15672 is the management plugin port , you need to connect on Port 5672 which is the AMQP port
Please correct the code as under
AMQP::Address address("localhost", 5672, AMQP::Login("guest", "guest"), "");

You could just use HareDu 2 Broker API to do it using the below code. Docs can be found here: https://github.com/ahives/HareDu2
var result = _container.Resolve<IBrokerObjectFactory>()
.Object<Queue>()
.Create(x =>
{
x.Queue("your_queue");
x.Configure(c =>
{
c.IsDurable();
c.AutoDeleteWhenNotInUse();
c.HasArguments(arg =>
{
arg.SetQueueExpiration(1000);
arg.SetPerQueuedMessageExpiration(2000);
});
});
x.Targeting(t =>
{
t.VirtualHost("your_vhost");
t.Node("your_node");
});
});

Related

Close Boost Websocket from Server side, C++, tcp::acceptor accept() timeout?

UPDATE:
Well it appears that I need to address my issue with an asynchronous implementation. I will update my posting with a new direction, once I've completed testing
Original:
I'm currently writing a multiserver application that will collect, share, and request information from multiple machines. In some cases, Machine A will request information from Machine B but will need to send it to Machine C, which will reply to A. Without getting too deep into what the application is going to do I need some help with my client application.
I have my client application designed with two threads. I used this example from boost, as the basis for my design.
Thread one will open a Client Websocket with Machine-A, it will stream a series of data points and commands. Here is a stripped-down version of my code
#include "Poco/Clock.h"
#include "Poco/Task.h"
#include "Poco/Thread.h"
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <jsoncons/json.hpp>
namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
using tcp = net::ip::tcp; // from <boost/asio/ip/tcp.hpp>
class ResponseChannel : public Poco::Runnable {
void do_session(tcp::socket socket)
{
try {
websocket::stream<tcp::socket> ws{std::move(socket)};
ws.set_option(websocket::stream_base::decorator(
[](websocket::response_type& res) {
res.set(http::field::server,
std::string(BOOST_BEAST_VERSION_STRING) +
" websocket-server-sync");
}));
ws.accept();
for (;;) {
beast::flat_buffer buffer;
ws.read(buffer);
if (ws.got_binary()) {
// do something
}
}
} catch (beast::system_error const& se) {
if (se.code() != websocket::error::closed) {
std::cerr << "do_session1 ->: " << se.code().message()
<< std::endl;
return;
}
} catch (std::exception const& e) {
std::cerr << "do_session2 ->: " << e.what() << std::endl;
return;
}
}
virtual void run()
{
auto const address = net::ip::make_address(host);
auto const port = static_cast<unsigned short>(respPort);
try {
net::io_context ioc{1};
tcp::acceptor acceptor{ioc, {address, port}};
tcp::socket socket{ioc};
for (; keep_running;) {
acceptor.accept(socket);
std::thread(&ResponseChannel::do_session, this,
std::move(socket))
.detach();
}
} catch (const std::exception& e) {
std::cout << "run: " << e.what() << std::endl;
}
}
void _terminate() { keep_running = false; }
public:
std::string host;
int respPort;
bool keep_running = true;
int responseCount = 0;
std::vector<long long int> latency_times;
long long int time_sum;
Poco::Clock* responseClock;
};
int main()
{
using namespace std::chrono_literals;
Poco::Clock clock = Poco::Clock();
Poco::Thread response_thread;
ResponseChannel response_channel;
response_channel.responseClock = &clock;
response_channel.host = "0.0.0.0";
response_channel.respPort = 8080;
response_thread.start(response_channel);
response_thread.setPriority(Poco::Thread::Priority::PRIO_HIGH);
// doing some work here. work will vary depending on command-line arguments
std::this_thread::sleep_for(30s);
response_channel.keep_running = false;
response_thread.join();
}
The way I have designed the multiple machines works as expected regarding sending commands to Machine-B and receiving results from Machine-C.
The issue I'm facing is closing out Thread 2, which contains my local response channel.
I went back and forth between Poco::Thread and Poco::Task, but I decided that I do not want to use Task, as it would be a mistake to be able to close the 2nd thread/task from the main thread. I need to know that all packets have been received before closing down the 2nd thread.
So I need to close events down only once I have received a websocket::error::closed flag from Machine-C. Shutting down the websocket, detached, thread is no issue, as when the flag arrives it takes care of that for me.
However, as part of the loop process for reconnecting after a closed socket, the thread just waits for a new connection.
acceptor.accept(socket);
It's blocking, and through the documentation, there doesn't seem to be a timeout feature. I see that there is a close option, but my attempt to use close simply threw an exception. Which ultimately added complexity, I didn't want.
Ultimately, I want the Server to continuously loop through a series of connections from both Machine-B and Machine-C, but only after my client application has ended. The last thing I do before waiting for the Poco::Thread to complete is to set the flag that I no longer want the Websocket server to run.
I've put that flag before the blocking accept() call. This would work, only with perfect timing of the flag going up, a new connection is opened and then closed, before looping back to wait for a new connection.
Ideally, there would be a timeout so that it would loop around, first checking if it timed out, allow for a periodic check if I wanted the thread to remain open.
Has anyone ever run into this?

Integration between Node.js and C++

I have a Node.js application that I want to be able to send a JSON-object into a C++ application.
The C++ application will use the Poco-libraries (pocoproject.org).
I want the interaction to be lighting fast, so preferably no files or network-sockets.
I have been looking into these areas:
Pipes
Shared memory
unixSockets
What should I focus on, and can someone point my direction to docs. and samples?
First of all, some more data is needed to give good advice.
In general shared memory is the fastest, since there's no transfer required, but it's also the hardest to keep fine. I'm not sure you'd be able to do that with Node though.
If this program is just running for this one task and closing it might be worth just sending your JSON to the CPP program as a startup param
myCPPProgram.exe "JsonDataHere"
The simplest thing with decent performance should be a socket connection using Unix domain sockets with some low-overhead data frame format. E.g., two-byte length followed by UTF-8 encoded JSON. On the C++ side this should be easy to implement using the Poco::Net::TCPServer framework. Depending on where your application will go in the future you may run into limits of this format, but if it's basically just streaming JSON objects it should be fine.
To make it even simpler, you can use a WebSocket, which will take care of the framing for you, at the cost of the overhead for the initial connection setup (HTTP upgrade request). May even be possible to run the WebSocket protocol over a Unix domain socket.
However, the performance difference between a (localhost only) TCP socket and a Unix domain socket may not even be significant, given all the JavaScript/node.js overhead. Also, if performance is really a concern, JSON may not even be the right serialization format to begin with.
Anyway, without more detailed information (size of JSON data, message frequency) it's hard to give a definite recommendation.
I created a TCPServer, which seems to work. However if I close the server and start it again I get this error:
Net Exception: Address already in use: /tmp/app.SocketTest
Is it not possible to re-attach to the socket if it exists?
Here is the code for the TCPServer:
#include "Poco/Util/ServerApplication.h"
#include "Poco/Net/TCPServer.h"
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/TCPServerConnectionFactory.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/File.h"
#include <fstream>
#include <iostream>
using Poco::Net::ServerSocket;
using Poco::Net::StreamSocket;
using Poco::Net::TCPServer;
using Poco::Net::TCPServerConnection;
using Poco::Net::TCPServerConnectionFactory;
using Poco::Net::SocketAddress;
using Poco::Util::ServerApplication;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;
class UnixSocketServerConnection: public TCPServerConnection
/// This class handles all client connections.
{
public:
UnixSocketServerConnection(const StreamSocket& s):
TCPServerConnection(s)
{
}
void run()
{
try
{
/*char buffer[1024];
int n = 1;
while (n > 0)
{
n = socket().receiveBytes(buffer, sizeof(buffer));
EchoBack(buffer);
}*/
std::string message;
char buffer[1024];
int n = 1;
while (n > 0)
{
n = socket().receiveBytes(buffer, sizeof(buffer));
buffer[n] = '\0';
message += buffer;
if(sizeof(buffer) > n && message != "")
{
EchoBack(message);
message = "";
}
}
}
catch (Poco::Exception& exc)
{
std::cerr << "Error: " << exc.displayText() << std::endl;
}
std::cout << "Disconnected." << std::endl;
}
private:
inline void EchoBack(std::string message)
{
std::cout << "Message: " << message << std::endl;
socket().sendBytes(message.data(), message.length());
}
};
class UnixSocketServerConnectionFactory: public TCPServerConnectionFactory
/// A factory
{
public:
UnixSocketServerConnectionFactory()
{
}
TCPServerConnection* createConnection(const StreamSocket& socket)
{
std::cout << "Got new connection." << std::endl;
return new UnixSocketServerConnection(socket);
}
private:
};
class UnixSocketServer: public Poco::Util::ServerApplication
/// The main application class.
{
public:
UnixSocketServer(): _helpRequested(false)
{
}
~UnixSocketServer()
{
}
protected:
void initialize(Application& self)
{
loadConfiguration(); // load default configuration files, if present
ServerApplication::initialize(self);
}
void uninitialize()
{
ServerApplication::uninitialize();
}
void defineOptions(OptionSet& options)
{
ServerApplication::defineOptions(options);
options.addOption(
Option("help", "h", "display help information on command line arguments")
.required(false)
.repeatable(false));
}
void handleOption(const std::string& name, const std::string& value)
{
ServerApplication::handleOption(name, value);
if (name == "help")
_helpRequested = true;
}
void displayHelp()
{
HelpFormatter helpFormatter(options());
helpFormatter.setCommand(commandName());
helpFormatter.setUsage("OPTIONS");
helpFormatter.setHeader("A server application to test unix domain sockets.");
helpFormatter.format(std::cout);
}
int main(const std::vector<std::string>& args)
{
if (_helpRequested)
{
displayHelp();
}
else
{
// set-up unix domain socket
Poco::File socketFile("/tmp/app.SocketTest");
SocketAddress unixSocket(SocketAddress::UNIX_LOCAL, socketFile.path());
// set-up a server socket
ServerSocket svs(unixSocket);
// set-up a TCPServer instance
TCPServer srv(new UnixSocketServerConnectionFactory, svs);
// start the TCPServer
srv.start();
// wait for CTRL-C or kill
waitForTerminationRequest();
// Stop the TCPServer
srv.stop();
}
return Application::EXIT_OK;
}
private:
bool _helpRequested;
};
int main(int argc, char **argv) {
UnixSocketServer app;
return app.run(argc, argv);
}
The solution I have gone for, is to use unix domain sockets. The solution will run on a Raspbian-setup and the socket-file is placed in /dev/shm, which is mounted into RAM.
On the C++ side, I use the Poco::Net::TCPServer framework as described elsewhere in this post.
On the Node.js side, I use the node-ipc module (http://riaevangelist.github.io/node-ipc/).

How do I make an in-place modification on an array using grpc and google protocol buffers?

I'm having a problem with a const request with the google protocol buffers using grpc. Here is my problem:
I would like to make an in-place modification of an array's value. For that I wrote this simple example where I try to pass an array and sum all of it's content. Here's my code:
adder.proto:
syntax = "proto3";
option java_package = "io.grpc.examples";
package adder;
// The greeter service definition.
service Adder {
// Sends a greeting
rpc Add (AdderRequest) returns (AdderReply) {}
}
// The request message containing the user's name.
message AdderRequest {
repeated int32 values = 1;
}
// The response message containing the greetings
message AdderReply {
int32 sum = 1;
}
server.cc:
//
// Created by Eric Reis on 7/6/16.
//
#include <iostream>
#include <grpc++/grpc++.h>
#include "adder.grpc.pb.h"
class AdderImpl final : public adder::Adder::Service
{
public:
grpc::Status Add(grpc::ServerContext* context, const adder::AdderRequest* request,
adder::AdderReply* reply) override
{
int sum = 0;
for(int i = 0, sz = request->values_size(); i < sz; i++)
{
request->set_values(i, 10); // -> this gives an error caused by the const declaration of the request variable
// error: "Non-const function 'set_values' is called on the const object"
sum += request->values(i); // -> this works fine
}
reply->set_sum(sum);
return grpc::Status::OK;
}
};
void RunServer()
{
std::string server_address("0.0.0.0:50051");
AdderImpl service;
grpc::ServerBuilder builder;
// Listen on the given address without any authentication mechanism.
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
// Register "service" as the instance through which we'll communicate with
// clients. In this case it corresponds to an *synchronous* service.
builder.RegisterService(&service);
// Finally assemble the server.
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
// Wait for the server to shutdown. Note that some other thread must be
// responsible for shutting down the server for this call to ever return.
server->Wait();
}
int main(int argc, char** argv)
{
RunServer();
return 0;
}
client.cc:
//
// Created by Eric Reis on 7/6/16.
//
#include <iostream>
#include <grpc++/grpc++.h>
#include "adder.grpc.pb.h"
class AdderClient
{
public:
AdderClient(std::shared_ptr<grpc::Channel> channel) : stub_(adder::Adder::NewStub(channel)) {}
int Add(int* values, int sz) {
// Data we are sending to the server.
adder::AdderRequest request;
for (int i = 0; i < sz; i++)
{
request.add_values(values[i]);
}
// Container for the data we expect from the server.
adder::AdderReply reply;
// Context for the client. It could be used to convey extra information to
// the server and/or tweak certain RPC behaviors.
grpc::ClientContext context;
// The actual RPC.
grpc::Status status = stub_->Add(&context, request, &reply);
// Act upon its status.
if (status.ok())
{
return reply.sum();
}
else {
std::cout << "RPC failed" << std::endl;
return -1;
}
}
private:
std::unique_ptr<adder::Adder::Stub> stub_;
};
int main(int argc, char** argv) {
// Instantiate the client. It requires a channel, out of which the actual RPCs
// are created. This channel models a connection to an endpoint (in this case,
// localhost at port 50051). We indicate that the channel isn't authenticated
// (use of InsecureChannelCredentials()).
AdderClient adder(grpc::CreateChannel("localhost:50051",
grpc::InsecureChannelCredentials()));
int values[] = {1,2};
int sum = adder.Add(values, 2);
std::cout << "Adder received: " << sum << std::endl;
return 0;
}
My error happens when i try to call the method set_values() on the request object that is defined as const. I understand why this error is occurring but I just can't figure out a way to overcome it without making a copy of the array.
I tried to remove the const definition but the RPC calls fails when I do that.
Since I'm new to this RPC world and even more on grpc and the google protocol buffers I'd like to call for your help. What is the best way to solve this problem?
Please see my answer here. The server receives a copy of the AdderRequest sent by the client. If you were to modify it, the client's original AdderRequest would not be modified. If by "in place" you mean the server modifies the client's original memory, no RPC technology can truly accomplish that, because the client and server run in separate address spaces (processes), even on different machines.
If you truly need the server to modify the client's memory:
Ensure the server and client run on the same machine.
Use OS-specific shared-memory APIs such as shm_open() and mmap() to map the same chunk of physical memory into the address spaces of both the client and the server.
Use RPC to transmit the identifier (name) of the shared memory (not the actual data in the memory) and to invoke the server's processing.
When both client and server have opened and mapped the memory, they both have pointers (likely with different values in the different address spaces) to the same physical memory, so the server will be able to read what the client writes there (with no copying or transmitting) and vice versa.

Poco stops after SMTPClientSession.login

I just started with the Poco library and tried to create an email program (Which I knew virtually nothing about). The following is my code (There may be other problems with it besides the one I've encountered so far, but I just started working on it)
int main(int argc, char** argv)
{
Poco::Net::SocketAddress add("smtp.gmail.com:465");
Poco::Net::StreamSocket sock(add);
Poco::Net::SMTPClientSession sess(sock);
std::cout << "-";
sess.login(
"gmail.com",
Poco::Net::SMTPClientSession::AUTH_LOGIN,
"----",
"----"
);
Poco::Net::MailMessage msg;
Poco::Net::MailRecipient resp(Poco::Net::MailRecipient::PRIMARY_RECIPIENT,"michaelrgoldfine#gmail.com");
msg.addRecipient(resp);
std::string content("HELP SOS");
msg.encodeWord(content);
std::cout << msg.getContent() << "-";
}
When I go into the debugger, it runs fine until it gets to sess.login then suddenly the little bar that represents were I am in the code disappears but the program keeps running (I'm not experienced enough to know what that means). None of the cout stuff I put in actually prints, the debugger just goes past that line but nothing shows up. After a little while this comes up:
terminate called throwing an exception
So what's going on?
You are attempting to use SMTP over TLS (the port 465 passed to the SocketAddress). In one shot you have to learn (1) TLS and certificate handling in POCO, before focusing on (2) your goal: sending an email message.
I suggest to start learning POCO with simpler examples. You can find sample code in the various samples directories in the POCO source code.
I think that your code is just hanging on the TLS handshake, because it doesn't know what to do.
These are the fixes you should do before looking at the solution:
Place your code inside a try/catch block. POCO uses exceptions.
Replace StreamSocket with SecureStreamSocket.
The simplest way to properly initialize SecureStreamSocket is via the Application class. See the Applications slides and Util/samples/SampleApp/src/SampleApp.cpp.
See the documentation for the SSLManager for how to properly tell the Application which certificates to use.
Don't specify an hostname to the login() method. The hostname is optional and should be the client hostname, not the server (See the SMTP RFC).
Remember to actually send the message! Your code is not sending it :-)
OK, and now for the running code. I left steps 4 and 6 as an exercise, but this code will at least run the TLS handshake, will tell you that it cannot verify the server's certificate and, if you answer Yes on the terminal to the questions on the certificates, it will fail the SMTP authentication.
class MiniApp : public Poco::Util::Application {
int main(const vector <string>& args) {
try {
Poco::Net::SocketAddress add("smtp.gmail.com:465");
Poco::Net::SecureStreamSocket sock(add);
Poco::Net::SMTPClientSession session(sock);
session.login(Poco::Net::SMTPClientSession::AUTH_LOGIN, "user", "pw");
Poco::Net::MailMessage msg;
Poco::Net::MailRecipient recipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT,
"michaelrgoldfine#gmail.com");
msg.addRecipient(recipient);
string content("HELP SOS");
msg.encodeWord(content);
} catch (Poco::Exception& e) {
cout << "Error: " << e.displayText() << endl;
return -1;
}
return 0;
}
};
POCO_APP_MAIN(MiniApp)
Yes, so I struggled with login(), trying to use smtp.gmail.com. This is the excerpt of the communication with the SSL session that made it work.
string host("smtp.gmail.com")
Poco::UInt16 port = 587;
SecureSMTPClientSession session(host, port);
session.open();
Poco::Net::initializeSSL();
SharedPtr<InvalidCertificateHandler> ptrHandler = new AcceptCertificateHandler(false);
Context::Ptr ptrContext = new Context(Context::CLIENT_USE, "", "", "", Context::VERIFY_RELAXED, 9, true, "ALL:!ADH:!LOW:!EXP:!MD5:#STRENGTH");
SSLManager::instance().initializeClient(0, ptrHandler, ptrContext);
try
{
// SSL
session.login();
if (session.startTLS(ptrContext))
{
session.login(SMTPClientSession::AUTH_LOGIN, "user#gmail.com", "yourpassword");
session.sendMessage(message);
}
session.close();
Poco::Net::uninitializeSSL();
}
catch (SMTPException &e)
{
cout << e.message() << endl;
session.close();
Poco::Net::uninitializeSSL();
return 0;
}
Original source:
http://www.axistasoft.sg/tutorials/cpp/poco/item/sending-email-messages-using-smtp-protocol

BOOST ASIO - How to write console server

I have to write asynchronous TCP Sever.
TCP Server have to be managed by console
(for eg: remove client, show list of all connected client, etcc..)
The problem is: How can I attach (or write) console, which can calls above functionalities.
This console have to be a client? Should I run this console client as a sepearate thread?
I have read a lot of tutorials and I couldn`t find a solution to my problem.
ServerTCP code
class ServerTCP
{
public:
ServerTCP(boost::asio::io_service& A_ioService, unsigned short A_uPortNumber = 13)
: m_tcpAcceptor(A_ioService, tcp::endpoint(tcp::v4(), A_uPortNumber)), m_ioService (A_ioService)
{
start();
}
private:
void start()
{
ClientSessionPtr spClient(new ClientSession(m_tcpAcceptor.io_service(), m_connectedClients));
m_tcpAcceptor.async_accept(spClient->getSocket(),
boost::bind(&ServerTCP::handleAccept, this, spClient,
boost::asio::placeholders::error));
}
void handleAccept(ClientSessionPtr A_spNewClient, const boost::system::error_code& A_nError)
{
if ( !A_nError )
{
A_spNewClient->start();
start();
}
}
boost::asio::io_service& m_ioService;
tcp::acceptor m_tcpAcceptor;
Clients m_connectedClients;
};
Main function:
try
{
boost::asio::io_service ioService;
ServerTCP server(ioService);
ioService.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
Hello Sam. Thanks for reply. Could you be so kind and show me a some piece of code or some links to examples involve with this problem ?
Propably, I don`t understand correctly "... single threaded server ..."
In Fact in "console" where I want to manage server operations, I need smt like below:
main()
cout << "Options: q - close server, s - show clients";
while(1)
{
char key = _getch();
switch( key )
{
case 'q':
closeServer();
break
case 's':
showClients();
break
}
}
The problem is: How can I attach (or
write) console, which can calls above
functionalities. This console have to
be a client? Should I run this console
client as a sepearate thread?
You don't need a separate thread, use a posix::stream_descriptor and assign STDIN_FILENO to it. Use async_read and handle the requests in the read handlers.
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
using namespace boost::asio;
class Input : public boost::enable_shared_from_this<Input>
{
public:
typedef boost::shared_ptr<Input> Ptr;
public:
static void create(
io_service& io_service
)
{
Ptr input(
new Input( io_service )
);
input->read();
}
private:
explicit Input(
io_service& io_service
) :
_input( io_service )
{
_input.assign( STDIN_FILENO );
}
void read()
{
async_read(
_input,
boost::asio::buffer( &_command, sizeof(_command) ),
boost::bind(
&Input::read_handler,
shared_from_this(),
placeholders::error,
placeholders::bytes_transferred
)
);
}
void read_handler(
const boost::system::error_code& error,
size_t bytes_transferred
)
{
if ( error ) {
std::cerr << "read error: " << boost::system::system_error(error).what() << std::endl;
return;
}
if ( _command != '\n' ) {
std::cout << "command: " << _command << std::endl;
}
this->read();
}
private:
posix::stream_descriptor _input;
char _command;
};
int
main()
{
io_service io_service;
Input::create( io_service );
io_service.run();
}
If I understand the OP correctly, he/she wants to run an async TCP server that is controlled via a console i.e console is used as user interface.
In that case you don't need a separate client application to query the server for connected clients, etc.:
You need to spawn a thread that somehow calls the io_service::run method. Currently you are calling this from main. Since your server will probably be scoped in main, you need do something like pass a ref to the server to the new thread. The io_service could e.g be a member of the server class (unless your application has other requirements in which case pass both the server and the io_service to the new thread).
add the corresponding methods such as showClients, closeServer, etc. to your server class
make sure that these calls which are triggered via the console are thread-safe
in your closeServer method you could for instance call io_service::stop which would result in the server ending.