Running boost asio io_service in a boost thread - c++

I'm using the boost daytime examples as a starter for a project that requires 2 way communication between machines and now need to launch the asio io_service in its own thread so I can pass data across seperatley. Here is the basis of my code: http://www.boost.org/doc/libs/1_35_0/doc/html/boost_asio/tutorial/tutdaytime7/src.html
It all works fine if I invoke the service in main with
io_service.run()
However, if I try to create a thread group and launch there like so:
int main()
{
boost::thread_group tgroup;
try
{
boost::asio::io_service io_service;
tcp_server server1(io_service);
udp_server server2(io_service);
tgroup.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
std::cout << "Server running on TCP port " << tcpport << std::endl << "Server running on UDP port " << udpport << std::endl;
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
tgroup.join_all();
return 0;
}
The code compiles and runs, the port numbers are quoted by cout correctly but it doesn't seem to open a listening port as the client gets a connection refused, although the server program seems to be ticking away awaiting connections.
What is happening here please?

My guess is that your code will work, if you put tgroup.join_all(); before catch:
...
try {
boost::asio::io_service io_service;
tcp_server server1(io_service);
udp_server server2(io_service);
tgroup.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
std::cout << "Server running on TCP port " << tcpport << std::endl << "Server running on UDP port " << udpport << std::endl;
tgroup.join_all();
}
...
io_service and server objects go out of scope here and get destroyed, possibly before thread from thread group even start running.

Related

boost/asio: Very simple chat server can't access the messages that are recieved

I am learning about boost and was messing around with its server and client communication to make a simple chat server, where anything that a client sends, is just displayed on the server. The server itself doesn't send anything and starts the receiving part. It is pretty straight-forward.
Server code:
#include <boost\asio\placeholders.hpp>
#include <boost\bind.hpp>
#include <boost\asio\ip\tcp.hpp>
#include <boost\asio\io_context.hpp>
#include <iostream>
class Server
{
private :
boost::asio::ip::tcp::socket server_socket;
boost::asio::ip::tcp::endpoint server_endpoint;
boost::asio::ip::tcp::acceptor acceptor;
std::string msg;
public :
Server(boost::asio::io_context &io) :
server_socket(io),
server_endpoint(boost::asio::ip::make_address("127.0.0.1"), 27015),
acceptor(io, server_endpoint)
{
acceptor.async_accept(server_socket,
boost::bind(&Server::async_acceptor_handler, this,
boost::asio::placeholders::error));
}
void async_acceptor_handler(const boost::system::error_code &ec)
{
if (!ec)
{
std::cout << "One client connected...\n";
server_socket.async_read_some(boost::asio::buffer(msg),
boost::bind(&Server::async_read_some_handler, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "async_acceptor failed with error code : " << ec.value() << std::endl;
std::cout << "Error description : " << ec.message() << std::endl;
}
}
void async_read_some_handler(const boost::system::error_code &ec)
{
if (!ec)
{
std::cout << msg << std::endl;
server_socket.async_read_some(boost::asio::buffer(msg),
boost::bind(&Server::async_read_some_handler, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "async_acceptor failed with error code : " << ec.value() << std::endl;
std::cout << "Error description : " << ec.message() << std::endl;
}
}
};
int main()
{
boost::asio::io_context io;
Server s(io);
io.run();
return 0;
}
In the client part, it is again a pretty straight-forward code, simply connects to the server and starts taking input from user and sends to server.
Client code:
#include <boost\asio\placeholders.hpp>
#include <boost\bind.hpp>
#include <boost\asio\ip\tcp.hpp>
#include <boost\asio\io_context.hpp>
#include <iostream>
class Client
{
private :
boost::asio::ip::tcp::socket client_socket;
boost::asio::ip::tcp::endpoint server_endpoint;
std::string msg;
public :
Client(boost::asio::io_context &iocontext) :
client_socket(iocontext),
server_endpoint(boost::asio::ip::make_address("127.0.0.1"), 27015)
{
//connect to server endpoint
client_socket.async_connect(server_endpoint,
boost::bind(&Client::async_connect_handler, this,
boost::asio::placeholders::error));
}
void async_connect_handler(const boost::system::error_code &ec)
{
if (!ec)
{
std::cout << "Connected to chat server...\n";
//wait for user input
std::cin >> msg;
std::cout << "\rC : " << msg << std::endl;
client_socket.async_write_some(boost::asio::buffer(msg),
boost::bind(&Client::async_write_some_handler, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "async_connect failed with error code : " << ec.value() << std::endl;
std::cout << "Error description : " << ec.message() << std::endl;
}
}
void async_write_some_handler(const boost::system::error_code &ec)
{
//wait for user input
std::cin >> msg;
std::cout << "\rC : " << msg << std::endl;
client_socket.async_write_some(boost::asio::buffer(msg),
boost::bind(&Client::async_write_some_handler, this,
boost::asio::placeholders::error));
}
};
int main()
{
boost::asio::io_context io;
Client c(io);
io.run();
return 0;
}
Now the problem:
It works fine, and connects to the server too. I get the proper "Connected to chat server..." in client and "One client connected..." in server. The problem arises after that :
In the server console, after the "One client" message, it just starts printing nothing and goes on and on.
The messages sent by the client are never showed in the server console.
Problem 1 can be a issue on my part as I am yet to check the wait functions and other calls which make the server wait. If you can guide me on that, it will be more than amazing. But the major problem is the part 2 of the problem, since, I have no idea why the server is always receiving nothing from client.
PS: This is an incomplete code and I plan to play a bit more with it, so, if there are some major flaws, please tell me so... :)
PPS: Before you say check other questions similar to this, I went through all the similar questions. For ex: this and this, but this are not relevant.
What is the size of string msg in the server side? It is 0. So the server reads always 0 bytes.
When you want to read to string and you call buffer::asio::buffer string must have some size, for example 10. It means you want to read 10 bytes into msg. You can call msg.resize(10) (before reading operation is initiated), then some data will be read into msg by async_read_some (it could be 1,2 bytes, whatever - it is how async_read_some works, but the maximum read characters is 10). But it is poor solution.
You are sending text, so you may consider using read data into streambuf instead of string, when you don't know how many bytes can come from the client side. Then you can call async_read_until with delimiter - it can be for example new line character.
Another solution is to use dynamic buffer. Where data is appened into string and you don't care about the initial size of string buffer. But dynamic buffer doesn't work with member functions of socket like async_read_some, it could be used with async_read as free function.

boost asio run io_service in a thread

I try to run an async network thread using boost::asio and boost::thread.
But the async_accept returns immediately with error code 125 - operation canceled...
attached I a minimal sample of the Problem:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
class Server{
public:
Server()
{ }
void listen(unsigned int port)
{
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);
boost::asio::ip::tcp::acceptor acceptor(m_io_service, endpoint);
std::cout << "Waiting for incomming connection on port: " << port << std::endl;
acceptor.async_accept(*m_stream.rdbuf(), boost::bind( &Server::handleAccept, this, boost::asio::placeholders::error, boost::ref( acceptor ) ) );
m_listenThread = new boost::thread(boost::bind(&boost::asio::io_service::run, &m_io_service));
}
void stop()
{
m_listenThread->join();
}
private:
void handleAccept(const boost::system::error_code& error, boost::asio::ip::tcp::acceptor& acceptor)
{
std::cout << "receiverd incomming connection" << std::endl;
if(error)
std::cout << "ERROR: " << error.message() << "(" << error.value() << ")" << std::endl;
}
boost::asio::io_service m_io_service;
boost::asio::ip::tcp::iostream m_stream;
boost::thread* m_listenThread;
};
int main(int argc, char *argv[])
{
Server server;
server.listen(10000);
while(1);
}
acceptor::async_accept returns immediately, scheduling a call of the handler when either there is an error or a connection is accepted (1)
the listen() function is returning, which is causing the destruction of the acceptor (2)
When an acceptor (or socket, or deadline_timer) is destroyed, all pending handlers are scheduled on the io_service with an error code of asio::error::operation_aborted. This is to satisfy the postconditions of the async_ functions (i.e., "the handler will be called exactly once, as if by io_service.post()") (3)
Therefore, at point (2), your handler is being scheduled - just before the code returns to the main loop.
To fix:
ensure that the acceptor survives until the handler has been called. This is standard practice in asio async programming. The examples on the boost website will help you to make sense of the (sparse) asio documentation.
Don't lose hope. It took me a long time to learn how to use asio properly, and to realise how fantastically powerful it is.

Random error in code

I have a function which has to search all pcs in the network and look for responses:
DLL void get_remote_ip(void)
{
initWSA();
if(create_Sockets() == INVALID_SOCKET)
{
std::cerr << "Socket Error\n";
return;
};
initiate_TXRX_variables();
boost::asio::io_service io_service;
udp_server_search server(io_service);
std::cout << "No crash till here\n";
boost::thread thread_1 = boost::thread(ultra_spam_network_udp);
boost::asio::deadline_timer dt1 = boost::asio::deadline_timer(io_service);
boost::thread thread_2(boost::bind(&boost::asio::io_service::run, &io_service));
dt1.expires_from_now(boost::posix_time::milliseconds(2000));
dt1.wait();
//ip_adr_ccd = server.return_ip(0);
if(ip_adr_ccd != "localhost" && ip_adr_daisy != "localhost")
{
std::cout << "Remote IP of CCD is: " << ip_adr_ccd << '\n';//For debug
std::cout << "Remote IP of TERS is: " << ip_adr_daisy << '\n'; //For debug
}
else
std::cout << "No new remote ips found\n";
//std::cout << Use << '\n';
//thread_1.join();
}
When I call this function, my program crashes sometimes without telling me why, it just tells me "Exception error in <hex-address>". Where is my bug? Is it possible that one thread tries to join, but the other one has not finished now (which can be possible because the errors are quite random and are killing the std::cout-output of the main thread within writing)?
Thank you!
I found my mistake, I have to stop io_service first and then call thread_2.join(), otherwise my thread_2 is crashing.
You don't seem to stop the io_service in a clean way. io_serice::run blocks while there are ramining handlers to be dispatched. My guess is that your udp_server_search causes an endless queueing of handlers. So either your join never finishes because it has to wait for the run() to return which never happens, or if you comment it out, leaving get_remote_ip will destroy the io_service while in thread_2 the run method continues to be executed on a now destroyed object.
What could solve your problem (besides from breaking the endless queue on the server) is manually stopping the ioservice:
boost::thread thread_2( [&]{io_service.run();} );
//do stuff, wait for the timer etc...
io_service.stop(); //run should return as soon as possible
thread_2.join(); //clean finishing of the service.

Make socket server accept multiple clients

I'd like to change the socket class I am using to accept an infinite amount of clients. At the moment it allows one client, and once that client disconnect the server exits.
#include "stdafx.h"
#include "mySocket.h"
#include "myException.h"
#include "myHostInfo.h"
void main()
{
#ifdef WINDOWS_XP
// Initialize the winsock library
WSADATA wsaData;
try
{
if (WSAStartup(0x101, &wsaData))
{
myException* initializationException = new myException(0,"Error: calling WSAStartup()");
throw initializationException;
}
}
catch(myException* excp)
{
excp->response();
delete excp;
exit(1);
}
#endif
// get local server information
myHostInfo uHostAddress;
string localHostName = uHostAddress.getHostName();
string localHostAddr = uHostAddress.getHostIPAddress();
cout << "------------------------------------------------------" << endl;
cout << " My local host information:" << endl;
cout << " Name: " << localHostName << endl;
cout << " Address: " << localHostAddr << endl;
cout << "------------------------------------------------------" << endl;
// open socket on the local host
myTcpSocket myServer(PORTNUM);
cout << myServer;
myServer.bindSocket();
cout << endl << "server finishes binding process... " << endl;
myServer.listenToClient();
cout << "server is listening to the port ... " << endl;
// wait to accept a client connection.
// processing is suspended until the client connects
cout << "server is waiting for client connecction ... " << endl;
myTcpSocket* client; // connection dedicated for client communication
string clientHost; // client name etc.
client = myServer.acceptClient(clientHost);
cout << endl << "==> A client from [" << clientHost << "] is connected!" << endl << endl;
while(1)
{
//Send message to the client
client->sendMessage(std::string("Test"));
// receive from the client
string clientMessageIn = "";
int numBytes = client->recieveMessage(clientMessageIn); //Get message from client, non-blocking using select()
if ( numBytes == -99 ) break;
if(clientMessageIn != "")
{
std::cout << "received: " << clientMessageIn << std::endl; //What did we receive?
/* Do somethign with message received here */
}
}
#ifdef WINDOWS_XP
// Close the winsock library
try
{
if (WSACleanup())
{
myException* cleanupException = new myException(0,"Error: calling WSACleanup()");
throw cleanupException;
}
}
catch(myException* excp)
{
excp->response();
delete excp;
exit(1);
}
#endif
}
How do I change the main() function so that it is constantly waiting for new clients to connect, and once they do, create a new thread for him (the client), or a new handler socket (whatever that may be).
I did find this thread to be informative, but I lack the required knowledge of sockets to actually implement it in the above code.
The answer states When doing socket communication, you basically have a single listener socket for all incoming connections, and multiple handler sockets for each connected client.
So I am guessing in my code;
myTcpSocket myServer(PORTNUM);
myServer.bindSocket();
myServer.listenToClient();
Would be the listener socket
But where/how would I fork the client who is connecting off to a handler socket ?
I am sorry for not being able to show more effort on my part, I don't like coming across as lazy. But for all the hours I have searched and the trial and error resulting from that, I don't have much to show for it.
The idea is simple, you just wait for incoming connections, and once accepted, pass the socket to a thread.
You need to pass the new socket returned from accept to the new thread; you could either spawn a new thread everytime and pass the socket via argument or add the socket to a shared queue used by a bunch of worker threads.
Here's some code for a simple proxy I wrote, it uses boost for the threads and a simple OOP wrapper around the socket functions.
The main thread - it creates 4 worker threads which idle and wait for
the semaphore to be signalled. It pushes all accepted connections to a global queue:
// Global variables
const size_t MAX_THREADS = 4;
queue<Socket> socketBuffer; // Holds new accepted sockets
boost::mutex queueGuard; // Guards the socketBuffer queue
semaphore queueIndicator; // Signals a new connection to the worker threads
bool ctrlc_pressed = false;
// Inside the main function...
boost::thread_group threads;
for(int i = 0; i < MAX_THREADS; i++)
{
threads.create_thread(boost::bind(&threadHandleRequest, i+1));
}
while(!ctrlc_pressed)
{
// wait for incoming connections and pass them to the worker threads
Socket s_connection = s_server.accept();
if(s_connection.valid())
{
boost::unique_lock<boost::mutex> lock(queueGuard);
socketBuffer.push(s_connection);
queueIndicator.signal();
}
}
threads.interrupt_all(); // interrupt the threads (at queueGuard.wait())
threads.join_all(); // wait for all threads to finish
s_server.close();
And the thread code:
bool threadHandleRequest(int tid)
{
while(true)
{
// wait for a semaphore counter > 0 and automatically decrease the counter
try
{
queueIndicator.wait();
}
catch (boost::thread_interrupted)
{
return false;
}
boost::unique_lock<boost::mutex> lock(queueGuard);
assert(!socketBuffer.empty());
Socket s_client = socketBuffer.front();
socketBuffer.pop();
lock.unlock();
// Do whatever you need to do with the socket here
}
}
Hope that helps :)
When doing socket communication, you basically have a single listener
socket for all incoming connections, and multiple handler sockets for
each connected client.
That's the point. You need a separate thread for the listener socket. When it receives an incoming request, it starts another thread for a handler socket (which will create and send the response), and starts listening again (you need a loop).
I would definitely use threads instead of forking. AFAIK on Windows only cygwin is able to fork, but I would not use cygwin for such a program.

Boost-Asio , multi-thread tcp server

I'm not able to succeed about boost-asio multithread program.
Since there is not any good example or documentation about this,
I want your help :)
Simply, I think this code do listen, but when I want to 'cout' buffer data,
it does not print anything or listening once and stopped.
My code is:
void Worker::startThread(int clientNumber) {
cout << "listening: "<< clients[clientNumber]->port << endl;
boost::asio::io_service io_service;
tcp::acceptor acc(io_service, tcp::endpoint(tcp::v4(),portNumber[clientNumber]));
socket_ptr sock(new tcp::socket(io_service));
acc.accept(*sock);
try
{
for (;;) {
char data[max_length];
boost::system::error_code error;
cout << "message?" << endl;
size_t length = sock->read_some(boost::asio::buffer(data), error);
cout << "message :)" << endl;
cout << data << endl;
if(error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
}
}
catch (std::exception& e)
{
std::cerr << "Exception in thread: " << e.what() << "\n";
}
}
void Worker::start() {
cout << "Starting thread server" << endl;
for(int i=0; i<clients.size(); i++) {
boost::thread t(boost::bind(&Worker::startThread, this, i));
}
for(;;);
}
You haven't looked at the documentation very long if you don't see the multi-threaded examples
HTTP Server 3
An HTTP server using a single
io_service and a thread pool calling
io_service::run().
HTTP Server 2
An HTTP server using an
io_service-per-CPU design.
Keep in mind these examples use asynchronous methods, which is where the Boost.Asio library really shines.
You've basically copied the Blocking TCP Echo Server example yet you're unable to find a good example or documentation?
Anyway, I see some problems with your code:
Your saying your listening on clients[clientNumber]->port but the actual port you're listening on is portNumber[clientNumber];
You need to zero-terminate your data after read_some and before printing it;
As soon as the error == boost::asio::error::eof condition is true (the client disconnected) the thread will exit and therefore you'll not be able to (re)connect another client on that port;
You're only accepting the first connection / client, any other clients connecting on the same port will not have their messages handled in any way.