The following code of the client:
typedef boost::array<char, 10> header_packet;
header_packet header;
boost::system::error_code error;
...
/** send header */
boost::asio::write(
_socket,
boost::asio::buffer(header, header.size()),
boost::asio::transfer_all(),
error
);
/** send body */
boost::asio::write(
_socket,
boost::asio::buffer(buffer, buffer.length()),
boost::asio::transfer_all(),
error
);
of the server:
struct header {
boost::uint32_t header_length;
boost::uint32_t id;
boost::uint32_t body_length;
};
static header unpack_header(const header_packet& data) {
header hdr;
sscanf(data.data(), "%02d%04d%04d", &hdr.header_length, &hdr.id, &hdr.body_length);
return hdr;
}
void connection::start() {
boost::asio::async_read(
_socket,
boost::asio::buffer(_header, _header.size()),
boost::bind(
&connection::read_header_handler,
shared_from_this(),
boost::asio::placeholders::error
)
);
}
/***************************************************************************/
void connection::read_header_handler(const boost::system::error_code& e) {
if ( !e ) {
std::cout << "readed header: " << _header.c_array() << std::endl;
std::cout << constants::unpack_header(_header);
boost::asio::async_read(
_socket,
boost::asio::buffer(_body, constants::unpack_header(_header).body_length),
boost::bind(
&connection::read_body_handler,
shared_from_this(),
boost::asio::placeholders::error
)
);
} else {
/** report error */
std::cout << "read header finished with error: " << e.message() << std::endl;
}
}
/***************************************************************************/
void connection::read_body_handler(const boost::system::error_code& e) {
if ( !e ) {
std::cout << "readed body: " << _body.c_array() << std::endl;
start();
} else {
/** report error */
std::cout << "read body finished with error: " << e.message() << std::endl;
}
}
On the server side the method read_header_handler() is called, but the method read_body_handler() is never called. Though the client has written down the data in a socket.
The header is readed and decoded successfully.
What's the error?
problem is solved.
error was in my code when sending the result of serialization in asio::write(). so the server could not read anything.
Related
I am trying to make tcp echo server with boost asio.
I successed transport of string data to server from client.
But I can't transport received data from client to client.
I do not know if this problem is caused by async_write() function in server code or async_read() function in client code.
I suppose that this problem is caused by thread's declaration and their function call but, I'm not sure.
Summary : I don't know correct cause of this problem..
Help me please...
sever code
#include <iostream>
#include <boost/asio.hpp>
#include <cstring>
#include <cstdlib>
#include <memory>
#include <deque>
#include <list>
#include <set>
using boost::asio::ip::tcp;
typedef std::string echo_message;
class echo_session
: public std::enable_shared_from_this<echo_session>
{
public:
echo_session(tcp::socket socket, std::set<std::shared_ptr<echo_session>>& session_place)
: socket_(std::move(socket)),
session_place_(session_place)
{
std::cout << "Session Initializing...\n";
read_msg_ = "Server!";
}
void start()
{
int se_num=0;
std::cout << "Session starting...\n";
session_place_.insert(shared_from_this());
for(auto session: session_place_)
{
se_num++;
}
std::cout << "Session num: " << se_num << std::endl;
do_read_message();
}
void deliver(const echo_message& msg)
{
this->write_msg_ = msg;
do_write();
}
private:
void do_read_message()
{
auto self(shared_from_this());
char *read_buffer = new char[128];
std::cout << "Reading Message...\n";
boost::asio::async_read(socket_,
boost::asio::buffer(read_buffer, 128),
[this, self, read_buffer](boost::system::error_code ec, std::size_t)
{
if(!ec)
{
read_msg_ = read_buffer;
std::cout << "do_read_message() Message:" << read_msg_ << std::endl;
/*
/////////////////////////////
Used Debugging Part
////////////////////////////
std::cout << "Async Read! : ";
std::cout << read_msg_ << std::endl;
std::cout << "Length:" << read_msg_.length() << std::endl;
*/
deliver(read_msg_);
do_read_message();
}
else
{
std::cout << "Async Read Failed!\n";
std::cerr << "Error: " << ec.message() << std::endl;
}
});
std::cout << "do_read_message() is returned!\n";
}
void do_write()
{
auto self(shared_from_this());
char *read_buffer = new char[sizeof(write_msg_.c_str())];
memcpy(read_buffer, write_msg_.c_str(), sizeof(write_msg_.c_str()));
boost::asio::async_write(socket_,
boost::asio::buffer(read_buffer, sizeof(read_buffer)),
[this, self, read_buffer](boost::system::error_code ec, std::size_t)
{
if(!ec)
{
std::cout << "Message <" << read_buffer << ">Writed!\n";
this->write_msg_ = "\0";
}
else
{
std::cout << "Write Failed\n";
}
std::cout << "do_write lambda returned!\n";
});
}
tcp::socket socket_;
echo_message read_msg_;
echo_message write_msg_;
std::set<std::shared_ptr<echo_session>>& session_place_;
};
class echo_server {
public:
echo_server(boost::asio::io_context& io_context,
const tcp::endpoint& endpoint)
: acceptor_(io_context, endpoint)
{
do_accept();
}
private:
void do_accept()
{
acceptor_.async_accept(
[this](boost::system::error_code ec, tcp::socket socket)
{
if(!ec)
{
std::make_shared<echo_session>(std::move(socket), sessions_)->start();
std::cout << "Accept!\n";
}
else
{
std::cout << "Accept Failed!\n";
}
do_accept();
});
}
tcp::acceptor acceptor_;
std::set<std::shared_ptr<echo_session>> sessions_;
};
int main(int args, char *argv[])
{
try
{
if( args != 2)
{
std::cerr << "Usage: server <port>" << std::endl;
return 1;
}
boost::asio::io_context io_context;
tcp::endpoint endpoint(tcp::v4(), std::atoi(argv[1]));
echo_server ex_server(io_context, endpoint);
io_context.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
}
return 0;
}
client code
#include <iostream>
#include <deque>
#include <thread>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
typedef std::string echo_message;
class echo_client {
public:
echo_client(boost::asio::io_context& io_context,
const tcp::resolver::results_type& endpoints)
: io_context_(io_context),
socket_(io_context)
{
do_connect(endpoints);
}
void write(const std::string string)
{
boost::asio::post(io_context_,
[this, string]()
{
//std::cout << "Post Success!\n";
do_write(string);
});
}
void close()
{
boost::asio::post(io_context_,
[this]()
{
std::cout << "Close Success!\n";
socket_.close();
});
}
private:
void do_connect(const tcp::resolver::results_type& endpoints)
{
boost::asio::async_connect(socket_, endpoints,
[this](boost::system::error_code ec, tcp::endpoint)
{
if(!ec)
{
std::cout << "Async_connect Success!\n";
do_read_message();
}
else
{
std::cout << "Async_connect error!\n";
}
});
}
void do_read_message()
{
std::cout << "read_message()" << std::endl;
//auto self(shared_from_this());
char *read_buffer = new char[128];
boost::asio::async_read(socket_,
boost::asio::buffer(read_buffer, 128),
[this, read_buffer/*, self*/](boost::system::error_code ec, std::size_t size)
{
if(!ec)
{
std::cout << "Async Read Success!\n";
read_msg_ = read_buffer;
if(read_msg_.length() != 0)
{
std::cout << "Message:" << read_msg_ << std::endl;
std::cout << "Length: " << read_msg_.length() << std::endl;
read_msg_ = "\0";
}
do_read_message();
}
else
{
std::cout << "Async_read error!\n";
std::cerr << "Error:" << ec.message() << std::endl;
socket_.close();
}
});
std::cout << "do_read_message() is returned!\n";
}
void do_write(const std::string string)
{
write_msg_ = string;
char *str = new char[sizeof(string.c_str())];
memcpy(str,string.c_str(),sizeof(string.c_str()));
boost::asio::async_write(socket_,
boost::asio::buffer(str, 128),
[this](boost::system::error_code ec, std::size_t)
{
if(!ec)
{
std::cout << "Transport Success!" << std::endl;
}
});
}
private:
boost::asio::io_context& io_context_;
tcp::socket socket_;
echo_message read_msg_;
echo_message write_msg_;
};
int main(int argc, char *argv[])
{
try
{
if(argc != 3)
{
std::cerr << "Usage: client <host> <port>" << std::endl;
return 1;
}
boost::asio::io_context io_context;
tcp::resolver resolver(io_context);
auto endpoints = resolver.resolve(argv[1], argv[2]);
echo_client c(io_context, endpoints);
std::thread t(
[&io_context]()
{
io_context.run();
});
std::string line;
while(std::cin >> line)
{
echo_message msg;
msg = line;
c.write(msg);
}
c.close();
t.join();
}
catch(std::exception e)
{
std::cerr << "Exception: " << e.what() << std::endl;
}
return 0;
}
I can't understand the behaviour of the code below.
When defining the symbol BUG, the third print of the variable this is wrong.
I think there is something in the method resolver::async_resolve that breaks the code. I'd like to understand what :-)
Thanks
#include <boost/asio.hpp>
#include <iostream>
using namespace std;
template <typename F>
#ifdef BUG
void Connect( boost::asio::ip::tcp::resolver& resolver, F Connected )
#else
void Connect( boost::asio::ip::tcp::resolver& resolver, const F& Connected )
#endif
{
resolver.async_resolve(
boost::asio::ip::tcp::resolver::query{ "localhost", "8088" },
[&Connected]( const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator i )
{
Connected();
}
);
}
struct Test
{
void Start()
{
cout << "this1 " << hex << this << dec << endl;
auto handler = [this]()
{
cout << "this2 " << hex << this << dec << endl;
boost::asio::ip::tcp::resolver resolver{ ios };
Connect( resolver, [this]()
{
cout << "this3 " << hex << this << dec << std::endl;
}
);
};
handler();
ios.run();
}
boost::asio::io_service ios;
};
int main()
{
Test t;
t.Start();
}
Your bug is not due to passing to Connect by value vs by const reference, it's undefined behaviour due to calling a dangling reference to a lambda.
This is because you're capturing Connnected by reference in the lambda passed to async_resolve.
resolver.async_resolve(
boost::asio::ip::tcp::resolver::query{ "localhost", "8088" },
[&Connected]( const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator i )
{
Connected(); // Connected is captured by reference
}
);
By the time Connected() is called, it's been popped off the stack and destroyed.
void Start()
{
cout << "this1 " << hex << this << dec << endl;
auto handler = [this]()
{
cout << "this2 " << hex << this << dec << endl;
boost::asio::ip::tcp::resolver resolver{ ios };
Connect( resolver, [this]()
{
cout << "this3 " << hex << this << dec << std::endl;
}
);
};
handler(); // after this function returns Connected will be destructed
ios.run(); // the thread is blocked in ios.run until the resolve returns
}
The call to handler() creates the "Connected" lambda on the stack and passes it to Connect, which in turn creates a lambda which captures Connected by reference, and starts an asynchronous operation.
handler() then returns, popping "Connected" off the stack, destructing it.
ios.run() prevents Test::Start() from returning as it waits for async_resolve to return.
async_resolve completes, and calls its lambda, which in return calls Connected(), which has been destroyed.
You can solve this by capturing Connected by-value
void Connect( boost::asio::ip::tcp::resolver& resolver, F Connected )
{
resolver.async_resolve(
boost::asio::ip::tcp::resolver::query{ "localhost", "8088" },
[Connected]( const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator i )
{
Connected();
}
);
}
I have the following boost::statechart state:
struct PendingWFInfo : bsc::state<PendingWFInfo, PseudoIdle> {
bool success;
PendingWFInfo(my_context ctx) : my_base(ctx) {
std::cout << "[+] PendingWFInfo" << std::endl;
success = context<RH_StateMachine>().startReplenishment();
if (success) {
std::cout
<< ".....................Start replenishment successfully called\n";
} else {
std::cout << ".....................Failed to call Start replenishment "
"service\n";
}
}
~PendingWFInfo() { std::cout << "[-] leaving PendingWFInfo state... \n"; }
typedef boost::mpl::list<bsc::custom_reaction<InboundInfoReceived>,
bsc::transition<Error, CommunicationError>
> reactions;
bsc::result react(const InboundInfoReceived &event) {
if (context<RH_StateMachine>().getWireframeCapacity() > 0) {
transit<UserConfirmationPending>();
}
else{
transit<InboundImpossible>();
}
}
};
When i am in the current state and a InboundInfoReceived event is emitted, i get the following error
/usr/include/boost/statechart/result.hpp:58: boost::statechart::detail::safe_reaction_result::~safe_reaction_result(): Assertion `reactionResult_ == consumed' failed.
The if statement is true but the transition gives me an assertion error.
I use boost::asio::deadline_timer using a member function as a handler (callback function).
If I cancel a timer, how to get error object in print() member function?
class printer
{
public:
printer(boost::asio::io_service& io)
: timer_(io, boost::posix_time::seconds(1)),
count_(0)
{
timer_.async_wait(boost::bind(&printer::print, this));
}
~printer()
{
std::cout << "Final count is " << count_ << "\n";
}
void print()
{
if (count_ < 5)
{
std::cout << count_ << "\n";
++count_;
timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));
timer_.async_wait(boost::bind(&printer::print, this));
}
}
private:
boost::asio::deadline_timer timer_;
int count_;
};
int main()
{
boost::asio::io_service io;
printer p(io);
io.run();
return 0;
}
I try to set error object using bind in async_wait(), but it's compile error
timer_.async_wait(boost::bind(&printer::print, this, boost::asio::placeholders::error));
As long as your method signature matches, it should be no problem:
void print(boost::system::error_code const ec)
// and
boost::bind(&printer::print, this, boost::asio::placeholders::error)
See it Live On Coliru:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
class printer
{
public:
printer(boost::asio::io_service& io)
: timer_(io, boost::posix_time::seconds(1)),
count_(0)
{
timer_.async_wait(boost::bind(&printer::print, this, boost::asio::placeholders::error));
}
~printer()
{
std::cout << "Final count is " << count_ << "\n";
}
void print(boost::system::error_code const ec)
{
if (ec)
std::cout << "Error: " << ec.message() << "\n";
if (count_ < 5)
{
std::cout << count_ << "\n";
++count_;
timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));
timer_.async_wait(boost::bind(&printer::print, this, boost::asio::placeholders::error));
}
}
private:
boost::asio::deadline_timer timer_;
int count_;
};
int main()
{
boost::asio::io_service io;
printer p(io);
io.run();
}
I have written a program that accepts N client connections and then writes data into them. The problem I am having now is: I can only write to N-1 clients, the first one is never written to. I have no idea why this is happening and so I wish some of you might be able to provide some assistance.
I have provided the portion of code that may be associated with this problem:
void ClientPartitionServer::AcceptClientConnections(int port) {
cout << "Listening to connections..." << endl;
cout << "Number of PartitionInstanceConnections: " <<
m_partitionInstanceConnections.size() << endl;
m_acceptor = new boost::asio::ip::tcp::acceptor(m_IOService);
m_endpoint = new boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(),
m_port);
m_acceptor->open(m_endpoint->protocol());
m_acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
m_acceptor->bind(*m_endpoint);
m_acceptor->listen();
boost::asio::ip::tcp::socket* acceptingSocket =
new boost::asio::ip::tcp::socket(m_IOService);
m_acceptor->async_accept(*acceptingSocket, boost::bind(
&ClientPartitionServer::HandleAccept, this, acceptingSocket,
boost::asio::placeholders::error));
}
void ClientPartitionServer::HandleAccept(boost::asio::ip::tcp::socket* socket,
const boost::system::error_code& error) {
cout << "Connection established..." << endl;
m_clientSockets.push_back(new boost::asio::ip::tcp::socket(m_IOService));
cout << m_clientSockets.back()->is_open() << endl;
++m_clientSocketsCounter;
cout << "ClientPartitionServer identifier: " << m_identifier << endl;
cout << "Client connected on port: " << m_port << endl;
cout << "Number of clients on port: " << m_clientSocketsCounter <<
endl;
m_acceptor->async_accept(*m_clientSockets.back(), boost::bind(
&ClientPartitionServer::HandleAccept, this, m_clientSockets.back(),
boost::asio::placeholders::error));
}
void ClientPartitionServer::HandleSignal(char* content, int transferSize,
int identifier) {
if(identifier == m_identifier) {
TransferToQueueBuffer(content, transferSize);
if(m_writeCompleteFlag) {
TransferToWriteBuffer(m_queueBuffer, m_queueBufferSize);
if(m_clientSockets.size() != 0) {
for(vector<boost::asio::ip::tcp::socket*>::const_iterator i =
m_clientSockets.begin(); i != m_clientSockets.end(); ++i) {
WriteToClient(m_writeBuffer, m_queueBufferSize, *i);
}
}
}
}
}
void ClientPartitionServer::WriteToClient(char* content, int transferSize,
boost::asio::ip::tcp::socket* clientSocket) {
boost::lock_guard<boost::mutex> lock(m_writeToClientMutex);
m_writeCompleteFlag = false;
boost::asio::async_write(*clientSocket, boost::asio::buffer("ABC ",
4), boost::bind(&ClientPartitionServer::HandleWrite,
this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void ClientPartitionServer::HandleWrite(const boost::system::error_code& ec,
size_t bytes_transferred) {
cout << "handlewrite" << endl;
m_writeCompleteFlag = true;
}
Thank you for any assistance.
The first async_accept() is called on acceptingSocket which is new'd in AcceptClientConnections() and leaked.
The subsequent async_accept()s are called on sockets that are new'd in HandleAccept() and push_back()'ed into m_clientSockets.
WriteToClient() is executed only on the sockets found in m_clientSockets, never on the first socket.
Solution: push_back that first socket in AcceptClientConnections() into m_clientSockets too.