I would like to use a dedicated thread to receive udp data using asio library. An example code is given below.
#define ASIO_STANDALONE // we are using the stand aloe version of ASIO and Not Boost::ASIO
#include <iostream>
#include "include/asio.hpp"
#include <array>
#include <thread>
class UDPServer
{
public:
UDPServer( asio::io_service& ioService): m_socket(ioService)
{}
~UDPServer(){}
void listen(const int& port)
{
m_socket.open(asio::ip::udp::v4());
m_socket.bind(asio::ip::udp::endpoint(asio::ip::udp::v4(), port));
#define DEDICATED_THREAD_FLAG 1
#if DEDICATED_THREAD_FLAG
m_thread = std::thread( &UDPServer::receive, this);
std::cout<<"Thead Id in listen:"<<std::this_thread::get_id()<<std::endl;
m_thread.join();
#else
receive();
#endif
}
template<std::size_t SIZE>
void processReceivedData(const std::array<char, SIZE>& rcvdMessage,
const int& rcvdMessageSizeInBytes,
const std::error_code& error)
{
std::cout<<"Rcvd Message: "<<rcvdMessage.data()<<std::endl;
receive();
}
void receive()
{
std::cout<<"Thead Id in receive0:"<<std::this_thread::get_id()<<std::endl;
asio::ip::udp::endpoint m_udpRemoteEndpoint;
m_socket.async_receive_from(asio::buffer(recv_buffer, recv_buffer.size()/*NetworkBufferSize*/), m_udpRemoteEndpoint,
[this](std::error_code ec, std::size_t bytesReceived)
{
std::cout<<"Thead Id in receive1:"<<std::this_thread::get_id()<<std::endl;
processReceivedData(recv_buffer, bytesReceived, ec);
});
}
private:
asio::ip::udp::socket m_socket;
std::thread m_thread;
static const int NetworkBufferSize = 9000;
std::array<char, NetworkBufferSize> recv_buffer;
};
int main()
{
std::cout<<"Main Thead Id:"<<std::this_thread::get_id()<<std::endl;
asio::io_service m_ioService;
UDPServer myServer( m_ioService);
myServer.listen(12345); // starting the UDP server
std::cout<<"Program waiting.."<<std::endl;
m_ioService.run();
std::cout<<"Program ending.."<<std::endl;
}
A non dedicated thread version can be enable by changing DEDICATED_THREAD_FLAG to 0, which is working as expected.
However, when DEDICATED_THREAD_FLAG is set to 1, a new thread is starting and entering the "receive" function. But when a udp packet arrives, it is handled by only the main thread and not by the dedicated thread.
What is going wrong here?
The whole event-loop that handles the asynchronous calls is done by the io_server, which you run in the main thread.
Instead of running the receive function in the thread (it will return immediately anyway), you should run io_service::run.
Related
I am new to Asio, so I am a little confused about the control flow of asynchronous operations. Let's see this server:
class session
{
...
sendMsg()
{
bool idle = msgQueue.empty();
msgQueue.push(msg);
if (idle)
send();
}
send()
{
async_write(write_handler);
}
write_handler()
{
msgQueue.pop()
if (!msgQueue.empty())
send();
}
recvMsg()
{
async_read(read_handler);
}
read_handler()
{
...
recvMsg();
}
...
};
class server
{
...
start()
{
async_accept(accept_handler);
}
accept_handler()
{
auto client = make_shared<session>(move(socket));
client->recvMsg();
...
start();
}
...
};
int main()
{
io_context;
server srv(io_context, 22222);
srv.start();
io_context.run();
return 0;
}
In this case, all completion handlers accept_handler, read_handler, write_handler will be called in the thread calling io_context.run(), which is the main thread. If they will run in the same thread, it means they will run sequentially, not concurrently, right? And further, the msgQueue will be accessed sequentially, so there is no need a mutex lock for this queue, right?
I think async_* functions tell the operating system to do some work, and these work will run simultaneously in some other threads with their own buffers. Even if these work are done at the same time(say, at a point, a new connection requirement arrives, a new message from a exist client arrives, sending a message to a exist client is done), the completion handlers(accept_handler, read_handler, write_handler) will still be called sequentially. They will not run concurrently, am I correct?
Thank you so much for your help.
Yes. There's only one thread running the io_context, so all completion handlers will run on that one thread. Indeed this implies a strand (the implicit strand) of execution, namely, all handlers will execute sequentially.
See: https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/overview/core/threads.html
and these work will run simultaneously in some other threads with their own buffers
They will run asynchronously, but not usually on another thread. There could be internal threads, or kernel threads, but also just hardware. Their "own" buffer is true, but dangerously worded, because in Asio the operations never own the buffer - you have to make sure it stays valid until the operation completes.
Note:
if there can be multiple threads running (or polling) the io service, you need to make sure access to IO objects is synchronized. In Asio this can be achieved with strand executors
not all IO operations may be active in overlapping fashion. You seem to be aware of this given the msgQueue in your pseudo code
Bonus
For bonus, let me convert your code into non-pseudo code showing an explicit strand per connection to be future proof:
Live On Coliru
#include <boost/asio.hpp>
#include <deque>
namespace asio = boost::asio;
using asio::ip::tcp;
using boost::system::error_code;
using namespace std::placeholders;
class session : public std::enable_shared_from_this<session> {
public:
session(tcp::socket s) : s(std::move(s)) {}
void start() {
post(s.get_executor(), [self = shared_from_this()] { self->recvMsg(); });
}
void sendMsg(std::string msg) {
post(s.get_executor(), [=, self = shared_from_this()] { self->do_sendMsg(msg); });
}
private:
//... all private members on strand
void do_sendMsg(std::string msg) {
bool was_idle = msgQueue.empty();
msgQueue.push_back(std::move(msg));
if (was_idle)
do_writeloop();
}
void do_writeloop() {
if (!msgQueue.empty())
async_write(s, asio::buffer(msgQueue.front()),
std::bind(&session::write_handler, shared_from_this(), _1, _2));
}
void write_handler(error_code ec, size_t) {
if (!ec) {
msgQueue.pop_front();
do_writeloop();
}
}
void recvMsg() {
//async_read(s, asio::dynamic_buffer(incoming),
//std::bind(&session::read_handler, shared_from_this(), _1, _2));
async_read_until(s, asio::dynamic_buffer(incoming), "\n",
std::bind(&session::read_handler, shared_from_this(), _1, _2));
}
void read_handler(error_code ec, size_t n) {
if (!ec) {
auto msg = incoming.substr(0, n);
incoming.erase(0, n);
recvMsg();
sendMsg("starting job for " + msg);
sendMsg("finishing job for " + msg);
sendMsg(" -- some other message --\n");
}
}
tcp::socket s;
std::string incoming;
std::deque<std::string> msgQueue;
};
class server {
public:
server(auto ex, uint16_t port) : acc(ex, tcp::v4()) {
acc.set_option(tcp::acceptor::reuse_address(true));
acc.bind({{}, port});
acc.listen();
}
void accept_loop() {
acc.async_accept(make_strand(acc.get_executor()),
std::bind(&server::accept_handler, this, _1, _2));
}
void accept_handler(error_code ec, tcp::socket s) {
if (!ec ){
std::make_shared<session>(std::move(s))->start();
accept_loop();
}
}
private:
tcp::acceptor acc;
};
int main() {
boost::asio::io_context ioc;
server srv(ioc.get_executor(), 22222);
srv.accept_loop();
ioc.run();
}
With a sample client
for a in foo bar qux; do (sleep 1.$RANDOM; echo "command $a")|nc 127.0.0.1 22222 -w2; done
Prints
starting job for command foo
finishing job for command foo
-- some other message --
starting job for command bar
finishing job for command bar
-- some other message --
starting job for command qux
finishing job for command qux
-- some other message --
i have this socket-tcp.h with an wrapper of socket implementation using boost asio:
#include <boost/asio.hpp>
#include <iostream>
#include <boost/thread.hpp>
static const std::string PORT = "65432";
static const std::string HOST = "127.0.0.1";
struct Client
{
boost::asio::io_service& io_service;
boost::asio::ip::tcp::socket socket;
Client(boost::asio::io_service& svc, std::string const& host, std::string const& port)
: io_service(svc), socket(io_service)
{
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::iterator endpoint = resolver.resolve(boost::asio::ip::tcp::resolver::query(host, port));
boost::asio::connect(this->socket, endpoint);
};
void send(std::string const& message) {
socket.send(boost::asio::buffer(message));
}
};
boost::asio::io_service svc;
Client client(svc, HOST, PORT);
class TcpSocket
{
private:
std::string HOST;
std::string PORT;
public:
TcpSocket (std::string const& host, std::string const& port): HOST{ host },PORT{ port }
{
}
void send(std::string const& message)
{
boost::thread t(client_thread,boost::ref(message),boost::ref(HOST),boost::ref(PORT));
t.join();
}
static void client_thread(std::string const& message,std::string const& host,std::string const& port)
{
client.send(message);
}
};
so that my main file looks like:
#include "socket-tcp.h"
int main()
{
TcpSocket socket(PORT,HOST);
std::string message = "socket implemented using global variables";
while (true)
{
socket.send(message);
}
}
I'm trying to figure out a way of implement this without the global variables
boost::asio::io_service svc;
Client client(svc, HOST, PORT);
such that TcpSocket be like:
class TcpSocket
{
//Object* myObject; // Will not try to call the constructor or do any initializing
//myObject = new Object(...); // Initialised now
private:
std::string HOST;
std::string PORT;
boost::asio::io_service svc;
public:
TcpSocket (std::string const& host, std::string const& port): HOST{ host },PORT{ port }
{
Client client(svc, HOST, PORT);
}
void send(std::string const& message)
{
boost::thread t(client_thread,boost::ref(message),boost::ref(HOST),boost::ref(PORT));
t.join();
}
static void client_thread(std::string const& message,std::string const& host,std::string const& port)
{
client.send(message);
}
};
but i end up with the runtime error:
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >'
what(): resolve: Service not found
is there a way to avoid using these global variables (objects), and keeping the same socket open all the time, without closing and opening it again at each new message?
I accept better implementations or suggestions for this wrapper, but the goal is to keep main as simple and clear as possible.
The "service not found" merely means that the port is not a valid service. That's because you swapped host and port parameters.
But that is the least of your worries.
You're playing fast and loose with object lifetimes. For example, you pass message all the way to another thread &&by reference** (std::string const&), but the object referenced lives on the stack (as a function argument) so that invokes Undefined Behaviour.
Besides, it's not clear how the thread (or client_thread) is supposed to access the Client instance (that your code constructs as a local variable in the TcpSocket constructor only). Let alone that it would be unsafe to share that client across threads.
Medium Fix
Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
#include <boost/thread.hpp>
static const std::string HOST = "127.0.0.1";
static const std::string PORT = "65432";
using boost::asio::ip::tcp;
struct Client
{
tcp::socket socket;
//template <typename Executor>
using Executor = boost::asio::io_service&;
Client(Executor executor, std::string const& host, std::string const& port)
: socket(executor)
{
std::cout << std::quoted(host) << std::endl;
std::cout << std::quoted(port) << std::endl;
auto ep = tcp::resolver{socket.get_executor()}.resolve(host, port);
connect(socket, ep);
};
void send(std::string const& message) {
socket.send(boost::asio::buffer(message));
}
};
class TcpSocket {
private:
std::string _host;
std::string _port;
boost::asio::io_service _svc;
public:
TcpSocket(std::string const& host, std::string const& port)
: _host{host}
, _port{port}
{
}
void send(std::string const& message)
{
boost::thread t( //
client_thread, boost::ref(_svc), message, _host, _port);
t.join();
}
static void client_thread( //
boost::asio::io_service& svc,
std::string message, // NOT A REFERENCE
std::string host, // same
std::string port)
{
Client client(svc, host, port);
client.send(message);
}
};
//#include "socket-tcp.h"
int main()
{
TcpSocket socket(HOST, PORT);
std::string const message = "socket implemented using global variables";
while (true) {
socket.send(message);
}
}
More Notes
The thread is by definition useless, since you join it immediately. But if you really wanted that, please consider c++11 style:
void send(std::string const& message)
{
boost::thread t([=, &_svc] {
Client client(_svc, _host, _port);
client.send(message);
});
t.join();
}
It makes far more sense to do it on the main thread:
void send(std::string const& message)
{
Client client(_svc, _host, _port);
client.send(message);
}
Or to use async IO. Note that you should probably prefer to pass executors rather than sharing references to an execution context. Also, prefer io_context because io_service is deprecated.
Here's a simplified program that still does the same: Live On Coliru
BONUS - Async With A Thread Pool
Seems like you wanted the messages to be delivered in async fashion. However, you didn't know how to get threads in the background. Regardless, it wouldn't be a safe idea to "just create a new thread" each time. The professional approach is to use a thread pool.
This example uses a ddefault boost::asio::thread_pool and throws in a strand (even though it's not currently required) and a Session object to hold all the state for a single message. Note that we now cache the resolver results. That can be a good thing ,or a bad thing depending on your application.
Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
#include <boost/thread.hpp>
#include <boost/enable_shared_from_this.hpp>
using boost::asio::ip::tcp;
using boost::system::error_code;
class TcpClient {
public:
TcpClient(std::string const& host, std::string const& port)
: _ep(tcp::resolver{_io}.resolve(host, port))
{ }
void send(std::string message)
{
boost::make_shared<Session>( //
make_strand(_io.get_executor()), std::move(message), _ep)
->run();
}
~TcpClient() {
//_io.stop(); // optionally
_io.join();
}
private:
boost::asio::thread_pool _io;
tcp::resolver::results_type _ep ;
struct Session : boost::enable_shared_from_this<Session> {
Session(auto executor, std::string message,
tcp::resolver::results_type ep)
: _socket(executor)
, _message(std::move(message))
, _ep(ep)
{
}
void run() {
async_connect( //
_socket, _ep,
[this, self = shared_from_this()](error_code ec,
tcp::endpoint) {
async_write(_socket, boost::asio::buffer(_message),
[this, self](error_code ec, size_t) {});
});
}
tcp::socket _socket;
std::string _message;
tcp::resolver::results_type _ep;
};
};
//#include "socket-tcp.h"
int main()
{
TcpClient socket("127.0.0.1", "65432");
for (int i = 0; i<100; ++i) {
socket.send("socket implemented using async IO on thread pool " +
std::to_string(i) + "\n");
}
}
I'm testing my application which contains a TCP client. To test that I've created a simple TCP server based on boost examples. The problem is that once each ~5 test invocations with valgrind the test fails to connect to local server. When not using valgrind all the tests pass on each invocation.
I can't find the cause of it. The server implementation:
class arcturus_mock
{
private:
boost::asio::io_service ios;
boost::asio::ip::tcp::socket socket;
boost::asio::ip::tcp::acceptor acceptor;
std::thread t;
public:
arcturus_mock(short port)
: acceptor(ios,
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
, socket(ios)
{
do_accept();
}
// A new thread is created to not to block on calling
// io_service::run function
void run()
{
t = std::thread([&ios = this->ios]() { ios.run(); });
}
void stop()
{
ios.stop();
t.join();
}
private:
void do_accept()
{
acceptor.async_accept(socket, [this](boost::system::error_code ec) {
if (!ec)
std::make_shared<arcturus_mock_session>(std::move(socket))
->start();
do_accept();
});
}
};
And the corresponding session:
class arcturus_mock_session : public std::enable_shared_from_this<arcturus_mock_session>
{
private:
boost::asio::ip::tcp::socket socket;
char data[1024];
public:
arcturus_mock_session(boost::asio::ip::tcp::socket &&used_socket)
: socket(std::move(used_socket))
{
}
void start()
{
using boost::asio::async_write;
async_write( ...
}
};
I run the tests using Catch2 framework. This is how the test case looks like:
TEST_CASE(" ... ")
{
arcturus_mock mock(1050);
mock.run();
SECTION(" ... ")
{
client c;
// That throws sometimes
REQUIRE_NOTHROW(c.connect_and_handle("localhost", 1050));
}
mock.stop();
}
Could the problem be caused by the thread which won't manage to create and start the server by the time the client connects to it?
It's a race condition.
When the server thread starts, there is not necessarily any work to be done (async_accept may not happen quickly enough). This means run() simply exits immediately, and the server doesn't run.
Either make async_accept precede the thread launch or use a io_service::work to keep the service occupied.
All of the boost examples work until I try to implement the exact same thing myself. I'm starting to think there must be an order of creation or io_service ownership for things to block properly.
My server structure is as follows:
class Server {
public:
Server(unsigned short port)
: ioService_(), acceptor_(ioService_), socket_(ioService_) {
acceptClient(); // begin async accept
}
void start(); // runs ioService_.run();
private:
void acceptClient();
asio::io_service ioService_;
tcp::acceptor acceptor_;
tcp::socket socket_;
Cluster cluster_; // essentially just a connection manager
};
The acceptClient() function works like this:
void Server::acceptClient() {
acceptor_.async_accept(socket_, [this](const system::error_code& e){
if(!acceptor_.is_open()) return;
if(!e) {
cluster_.add(std::make_shared<Client>(std::move(socket_), cluster_));
}
acceptClient();
});
}
I'm not sure if you need an outline of the Client class since the server should run and block even with no clients.
The creation of the server goes as follows:
try {
Server server(port);
server.start(); // this calls the server's member io_service's run();
} catch (const std::exception& e) {
std::cerr << e.what(); << std::endl;
}
The problem is the server instantly closes after that call. The program starts and then exits with no errors. Is there something that io_service.run() relies on? e.g. some form of asynchronous link that I've forgotten? My learned this design from boost asio's http server design but I've worked it to fit my basic purposes. The problem is some boost examples establish a new member boost tcp::socket in the client itself rather than moving the server's to the client so I'm quite confused. They also tend to use boost's versions of std::bind instead of lambdas which etc.
So, can anyone give me a brief rundown on how to create a basic, stripped, async server since the boost examples are really confusing since the code conventions differ per example. I was wondering if anybody noticed anything straight away that would cause my server to instantly close.
Thanks.
I tested async_accept with the following code which sends Hello to clients connecting to the port. At least there is the creation of endpoint object, acceptor.open(endpoint.protocol()), acceptor.bind(endpoint) and acceptor.listen() calls that seem to be missing from your code.
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <string>
using namespace boost::asio;
void handle_accept(
io_service * ios,
ip::tcp::acceptor * acceptor,
ip::tcp::socket * socket,
const boost::system::error_code & error)
{
if (!error) {
std::string msg("Hello\n");
socket->send(buffer(msg, msg.length()));
ip::tcp::socket * temp = new ip::tcp::socket(*ios);
acceptor->async_accept(*temp,
boost::bind(handle_accept,
ios, acceptor, temp,
placeholders::error));
}
}
int main(void)
{
io_service ios;
ip::tcp::socket socket(ios);
ip::tcp::acceptor acceptor(ios);
ip::tcp::endpoint endpoint(ip::tcp::v4(), 1500);
acceptor.open(endpoint.protocol());
acceptor.set_option(ip::tcp::acceptor::reuse_address(true));
acceptor.bind(endpoint);
acceptor.listen();
acceptor.async_accept(socket,
boost::bind(handle_accept,
&ios, &acceptor, &socket,
placeholders::error));
ios.run();
/*
acceptor.accept(socket);
std::string msg("Hello\n");
socket.send(buffer(msg, msg.length()));
*/
}
A version with a Server class and a lambda as a argument for async_accept:
#include <boost/asio.hpp>
#include <functional>
#include <string>
using namespace boost::asio;
class Server {
public:
Server(unsigned short port) : ios(), acceptor(ios), socket(ios),
endpoint(ip::tcp::v4(), port) {
acceptor.open(endpoint.protocol());
acceptor.set_option(ip::tcp::acceptor::reuse_address(true));
acceptor.bind(endpoint);
acceptor.listen();
nsocket = &socket;
}
void run() {
std::function<void (const boost::system::error_code &)> f;
f = [&f, this] (const boost::system::error_code & error) {
if (!error) {
std::string msg("Hello\n");
nsocket->send(buffer(msg, msg.length()));
nsocket = new ip::tcp::socket(ios);
acceptor.async_accept(*nsocket, f);
}
};
acceptor.async_accept(socket, f);
ios.run();
}
protected:
io_service ios;
ip::tcp::acceptor acceptor;
ip::tcp::socket socket;
ip::tcp::endpoint endpoint;
ip::tcp::socket * nsocket;
};
int main(void)
{
Server srv(1500);
srv.run();
}
I am a bit lost in a construct of libraries, which I have to tangle together. I need help to indtroduce some timers into this construct.
I have the following:
com.cpp which has main and includes com.hpp
com.hpp which includes a host.h and needed boost includes and defines a class comClient
host.c with included host.h
wrapper.cpp with included com.hpp and some needed boost includes
Now, my com.cpp is creating a comClient and uses it for asynch communication on the com-port. Using boost::asio::serial_port and boost::asio::io_service.
I need to work with some timers, in order to catch when a paket needed too long to transmit.
When creating an instance of comClient, the paket-timer should be initialised.
Using asynch_read_some in a private function of comClient, I call a private handler of comClient, then this handler calls a function of host.c, which calls to the wrapper.cpp a function to restart the timer.
This is the function to init the timer:
//wrapper.cpp
void IniPacketTimer(void *pCHandle){
boost::asio::io_service io;
boost::asio::deadline_timer t(io, boost::posix_time::milliseconds(25));
t.async_wait(&hostOnTimeout(pCHandle));
io.run();
}
This would be the command chain in short:
//comClient.cpp
main{
comClient cc();
}
//comClient.hpp
class comClient(boost::asio::io_service& io_service){
comClient(){
hostInit();
aread();
}
private:
aread( call aread_done)
areaddone(call hostNewData())
}
//host.c
hostInit(){
IniPacketTimer()
}
hostNewData(){
resetTimer
}
//wrapper.cpp
resetTimer(){
t.expires_from_now
}
Questions:
How can I provide an asynchronous timer, which does not affect the asynch read/write operations on my serial port, but triggers execution of a function when the deadline is hit?
Should I use the already existing io_service or is it ok, if I just create another?
Why do I get an error C2102 '&' expects L-Value for my line t.async_wait?
You problem is not clear and since you don't post real code it is quite hard to guess what your problem is.
Especially your threading is not clear but for asio very important.
Below is an example that will compile but not run. I hope it gives you an hint on how to proceed.
It will open a serial port and a timer. Whenever the timer expires it will start a new one. It is a stripped version of code I used some time ago so maybe it will help you.
#include <boost/asio.hpp>
#include <boost/asio/serial_port.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <vector>
class SerialCommunication
{
public:
SerialCommunication(boost::asio::io_service& io_service, const std::string& serialPort)
: m_io_service(io_service)
, m_serialPort(m_io_service)
, m_timeoutTimer(m_io_service, boost::posix_time::milliseconds(5))
{
configureSerialPort(serialPort);
}
void configureSerialPort(const std::string& serialPort)
{
if(m_serialPort.is_open())
{
m_serialPort.close();
m_timeoutTimer.cancel();
}
boost::system::error_code ec;
m_serialPort.open(serialPort, ec);
if(m_serialPort.is_open())
{
// start Timer
m_timeoutTimer.async_wait(boost::bind(&SerialCommunication::TimerExpired, this, _1));
header_sync();
}
}
void header_sync()
{
m_serialPort.async_read_some(boost::asio::buffer(&m_header.back(), 1),
boost::bind(&SerialCommunication::header_sync_complete, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void header_sync_complete(
const boost::system::error_code& error, size_t bytes_transferred)
{
// stripped
read_payload(&m_payload[0], 0);
}
void read_payload(uint8_t* buffer, uint8_t length)
{
m_serialPort.async_read_some(boost::asio::buffer(buffer, length),
boost::bind(&SerialCommunication::payload_read_complete, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void payload_read_complete(
const boost::system::error_code& error, size_t bytes_transferred)
{
// stripped
// timer cancel and reset
m_timeoutTimer.cancel();
m_timeoutTimer.expires_at(boost::posix_time::microsec_clock::local_time() +
boost::posix_time::milliseconds(5));
m_timeoutTimer.async_wait(boost::bind(&SerialCommunication::TimerExpired, this, _1));
memset(&m_header[0], 0, 3);
header_sync();
}
void TimerExpired(const boost::system::error_code& e)
{
m_timeoutTimer.expires_at(m_timeoutTimer.expires_at() + boost::posix_time::milliseconds(5));
m_timeoutTimer.async_wait(boost::bind(&SerialCommunication::TimerExpired, this, _1));
}
boost::asio::io_service& m_io_service;
boost::asio::deadline_timer m_timeoutTimer;
boost::asio::serial_port m_serialPort;
std::vector<uint8_t> m_header;
std::vector<uint8_t> m_payload;
};
int main()
{
boost::asio::io_service io_service;
SerialCommunication cc(io_service, "/dev/ttyS0");
io_service.run();
return 0;
}