I'm trying to send messages via async_write, but they are only sent after I shutdown the server ( ctrl-c)
For example: as client I send "test" and "test2", and only after closing the server client recieves "testtest2"
I'm making a chat that accepts a message from a user (successfully) and has to broadcast it to everyone
message sending code
void Server::writeHandler(int id, boost::system::error_code error){
if (!error){
std::cout << "[DEBUG] message broadcasted ";
} else {
close_connection(id);
}
}
void Server::broadcast(std::string msg, boost::system::error_code error){
for (auto& user : m_users){ // for every user in unordered map of users
asio::async_write(user.second->socket, asio::buffer(msg, msg.size()),
std::bind(&Server::writeHandler, this, user.first, std::placeholders::_1));
}
}
broadcast calls in onMessage
void Server::onMessage(int id, boost::system::error_code error){
if (!error){
broadcast(m_read_msg, error); // char m_read_msg[PACK_SIZE] // PACK_SIZE = 512
asio::async_read(m_users[id].get()->socket, asio::buffer(m_read_msg, PACK_SIZE), // PACK_SIZE = 512
std::bind(&Server::onMessage, this, id, std::placeholders::_1));
} else {
close_connection(id);
}
}
server run function:
void Server::run(int port){
asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port);
std::cout << "[DEBUG] binded on " << port << std::endl;
// acceptor initialization
m_acceptor = std::make_shared<asio::ip::tcp::acceptor>(m_io, endpoint);
// start to listen for connections
listen();
// run the io_service in thread
io_thread = std::thread( [&]{ m_io.run(); } ); // m_io = io_serivce
while (true){
}
}
void Server::listen(){
std::shared_ptr<User> pUser(new User(m_io));
m_acceptor->async_accept(pUser->socket, std::bind(&Server::onAccept, this, pUser));
}
Infinite loops are UB in C++.
Your
std::string msgis a local (parameter) and passing it to an async operation (async_write) is also UB.To start a thread, immediately followed by an infinite loop is useless, unless the objective is to waste a lot of CPU power. So, replace it with just
Next up, the code is far from self contained and lacks all manner of error handling. Here's my imaged minimal completion, fixing the UBs already mentioned:
Note that nothing ever broadcasts in the first place, so I'm not sure what the problem is.
What I can see is that
io_serviceis deprecated (useio_context)io_service&around is anti-pattern (use executors)ServerandUser. The handlers for each user session need to use the state fromUserand are much more naturally member ofUser. In fact, that's the only way to do it correctly because with a out-of-session broadcast you MUST guarantee the correct sequencing of writes, which means you MUST have a per-session (user) queueenable_shared_from_thism_usersstore aweak_ptrso you can observe when connections terminateHere's what it would look like with those addressed:
Live On Coliru
Local demo:
BONUS: Chat Server?
Of course, still nothing ever calls
broadcast. Assuming you might actually want something like a chat-server:Live On Coliru
With a local demo again: