I'm currently working with Boost::Asio to do a basic Read/Write server, I have a little problem when it comes to the usage of the async_read function of the library.
Here's my code snippet :
main.cpp :
#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include "TCPServer.hpp"
#include "TCPConnection.hpp"
using boost::asio::ip::tcp;
int main()
{
try
{
boost::asio::io_service io_service;
TCPServer server(io_service);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
TCPServer.hpp :
#ifndef TCPSERVER_HPP_
#define TCPSERVER_HPP_
#include <ctime>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
#include "TCPConnection.hpp"
using boost::asio::ip::tcp;
class TCPServer
{
private:
tcp::acceptor _acceptor;
public:
TCPServer(boost::asio::io_service& ioService)
: _acceptor(ioService, tcp::endpoint(tcp::v4(), 4040))
{
startAccept();
}
private:
void startAccept()
{
TCPConnection::pointer newConnection =
TCPConnection::create(_acceptor.get_io_service());
_acceptor.async_accept(newConnection->getSocket(),
boost::bind(&TCPServer::handleAccept, this, newConnection,
boost::asio::placeholders::error));
}
void handleAccept(TCPConnection::pointer newConnection, const boost::system::error_code& error)
{
if (!error)
{
newConnection->asyncWrite("JIOLE");
startAccept();
}
}
};
#endif
TCPConnection.hpp :
#ifndef TCPCONNECTION_HPP_
#define TCPCONNECTION_HPP_
#include <ctime>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
class TCPConnection : public boost::enable_shared_from_this<TCPConnection>
{
private:
boost::asio::ip::tcp::socket _socket;
std::string _readMessage;
boost::asio::streambuf _response;
public:
typedef boost::shared_ptr<TCPConnection> pointer;
static pointer create(boost::asio::io_service& ios)
{
return pointer(new TCPConnection(ios));
}
boost::asio::ip::tcp::socket& getSocket()
{
return _socket;
}
void asyncWrite(const std::string &message)
{
boost::asio::async_write(_socket,
boost::asio::buffer(message),
boost::bind(&TCPConnection::handleWrite, shared_from_this(),
boost::asio::placeholders::error));
std::cout << "AsyncWrite" << std::endl;
}
void asyncRead()
{
std::cout << "1st \"asyncRead\"" << std::endl;
boost::asio::async_read(_socket,
_response,
boost::bind(&TCPConnection::handleRead, shared_from_this(),
boost::asio::placeholders::error));
std::cout << "2nd \"asyncRead\"" << std::endl;
}
void close()
{
_socket.close();
}
private:
TCPConnection(boost::asio::io_service &ioS) : _socket(ioS) {}
void handleWrite(const boost::system::error_code& error)
{
std::cout << "Write Handler" << std::endl;
if (!error)
{
asyncRead();
}
//SEE WHAT TO DO IN CASE OF ERROR
}
void handleRead(const boost::system::error_code& error)
{
std::cout << "Read Handler" << std::endl;
if (!error)
{
std::cout << &_response << std::endl;
asyncRead();
}
else
{
std::cout << &error << std::endl;
_socket.close();
}
//CREATE SENDER(RSEPONSE::ERROR)
}
};
#endif
The problem is that my async_read doesn't call the handler. Here is the output :
Output :
AsyncWrite
Write Handler
1st "asyncRead"
2nd "asyncRead"
When I'm writing something on a NetCat Client nothing is being received.
Here what happens when i'm pressing ctrl+C :
Read Handler
0x7fff645f3be0
I don't understand why nothing is received.
The problem is that you did not tell async_read when it should call the handler function. There are two ways to specify this: Either specify the input size after which the handler shall be called or specifiy a delimiter through async_read_until.
In your case, you could use the following:
boost::asio::async_read_until(_socket,
_response,
"\n",
boost::bind(&TCPConnection::handleRead,
shared_from_this(),
boost::asio::placeholders::error)
);
This will call the handler when a newline is sent from the client.
Related
I try to open a UDP server. A baby example works (I receive what I expect and what wireshark also shows):
Baby example:
int main(int argc, char* const argv[])
{
try
{
boost::asio::io_context io_context;
boost::asio::ip::udp::endpoint ep(boost::asio::ip::udp::v4(), 60001);
boost::asio::ip::udp::socket sock(io_context, ep);
UDPServer server(std::move(sock), callbackUDP);
io_context.run();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
UDPServer.hpp:
#include <boost/asio.hpp>
#include <functional>
#include <vector>
#include <thread>
#define BUFFERSIZE 1501
class UDPServer
{
public:
explicit UDPServer(boost::asio::ip::udp::socket socket, std::function<void(const std::vector<char>&)> callbackFunction);
virtual ~UDPServer();
private:
void read();
boost::asio::ip::udp::socket socket_;
boost::asio::ip::udp::endpoint endpoint_;
std::function<void(const std::vector<char>&)> callbackFunction_;
char data_[1500 + 1]; // 1500 bytes is safe limit as it is max of ethernet frame, +1 is for \0 terminator
};
UDPServer.cpp:
#include <iostream>
#include "UDPServer.h"
UDPServer::UDPServer(boost::asio::ip::udp::socket socket, std::function<void(const std::vector<char>&)> callbackFunction):
socket_(std::move(socket)),
callbackFunction_(callbackFunction)
{
read();
}
UDPServer::~UDPServer()
{
}
void UDPServer::read()
{
socket_.async_receive_from(boost::asio::buffer(data_, 1500), endpoint_,
[this](boost::system::error_code ec, std::size_t length)
{
if (ec)
{
return;
}
data_[length] = '\0';
if (strcmp(data_, "\n") == 0)
{
return;
}
std::vector<char> dataVector(data_, data_ + length);
callbackFunction_(dataVector);
read();
}
);
}
Now what I want to convert this to is a class with as constructor only the port and a callback function (let forget about the latter and just print the message for now, adding the callback is normally no problem).
I tried the following, but it doesn't work:
int main(int argc, char* const argv[])
{
UDPServer server(60001);
}
UDPServer.h:
#include <boost/asio.hpp>
#include <functional>
#include <vector>
#include <thread>
#define BUFFERSIZE 1501
class UDPServer
{
public:
explicit UDPServer(uint16_t port);
virtual ~UDPServer();
private:
boost::asio::io_context io_context_;
boost::asio::ip::udp::socket socket_;
boost::asio::ip::udp::endpoint endpoint_;
std::array<char, BUFFERSIZE> recv_buffer_;
std::thread thread_;
void run();
void start_receive();
void handle_reply(const boost::system::error_code& error, std::size_t bytes_transferred);
};
UDPServer.cpp:
#include <iostream>
#include "UDPServer.h"
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>
UDPServer::UDPServer(uint16_t port):
endpoint_(boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port)),
io_context_(),
socket_(io_context_, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port)),
thread_(&UDPServer::run, this)
{
start_receive();
}
UDPServer::~UDPServer()
{
io_context_.stop();
thread_.join();
}
void UDPServer::start_receive()
{
socket_.async_receive_from(boost::asio::buffer(recv_buffer_), endpoint_,
boost::bind(&UDPServer::handle_reply, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void UDPServer::handle_reply(const boost::system::error_code& error, std::size_t bytes_transferred)
{
if (!error)
{
try {
std::string string(recv_buffer_.data(), recv_buffer_.data() + bytes_transferred);
std::cout << "Message received: " << std::to_string(bytes_transferred) << ", " << string << std::endl;
}
catch (std::exception ex) {
std::cout << "handle_reply: Error parsing incoming message:" << ex.what() << std::endl;
}
catch (...)
{
std::cout << "handle_reply: Unknown error while parsing incoming message" << std::endl;
}
}
else
{
std::cout << "handle_reply: error: " << error.message() << std::endl;
}
start_receive();
}
void UDPServer::run()
{
try {
io_context_.run();
} catch( const std::exception& e )
{
std::cout << "Server network exception: " << e.what() << std::endl;
}
catch(...)
{
std::cout << "Unknown exception in server network thread" << std::endl;
}
std::cout << "Server network thread stopped" << std::endl;
};
When running I get "Server network thread stopped". io_context doesn't seem to start and doesn't block. Someone an idea what I do wrong? Thanks a lot!
EDIT tried this after comment, same result (except that message comes after 1 second)
UDPServer::UDPServer(uint16_t port):
endpoint_(boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port)),
io_context_(),
socket_(io_context_, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port))
{
start_receive();
std::this_thread::sleep_for (std::chrono::seconds(1));
thread_ = std::thread(&UDPServer::run, this);
}
Your destructor explicitly tells the service to stop:
UDPServer::~UDPServer() {
io_context_.stop();
thread_.join();
}
That's part of your problem. The other part is as pointed out in the comment: you have a race condition where the thread exits before you even post your first async operation.
Solve it by adding a work guard:
boost::asio::io_context io_;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work_ {io_.get_executor()};
Now the destructor can be:
UDPServer::~UDPServer() {
work_.reset(); // allow service to run out of work
thread_.join();
}
Other notes:
avoid chaining back to start_receive when there was an error
std::to_string was redundant
the order of initialization for members is defined by the order of their declaration, not their initializers in the initializer list. Catch these bug sources with -Wall -Wextra -pedantic
= handle exceptions in your service thread (see Should the exception thrown by boost::asio::io_service::run() be caught?)
I'd suggest std::bind over boost::bind:
std::bind(&UDPServer::handle_reply, this,
std::placeholders::_1,
std::placeholders::_2));
Or just use a lambda:
[this](error_code ec, size_t xfer) { handle_reply(ec, xfer); });
LIVE DEMO
Compiler Explorer
#include <boost/asio.hpp>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <thread>
#include <vector>
using boost::asio::ip::udp;
using boost::system::error_code;
using boost::asio::io_context;
#define BUFFERSIZE 1501
class UDPServer {
public:
explicit UDPServer(uint16_t port);
virtual ~UDPServer();
private:
io_context io_;
boost::asio::executor_work_guard<io_context::executor_type> work_ {io_.get_executor()};
udp::endpoint endpoint_;
udp::socket socket_;
std::array<char, BUFFERSIZE> recv_buffer_;
std::thread thread_;
void run();
void start_receive();
void handle_reply(const error_code& error, size_t transferred);
};
UDPServer::UDPServer(uint16_t port)
: endpoint_(udp::endpoint(udp::v4(), port)),
socket_(io_, endpoint_),
thread_(&UDPServer::run, this) {
start_receive();
}
UDPServer::~UDPServer() {
work_.reset(); // allow service to run out of work
thread_.join();
}
void UDPServer::start_receive() {
socket_.async_receive_from(boost::asio::buffer(recv_buffer_), endpoint_,
#if 0
std::bind(&UDPServer::handle_reply, this,
std::placeholders::_1,
std::placeholders::_2));
#else
[this](error_code ec, size_t xfer) { handle_reply(ec, xfer); });
#endif
}
void UDPServer::handle_reply(const error_code& error, size_t transferred) {
if (!error) {
try {
std::string_view s(recv_buffer_.data(), transferred);
std::cout << "Message received: " << transferred << ", "
<< std::quoted(s) << "\n";
} catch (std::exception const& ex) {
std::cout << "handle_reply: Error parsing incoming message:"
<< ex.what() << "\n";
} catch (...) {
std::cout
<< "handle_reply: Unknown error while parsing incoming message\n";
}
start_receive();
} else {
std::cout << "handle_reply: error: " << error.message() << "\n";
}
}
void UDPServer::run() {
while (true) {
try {
if (io_.run() == 0u) {
break;
}
} catch (const std::exception& e) {
std::cout << "Server network exception: " << e.what() << "\n";
} catch (...) {
std::cout << "Unknown exception in server network thread\n";
}
}
std::cout << "Server network thread stopped\n";
}
int main() {
std::cout << std::unitbuf;
UDPServer server(60001);
}
Testing with random words:
sort -R /etc/dictionaries-common/words | while read w; do sleep 1; netcat -u localhost 60001 -w 0 <<<"$w"; done
Live output:
I have the following code which is simplified from my real code where I am trying to do an async_read on an async_pipe connected to a child process. In the child process I am calling "ls ." as just a test and I want my async read to get the result of that. It returns the following
$ ./a.out
system:0
0
Why does this happen I cannot figure out? Ideally I want to replace "ls ." with a long running process where I can read line after line with async_read.
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <boost/process.hpp>
namespace bp = boost::process;
class test {
private:
boost::asio::io_service ios;
boost::asio::io_service::work work;
bp::async_pipe ap;
std::vector<char> buf;
public:
test()
: ios(), work(ios), ap(ios) {
}
void read(
const boost::system::error_code& ec,
std::size_t size) {
std::cout << ec << std::endl;
std::cout << size << std::endl;
}
void run() {
bp::child c(bp::search_path("ls"), ".", bp::std_out > ap);
boost::asio::async_read(ap, boost::asio::buffer(buf),
boost::bind(&test::read,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
ios.run();
}
};
int main() {
test c;
c.run();
}
You read into a vector of size 0.
You read 0 bytes. That's what you asked for.
I'd suggest using a streambuf and just reading till EOF. Also, drop work unless you really did want run() to never return:
Live On Coliru
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/process.hpp>
#include <iostream>
namespace bp = boost::process;
class test {
private:
boost::asio::io_service ios;
bp::async_pipe ap;
boost::asio::streambuf buf;
public:
test() : ios(), ap(ios) {}
void read(const boost::system::error_code &ec, std::size_t size) {
std::cout << ec.message() << "\n";
std::cout << size << "\n";
std::cout << &buf << std::flush;
}
void run() {
bp::child c(bp::search_path("ls"), ".", bp::std_out > ap, ios);
async_read(ap, buf, boost::bind(&test::read, this, _1, _2));
ios.run();
}
};
int main() {
test c;
c.run();
}
Prints, e.g.
End of file
15
a.out
main.cpp
I did the boost tutorial : An asynchronous TCP daytime server http://think-async.com/Asio/asio-1.1.1/doc/asio/tutorial/tutdaytime3.html
When I want to test it, the server is running so that's good but if I do nc -C localhost 4242 the client got the message of the server but the client is directly disconnected after.
Here my code :
#include "server.h"
#include "connection.h"
Server::Server(boost::asio::io_service& io_service) : accept(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 4242))
{
wait_connection();
}
Server::~Server()
{
}
void Server::wait_connection()
{
std::cout << "wait_connection" << std::endl;
boost::shared_ptr<Connection> new_connection =
Connection::start_connection(accept.get_io_service());
accept.async_accept(new_connection->getSocket(), boost::bind(&Server::callback_accept, this, new_connection, boost::asio::placeholders::error));
}
void Server::callback_accept(boost::shared_ptr<Connection> new_connection, const boost::system::error_code &error)
{
if (!error)
{
new_connection->send_message_to_client();
wait_connection();
}
}
Connection::Connection(boost::asio::io_service& io_service) : socket(io_service)
{
}
Connection::~Connection()
{
std::cout << "destructeur Connection" << std::endl;
}
boost::shared_ptr<Connection> Connection::start_connection(boost::asio::io_service& io_service)
{
return (boost::shared_ptr<Connection>(new Connection(io_service)));
}
boost::asio::ip::tcp::socket& Connection::getSocket()
{
return (this->socket);
}
void Connection::send_message_to_client()
{
message = "Bienvenue!\n";
boost::asio::async_write(socket, boost::asio::buffer(message), boost::bind(&Connection::callback_send, shared_from_this()));
}
void Connection::callback_send()
{
}
int main()
{
try {
boost::asio::io_service io_service;
Server server(io_service);
io_service.run();
}
catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
return (0);
}
#ifndef SERVER_H
#define SERVER_H
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
#include "connection.h"
class Server {
private:
boost::asio::ip::tcp::acceptor accept;
public:
Server (boost::asio::io_service&);
~Server ();
void wait_connection();
void callback_accept(boost::shared_ptr<Connection> new_connection, const boost::system::error_code& error);
};
#endif /* end of include guard: SERVER_H */
#ifndef CONNECTION_H
#define CONNECTION_H
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
class Connection : public boost::enable_shared_from_this<Connection>
{
private:
boost::asio::ip::tcp::socket socket;
std::string message;
public:
Connection (boost::asio::io_service&);
~Connection ();
static boost::shared_ptr<Connection> start_connection(boost::asio::io_service&);
boost::asio::ip::tcp::socket& getSocket();
void send_message_to_client();
void callback_send();
};
#endif /* end of include guard: CONNECTION_H */
Crux: Shared pointers employ keep the object alive until the reference count reaches zero.
You write the message to the client here. When it's complete, you will execute callback_send:
boost::asio::async_write(socket, boost::asio::buffer(message),
boost::bind(&Connection::callback_send, shared_from_this()));
So what do we do next?
void Connection::callback_send() {}
Oh. That's... not a lot. So. Nothing?
Well. Almost nothing.
It's a case of "not doing something is also doing something". By not posting another operation that keeps the socket/connection alive, this means that the connection is going to be released.
Because nothing else keeps the shared_ptr to the connection, shared_ptr will delete the connection (invoking the destructor, which you could see because it prints destructeur Connection every time).
So. What is the solution? We Don't Know. It's up to you what you want to do after you said "welcome". In most likely-hood you will want to wait for some kind of message from the client. This would involve some async_read* call which happily keeps the connection alive (shared_from_this() again).
Demo
Let's assume you want to keep receiving lines, and you send the same lines back, reversed:
void Connection::callback_send() {
boost::asio::async_read_until(socket, request, "\n",
boost::bind(&Connection::on_request_received, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void Connection::on_request_received(boost::system::error_code ec, size_t n) {
if (ec && !((ec == boost::asio::error::eof) && n))
std::cout << "Receive error: " << ec.message() << "\n";
else
{
std::cout << "Received request\n";
{
std::istream is(&request);
std::getline(is, message);
}
std::reverse(message.begin(), message.end());
std::cout << "Sending response: " << message << "\n";
message += '\n';
if (!ec) boost::asio::async_write(socket, boost::asio::buffer(message),
boost::bind(&Connection::callback_send, shared_from_this()));
}
}
I am using c++ boost asio for making a server client application.
I followed the guide lines from here.
And I am still wondering why I get the following result:
./server #ok
./client # error
bind: Address already in use
server.cpp:
#include <ctime>
#include <iostream>
#include <stdio.h>
#include <string>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::udp;
struct UDP_Message
{
double number;
};
int main()
{
try
{
boost::asio::io_service io_service;
udp::socket socket(io_service, udp::endpoint(udp::v4(), config::udp_port));
UDP_Message message;
message.number=0;
for (;;)
{
udp::endpoint remote_endpoint;
message.number=message.number+0.001;
boost::system::error_code ignored_error;
socket.send_to(boost::asio::buffer(&message,sizeof(message)),
remote_endpoint, 0, ignored_error);
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
client.cpp:
#include <ctime>
#include <iostream>
#include <stdio.h>
#include <string>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::udp;
namespace config
{
const unsigned short udp_port=1414;
}
struct UDP_Message
{
double number;
};
int main()
{
try
{
boost::asio::io_service io_service;
boost::asio::socket_base::reuse_address option(true);
udp::socket socket(io_service, udp::v4());
socket.set_option(option);
socket.bind(udp::endpoint(udp::v4(), config::udp_port));
UDP_Message message;
for (;;)
{
boost::array<char, 1> recv_buf;
udp::endpoint remote_endpoint;
boost::system::error_code error;
socket.receive_from(boost::asio::buffer(recv_buf),
remote_endpoint, 0, error);
if (error && error != boost::asio::error::message_size)
throw boost::system::system_error(error);
std::memcpy(&message,recv_buf.data(),sizeof(message));
std::cout<<message.number<<std::endl;
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
You are trying to bind both your client and server to the same port, udp_port=1414. This you can not do.
I've been trying to create servers and clients using boost::asio, and the requirement is that the server will raise the process of the clients. so I've implemented a Master, a Loader and a Slave.
Now for some reason it looks like it's not really multi process. I.E. the server is stuck and not receiving any answer from the client, if I make the client asynchronically wait for an answer after send, the console prints I am getting is:
Slave Loaded
Slave::Resolved
Slave::Connected
Slave::Write Ended
I.E. the master is not receiving any answers from the slave,
btw, if I remove the sync_read in the client, I get:
Slave Loaded
Slave::Resolved
Slave::Connected
Slave::Write Ended
Slave Ended
Master::Received: 1
which makes me think even more that it's not multi process... has anyone experienced this?
these are the files ( 3 projects)
Master:
#include <iostream>
#include <string>
#include <list>
#include <tchar.h>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/bind.hpp>
using namespace std;
using namespace boost::asio;
using boost::asio::ip::tcp;
static int const s_srvCnt = 1;
class tcp_connection
: public boost::enable_shared_from_this<tcp_connection>
{
public:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& io_service)
{
return pointer(new tcp_connection(io_service));
}
tcp::socket& socket()
{
return m_socket;
}
void start()
{
async_read(m_socket, m_buf,
boost::bind(&tcp_connection::received, this,
boost::asio::placeholders::error));
}
private:
tcp_connection(boost::asio::io_service& io_service)
: m_socket(io_service)
{
}
void handle_write(const boost::system::error_code& /*error*/)
{
}
void received(const boost::system::error_code& err) {
cout << "Master::Received: " << &m_buf << endl;
boost::asio::async_write(m_socket, boost::asio::buffer("Thanks"),
boost::bind(&tcp_connection::handle_write, this,
boost::asio::placeholders::error));
}
tcp::socket m_socket;
boost::asio::streambuf m_buf;
};
class tcp_server
{
public:
tcp_server(boost::asio::io_service& io_service)
: m_acceptor(io_service, tcp::endpoint(tcp::v4(), 1300))
{
start_accept();
}
private:
void start_accept()
{
tcp_connection::pointer new_connection =
tcp_connection::create(m_acceptor.get_io_service());
m_acceptor.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
}
void handle_accept(tcp_connection::pointer new_connection,
const boost::system::error_code& error)
{
m_connections.push_back(new_connection);
if (!error)
{
new_connection->start();
}
start_accept();
}
tcp::acceptor m_acceptor;
list<tcp_connection::pointer> m_connections;
};
void main()
{
//list<wstring> processes;
//processes.push_back("Process1");
//processes.push_back("Process2");
STARTUPINFO si;
PROCESS_INFORMATION pi;
//LPWSTR concatted = concatted_stdstr.c_str();
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
TCHAR params[100];
// Start the child process.
boost::asio::io_service service;
tcp_server server(service);
size_t current = 0;
for (int i = 1 ; i <= s_srvCnt ; i++) {
swprintf_s(params, TEXT("-id %d"), i);
if( !CreateProcess(TEXT("D:\\Users\\myuser\\Documents\\Visual Studio 2012\\Projects\\MultiProcess\\x64\\Debug\\Loader.exe"), // No module name (use command line) // change this to your local wherever you run from
params, // Command line // -name Process1
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
//current = service.poll_one();
}
//size_t polled = service.poll();
service.run();
cout << "Master Ended";
//while(true);
}
Slave:
#include "dllmain.h"
#include <iostream>
#include <tchar.h>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/bind.hpp>
using namespace std;
using boost::asio::ip::tcp;
class client
{
public:
client(boost::asio::io_service& io_service, const std::string& parms)
: m_resolver(io_service),
m_socket(io_service),
m_params(parms)
{
// Start an asynchronous resolve to translate the server and service names
// into a list of endpoints.
tcp::resolver::query query("localhost", "1300");
m_resolver.async_resolve(query,
boost::bind(&client::handle_resolve, this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator));
}
private:
void handle_resolve(const boost::system::error_code& err,
tcp::resolver::iterator endpoint_iterator)
{
if (!err)
{
cout << "Slave::Resolved" << endl;
// Attempt a connection to each endpoint in the list until we
// successfully establish a connection.
boost::asio::async_connect(m_socket, endpoint_iterator,
boost::bind(&client::handle_connect, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "Error1: " << err.message() << "\n";
}
}
void handle_connect(const boost::system::error_code& err)
{
if (!err)
{
cout << "Slave::Connected" << endl;
// The connection was successful. Send the request.
boost::asio::async_write(m_socket, boost::asio::buffer(m_params),
boost::bind(&client::handle_write, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "Error2: " << err.message() << "\n";
}
}
void handle_write(const boost::system::error_code& err)
{
if (!err)
{
// Read the response status line. The response_ streambuf will
// automatically grow to accommodate the entire line. The growth may be
// limited by passing a maximum size to the streambuf constructor.
cout << "Slave::Write Ended" << endl;
/* boost::asio::async_read(m_socket, m_buf,
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error));*/
}
else
{
std::cout << "Error3: " << err.message() << "\n";
}
}
void handle_read(const boost::system::error_code& err)
{
if (!err)
{
cout << "Slave::Received: " << &m_buf << endl;
}
else
{
std::cout << "Error4: " << err << "\n";
}
}
tcp::resolver m_resolver;
tcp::socket m_socket;
boost::asio::streambuf m_buf;
std::string m_params;
};
bool Init(int n, char* params[])
{
std::string parameters;
for (int i = 1 ; i < n ; ++i)
parameters.append(params[i]);
cout << "Slave Loaded" << endl;
boost::asio::io_service service;
client client(service, parameters);
service.run();
cout << "Slave Ended" << endl;
return true;
}
Slave h file:
(dllmain.h)
#if !defined(__dllmain_h_Included_)
#define __dllmain_h_Included_
#if !defined(WIN32)
# define SLAVE_API
# if defined(SLAVE_EXPORTS)
# define SLAVE_EXTERN
# else
# define SLAVE_EXTERN extern
# endif
#else
# if defined(SLAVE_EXPORTS)
# define SLAVE_API __declspec(dllexport)
# define SLAVE_EXTERN
# else
# define SLAVE_API __declspec(dllimport)
# define SLAVE_EXTERN extern
# endif
#endif
extern "C" SLAVE_API bool Init(int n, char* params[]);
#endif // !defined(__dllmain_h_Included_)
Loader:
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
typedef bool (*Init)(int, char* params[]);
void main(int argc, char* argv[])
{
HMODULE m_handle = ::LoadLibrary(TEXT("Slave.dll"));
if (!m_handle) {
cout
<< "failed loading dll: " << "" << " failed code " << GetLastError() << endl ;
}
void* foo = ::GetProcAddress(m_handle, "Init");
Init f = (Init)foo;
f(argc, argv);
while(true) Sleep(10000);
}
Help?
Addition:
I am now sure it is not the boost problem, but a process creation problem.
if I close the second process using task manager, then the master receives the msg.
so my question is, why is the 2nd process locking the 1st that created it?