boost::asio::async_read doesn't call the handler and keeps receiving, am trying to receive some buffers that I don't know it's length , but max is 1024
#include "AsyncConnection.h"
AsyncConnection::AsyncConnection(boost::asio::io_service& io_service)
: socket(io_service)
{
}
AsyncConnection::~AsyncConnection()
{
}
AsyncConnection::Pointer AsyncConnection::Create(boost::asio::io_service& io_service){
return Pointer(new AsyncConnection(io_service));
}
boost::asio::ip::tcp::socket& AsyncConnection::GetSocket(){
return socket;
}
void AsyncConnection::BeginReceive(){
boost::asio::async_read(socket, boost::asio::buffer(buffer, 1024),
boost::bind(&AsyncConnection::EndReceive, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void AsyncConnection::EndReceive(const boost::system::error_code& error, std::size_t bytes_transferred){
if (!error){
}
else{
std::cout << error.message() << std::endl;
}
}
it never calls the EndReceive , my guess is it's keeping receiving until the buffer is full?! how to fix that tho!
Related
I try to make TCP asynchronous server, but I'm encountering some difficulties with async_read function. The handler async_read function is never called. I use this command to write on server's socket "nc -C 127.0.0.1 4242". Can you explain to me what I didn't understand or what mistakes I have made? Thanks for your help.
ChatSession.cpp
ChatSession::ChatSession(boost::asio::io_context& ioc)
: __socket(ioc)
{
}
ChatSession::pointer ChatSession::create(boost::asio::io_context& ioc)
{
return pointer(new ChatSession(ioc));
}
tcp::socket& ChatSession::socket()
{
return this->__socket;
}
void ChatSession::handle_start()
{
}
void ChatSession::start()
{
std::string buffer = "Bienvenue\n";
boost::asio::async_write(__socket, boost::asio::buffer(buffer),
boost::bind(&ChatSession::handle_start, shared_from_this()));
readHeader();
}
void ChatSession::handleReadHeader(const boost::system::error_code& error,
std::size_t byte_transferred)
{
if (!error && this->__readMessage.decodeHeader()) {
std::strcpy(__readMessage.getData(), __test.data());
std::cout << __readMessage.getData() << std::endl;
readBody();
} else {
std::cerr << "Erreur" << std::endl;
}
}
void ChatSession::readHeader()
{
__test.resize(6);
boost::asio::async_read(__socket,
boost::asio::buffer(__test),
boost::bind(
&ChatSession::handleReadHeader,
shared_from_this(),
boost::asio::placeholders::error,
}
TcpServer.cpp:
TcpServer::TcpServer(boost::asio::io_context& io_context, int port)
: __acceptor (io_context, tcp::endpoint(tcp::endpoint(tcp::v4(), port)))
{
startAccept();
}
void TcpServer::startAccept()
{
ChatSession::pointer newConnection = ChatSession::create(__io_context);
__acceptor.async_accept(newConnection->socket(),
boost::bind(&TcpServer::handle_accept, this, newConnection,
boost::asio::placeholders::error));
}
void TcpServer::handle_accept(ChatSession::pointer newConnection,
const boost::system::error_code& error)
{
if (!error) {
newConnection->start();
startAccept();
}
}
main.cpp:
int main(int ac, char** av) {
try {
boost::asio::io_context io_context;
TcpServer server(io_context, 4242);
io_context.run();
} catch(const std::exception& e) {
std::cerr << e.what() << std::endl;
}
return 0;
}
I am trying to write my socket class (code below).
At last everything works:reconnection, connection, message send, message receive
But I noticed memory leak when I repeat TCPSocketBody::Connect(const std::string &adress, const std::string &port) if for example host is unreachable. Size of my application is growing.
I discovered that when I remove line:
thread_io_service = boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_global));
the problem disappears. But I need this line. What I am doing wrong?
I checked from command line number of thread in my application and it always is 1 or 2.
#include "TCPSocketBody.h"
TCPSocketBody::TCPSocketBody() : socket_(io_service_global),
resolver(io_service_global),
connected(false),
expectedMessage(0)
{
}
void TCPSocketBody::Close()
{
io_service_global.post(boost::bind(&TCPSocketBody::DoClose, this));
}
void TCPSocketBody::Connect(const std::string &adress, const std::string &port)
{
io_service_global.reset();
iterator = resolver.resolve({adress, port});
boost::asio::async_connect(socket_, iterator,
boost::bind(&TCPSocketBody::HandleConnect, this,
boost::asio::placeholders::error));
socket_.set_option(boost::asio::ip::tcp::no_delay(true));
thread_io_service = boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_global));
}
void TCPSocketBody::HandleConnect(const boost::system::error_code& error)
{
if (!error)
{
connected = true;
boost::asio::async_read(socket_,
boost::asio::buffer(data_to_read, MessageCoder::BufferSize()), boost::asio::transfer_all(),
boost::bind(&TCPSocketBody::HandleReadHeader, this,
boost::asio::placeholders::error));
} else
{
Close();
}
}
void TCPSocketBody::HandleReadHeader(const boost::system::error_code& error)
{
expectedMessage = MessageCoder::HeaderToVal(data_to_read);
if (expectedMessage > MessageCoder::MaxMessageSize())
{
expectedMessage = 0;
Close();
} else
{
boost::asio::async_read(socket_,
boost::asio::buffer(data_to_read, expectedMessage), boost::asio::transfer_all(),
boost::bind(&TCPSocketBody::HandleReadMessage, this,
boost::asio::placeholders::error));
}
}
void TCPSocketBody::HandleReadMessage(const boost::system::error_code& error)
{
expectedMessage = 0;
boost::asio::async_read(socket_,
boost::asio::buffer(data_to_read, MessageCoder::BufferSize()), boost::asio::transfer_all(),
boost::bind(&TCPSocketBody::HandleReadHeader, this,
boost::asio::placeholders::error));
}
void TCPSocketBody::WriteMessage(char *dataToSend)
{
io_service_global.post(boost::bind(&TCPSocketBody::Write, this, dataToSend));
}
void TCPSocketBody::Write(char *dataToSend)
{
data = dataToSend;
boost::asio::async_write(socket_,
boost::asio::buffer(data, std::strlen(data)),
boost::bind(&TCPSocketBody::HandleWrite, this,
boost::asio::placeholders::error));
}
void TCPSocketBody::HandleWrite(const boost::system::error_code& error)
{
if (!error)
{
}
else
{
Close();
}
}
void TCPSocketBody::DoClose()
{
socket_.close();
connected = false;
}
Without the header file, it is hard to be certain. I suspect that thread_io_service is a member variable. A second call to 'Connect' will overwrite the existing value without destroying the object. Any memory allocated within the object will be leaked.
Perhaps try making a std::vector of thread_io_service and push_back each new thread on the connect call. The vector will destroy the contained objects when it gets destructed.
Valgrind can likely pinpoint the issue with more detail.
I've not found a specific reference to a solution to this problem. I am writing a server using a modified version of the boost asynch example 3. I am using async_read_until. when recieving the message the program calls the handle read and calls for a new thread but the streambuf is still contains the delimeter (i'm sending an xml from a different project) and immediately calls another thread up to my threadmax.
class server{
....
void server::run()
{
std::vector<boost::shared_ptr<boost::thread>> threads;
for (std::size_t i = 0; i < thread_pool_size_; ++i)
{
boost::shared_ptr<boost::thread> thread(new boost::thread(
boost::bind(&boost::asio::io_service::run, &io_service_)));
threads.push_back(thread);
}
//wait for all threads in the pool to exit.
for (std::size_t i = 0; i < threads.size(); ++i)
threads[i]->join();
}
void server::start_accept()
{
new_connection_.reset(new connection(io_service_, request_handler_));
acceptor_.async_accept(new_connection_->socket(),
boost::bind(&server::handle_accept, this,
boost::asio::placeholders::error));
}
void server::handle_accept(const boost::system::error_code& e)
{
if (!e)
{
new_connection_->start();
}
start_accept()
}
}
class connection{
....
void connection::start()
{
boost::asio::async_read_until(socket_, buffer_,
"<\\User>",
boost::bind(&connection::handle_read, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void connection::handle_read(const boost::system::error_code& e,
std::size_t bytes_transferred)
{
if(!e)
{
std::ostringstream ss;
std::cout << ss.str();
buffer_.consume(buffer_.size());
}
}
I'm developing a 3d (first/third person) game and I'm trying to make it multiplayer using TCP sockets. I'm using the boost asio library for this, and I'm in a little over my head. I've played with the tutorials and examples a bit on the boost asio doc page and they compiled/ran/worked just fine, I'm just a little confused as to how everything works.
Right now I'm just trying to make the server accept messages from the client, and print the message after receiving it. When I execute the code below (it compiles/links/runs fine), nothing happens. More specifically, the client appears to successfully send the message, and the server never seems to receive the message.
Client code:
ClientFramework::ClientFramework() :
mResolver(mIOService)
{
}
bool ClientFramework::Initialize()
{
try
{
tcp::resolver::query query("localhost", "daytime");
tcp::resolver::iterator it = mResolver.resolve(query);
tcp::socket socket(mIOService);
boost::asio::connect(socket, it);
std::string s = "hello world";
boost::system::error_code e;
socket.write_some(boost::asio::buffer(s.c_str(), s.size()), e);
if (e)
{
throw boost::system::system_error(e);
}
} catch (std::exception& e)
{
gLog << LOG_ERROR << e.what() << "\n";
}
return true;
}
Server code:
ServerFramework::ServerFramework() :
mAcceptor(mIOService, tcp::endpoint(tcp::v4(), 13))
{
}
bool ServerFramework::Initialize()
{
mIOService.run();
StartAccept();
return true;
}
void ServerFramework::StartAccept()
{
Connection::ptr conn =
Connection::create(mAcceptor.get_io_service());
mAcceptor.async_accept(conn->Socket(),
boost::bind(&ServerFramework::HandleAccept, this, conn,
boost::asio::placeholders::error));
}
void ServerFramework::HandleAccept(Connection::ptr conn,
const boost::system::error_code& error)
{
if (!error)
{
conn->Initialize();
}
StartAccept();
}
Connection::ptr Connection::create(boost::asio::io_service& io_service)
{
return ptr(new Connection(io_service));
}
tcp::socket& Connection::Socket()
{
return mSocket;
}
void Connection::Initialize()
{
boost::asio::async_read(mSocket, boost::asio::buffer(buf, BUFFER_SIZE),
boost::bind(&Connection::handle_read, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
Connection::Connection(boost::asio::io_service& io_service) :
mSocket(io_service)
{
}
void Connection::handle_read(const boost::system::error_code& e, size_t size)
{
std::string s(buf, size);
gLog << LOG_INFO << s << "\n";
boost::asio::async_read(mSocket, boost::asio::buffer(buf, BUFFER_SIZE),
boost::bind(&Connection::handle_read, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
It does not look like your io_service has any work to do when you invoke run().
bool ServerFramework::Initialize()
{
mIOService.run(); // <-- you don't check the return value here
StartAccept();
return true;
}
it will return the number of handlers executed, I suspect it is zero. Try invoking it after async_accept()
bool ServerFramework::Initialize()
{
StartAccept();
mIOService.run();
return true;
}
Though, it isn't entirely obvious by your limited code snippets where you invoke ServerFramework::Initialize(). I suggest editing your question with a short, self contained, correct example that we can compile with little to no effort. Your current code will not compile without additional boilerplate stuff, like main().
I'm trying to modify the echo server example from boost asio and I'm running into problem when I try to use boost::asio::async_read_until. Here's the code:
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
class session
{
public:
session(boost::asio::io_service& io_service)
: socket_(io_service)
{
}
tcp::socket& socket()
{
return socket_;
}
void start()
{
std::cout<<"starting"<<std::endl;
boost::asio::async_read_until(socket_, boost::asio::buffer(data_, max_length), ' ',
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
std::cout<<"handling read"<<std::endl;
if (!error)
{
boost::asio::async_write(socket_,
boost::asio::buffer(data_, bytes_transferred),
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));
}
else
{
delete this;
}
}
void handle_write(const boost::system::error_code& error)
{
if (!error)
{
/*
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
*/ }
else
{
delete this;
}
}
private:
tcp::socket socket_;
enum { max_length = 1024 };
char data_[max_length];
};
class server
{
public:
server(boost::asio::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
session* new_session = new session(io_service_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
void handle_accept(session* new_session,
const boost::system::error_code& error)
{
if (!error)
{
new_session->start();
new_session = new session(io_service_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
else
{
delete new_session;
}
}
private:
boost::asio::io_service& io_service_;
tcp::acceptor acceptor_;
};
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: async_tcp_echo_server <port>\n";
return 1;
}
boost::asio::io_service io_service;
using namespace std; // For atoi.
server s(io_service, atoi(argv[1]));
io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
The problem is when I try to compile I get this weird error:
server.cpp: In member function ‘void session::start()’:
server.cpp:27: error: no matching function for call to ‘async_read_until(boost::asio::basic_stream_socket >&, boost::asio::mutable_buffers_1, char, boost::_bi::bind_t, boost::_bi::list3, boost::arg<1> ()(), boost::arg<2> ()()> >)’
Can someone please explain what's going on? From what I can tell the arguments to async_read_until are correct.
Thanks!
The second argument of async_read_until should be a streambuf object into which the data will be read. To put it simple, you need to pass a boost::asio::streambuf by reference, not a boost::asio::buffer by value.
There is no need to use streambufs. There are overloads that accept dynamic buffers. Dynamic is key since read_until implies the need for a buffer that can increase its size at the callee's discretion. Therefore, all you need is to replace the call to boost::asio::buffer with boost::asio::dynamic_buffer and call it on either std::string or std::vector<char>.
...
void start()
{
std::cout<<"starting"<<std::endl;
boost::asio::async_read_until(
socket_, boost::asio::dynamic_buffer(data_), ' ',
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
...
private:
tcp::socket socket_;
std::string data_;
// or
//std::vector<char> data_;
};
I would also get rid of boost::bind since it's an overkill and use a lambda (use them as much as you can)
[this](const boost::system::error_code& error, size_t bytes_transferred) {
handle_read(error, bytes_transferred);
}
const (in)correctness may also cause this type of error message.