I've got some trouble with the asio timer.
It is bind to a class method, and when I reload the timer (each time I'm waiting for data or ack), the call back method is called (according to the boost spec).
The problem is that I don't know how to differentiate the cancelation or the completion of the timer.
How should I do that ?
Thanks !
const int TIMER_DURATION = 5000; // ms
tftp_connection::tftp_connection (std::string id,
std::string file_name,
connection_type_enum connection_type,
tftp_server* server,
boost::asio::io_service& io_service)
: timer(io_service, boost::posix_time::milliseconds(TIMER_DURATION)) {
//...
// when sending a block and waiting for acknowledgement
timer.expires_from_now(boost::posix_time::milliseconds(TIMER_DURATION));
timer.async_wait(boost::bind(&tftp_connection::timeout_callback , this));
//...
void tftp_connection::timeout_callback() {
std::cout << "Time Out\n"; }
Looks like you want to check the error code that can be given to the callback if you use the right callback function type. Have a look at:
Boost async_wait example
Your callback should look somehow like this:
void tftp_connection::timeout_callback(const boost::system::error_code& e) {
if(e.value() == ERROR_TIMEOUT) // Or whatever error code you want to check for.
{
std::cout << "Time Out\n";
}
}
in addition, you need to change the bind to:
timer.async_wait(boost::bind(&tftp_connection::timeout_callback , this,boost::asio::placeholders::error));
The boost::asio::placeholders::error tells the bind to create a function which can use the error code as an argument.
Related
This works well:
class cStartSequence
{
void Tick()
{
// do something
}
void Wait()
{
myTimer->expires_from_now(
boost::posix_time::seconds( mySecs ) );
myTimer->async_wait(boost::bind(
&cStartSequence::Tick,
this
));
}
...
};
I want to be able to cancel the timer and have the handler do something different
void Tick( boost::system::error_code & ec )
{
if( ! ec )
// do something
else
// do something different
}
The question is how to modify the call to async_wait?
This does not compile
myTimer->async_wait(boost::bind(
&cStartSequence::Tick,
this,
boost::asio::placeholders::error
));
compiler complaint:
C:\Users\James\code\boost\v1_63\boost\bind\bind.hpp|319|error:
no match for call to
'(boost::_mfi::mf1<void, pinmed::wrs::cStartSequence, boost::system::error_code&>)
(pinmed::wrs::cStartSequence*&, const boost::system::error_code&)'
I tried some variations on the async_wait parameters, but no luck.
boost:asio v1.63, windows 10, code::blocks v16.01
Your Tick method takes a non-const reference. That's not ok (and doesn't satisfy the handler requirements). Use either
void Tick(boost::system::error_code const& ec);
Or maybe
void Tick(boost::system::error_code ec);
The first one is preferred by Asio author(s) for slightly obscurantist reasons (library-specific optimizations IIRC)
PS. For safe cancellation of deadline timers see also
cancel a deadline_timer, callback triggered anyway
Proper cleanup with a suspended coroutine
I am new with NS3. I am trying to create a custom application and currently have a difficulty on calling a Socket callback function using socket->SetRecvCallback. This problem occur while I use TcpSocketFactory, another socket such as UDP does not produce this issue.
On main
Ptr<Socket> ns3TcpSocket = Socket::CreateSocket(nodes.Get(0), TcpSocketFactory::GetTypeId());
Custom Tcp Application Class
this->socket->SetRecvCallback(MakeCallback(&CustomTcpApplication::RecvCallback, this));
this->socket->SetSendCallback(MakeCallback(&CustomTcpApplication::WriteUntilBufferFull, this));
My callback function
void CustomTcpApplication::RecvCallback(Ptr<Socket> socket)
{
std::cout << "On Receive Callback Function" << std::endl;
}
void CustomTcpApplication::WriteUntilBufferFull(Ptr<Socket> localSocket, uint32_t txSpace)
{
std::cout << "On Send Callback Function" << std::endl;
}
Also. I read from this answer to implements SetAcceptCallback, ns-3 wlan grid TCP not working while UDP is
this->socket->SetAcceptCallback(MakeNullCallback<bool, Ptr<Socket>, const Address &>(), MakeCallback(&CustomTcpApplication::Accept, this));
Callback Function
void CustomTcpApplication::Accept(Ptr<Socket> socket, const ns3::Address& from)
{
std::cout << "Connection accepted" << std::endl;
socket->SetRecvCallback(MakeCallback(&CustomTcpApplication::MainRecvCallback, this));
}
However, I still cannot log it on the function. Did I missing any step?
I got the same problem today. After tracing codes for hours, I found that there is no native support for TCP data receiving callback.
The tcp-socket-base.cc forks a new TcpSocketBase object for the following data transmission in TcpSocketBase::ProcessListen().The copy constructor of TcpSocketBase resets new socket's callback functions including m_receivedData. That's why data receiving callback doesn't work for TCP.
A simple workaround is to reserve the callback variable from original TcpSocketBase and make m_receivedDataTCP public in src/network/model/socket.h.
TcpSocketBase::TcpSocketBase (const TcpSocketBase& sock)
{
...
m_receivedDataTCP = sock.m_receivedDataTCP;
}
First of all, this is my first time using boost::asio as well as asynchronous programming. So, I am not at all well versed with either of the two.
Basically I want to interact with a robot via serial port. For this purpose, i am using boost::asio::serial_port. One of the operations I want to do is enable the robot to rotate for a few milliseconds, but asynchronously, so as not to have any lag in other processing being done. The internals of the class are as follows:
class Robot
{
boost::asio::io_service is;
boost::asio::serial_port port;
...
public:
Robot(const std::string &visionDeviceAddress, const std::string &motorControlDeviceAddress)
:visionDevice(visionDeviceAddress), port(is), motorControlDevice(motorControlDeviceAddress)
...
void completePendingMotions()
{
is.run();
}
}
I believe the following function should do the job:
void Robot::async_rotateLeftFor(unsigned long milliseconds)
{
boost::asio::deadline_timer t(is, boost::posix_time::milliseconds(milliseconds));
//the character 'a' initiates a non-stop anticlockwise rotation
char c='a';
boost::asio::write(port, boost::asio::buffer(&c,1));
t.async_wait([&](boost::system::error_code e)
{
//to stop the rotation, i need to pass the character 'q'
//this is done synchronously by function stop()
stop();
});
}
Finally, the call from main() looks like:
int main(void)
{
Robot r("0","COM6");
r.connect();
r.async_rotateLeftFor(2000);
r.completePendingMotions();
return 0;
}
What I get is simply that robot connection is established successfully, it starts rotating, but then it does not stop, as it should due to the completion handler. I am at a loss as to what could be the cause. Lack of documentation on asio doesn't help either. Any assistance is extremely appreciated.
The problem is that the deadline_timer object needs to stay alive until the handler triggers, otherwise the handler will be triggered instantly with an error when is.run() is called. The timer is being destroyed when the async_rotateLeftFor function exits.
What I do to keep the timer around, is wrap the timer object in a shared_ptr and pass it along to the handler object.
void Robot::async_rotateLeftFor(unsigned long milliseconds) {
auto t = std::make_shared<boost::asio::deadline_timer>(
is, boost::posix_time::milliseconds( milliseconds ));
//...
// (capture shared_ptr in lambda)
t->async_wait( [this,t](boost::system::error_code e )
{
stop();
}
);
I want to make an asynchronous call in C++ with timeout, meaning I want to achieve sth like that.
AsynchronousCall(function, time);
if(success)
//call finished succesfully
else
//function was not finished because of timeout
EDIT : Where function is a method that takes a lot of time and I want to interrupt it when it takes too much time.
I' ve been looking for how to achieve it and I thinki boost::asio::deadline_timer is way to go. I guess calling timer.async_wait(boost::bind(&A::fun, this, args)) is what I need, but I do not know how to find if the call was success or was aborted due to timeout.
EDIT: after the answer from ForEveR my code now looks like this.
boost::asio::io_service service;
boost::asio::deadline_timer timer(service);
timer.expires_from_now(boost::posix_time::seconds(5));
timer.async_wait(boost::bind(&A::CheckTimer, this, boost::asio::placeholders::error));
boost::thread bt(&A::AsynchronousMethod, this, timer, args); //asynchronous launch
void A::CheckTimer(const boost::system::error_code& error)
{
if (error != boost::asio::error::operation_aborted)
{
cout<<"ok"<<endl;
}
// timer is cancelled.
else
{
cout<<"error"<<endl;
}
}
I wanted to pass the timer by reference and cancel it in the end of asynchronous method, but I got an error that I cannot access private member declared in class ::boost::asio::basic_io_object.
Maybe using the deadline timer is not that good idea ? I would really appreciate any help. I am passing the timer to the function, because the method that calls the asynchronous method is asynchronous itself and thus I cannot have one timer for whole class or sth like that.
You should use boost::asio::placeholders::error
timer.async_wait(boost::bind(
&A::fun, this, boost::asio::placeholders::error));
A::fun(const boost::system::error_code& error)
{
// timeout, or some other shit happens
if (error != boost::asio::error::operation_aborted)
{
}
// timer is cancelled.
else
{
}
}
I am writing a DLL plugin for the Orbiter space simulator, which allows for UDP communication with an external system. I've chosen boost::asio for the task, as it allows me to abstract from the low-level stuff.
The "boundary conditions" are as follows:
I can create any threads or call any API functions from my DLL
I can modify the data inside of the simulation only inside the callback passed to my DLL (each frame), due to lack of other thread safety.
Hence, I chose the following architecture for the NetworkClient class I'm using for communications:
Upon construction, it initializes the UDP socket (boost::socket+boost::io_service) and starts a thread, which calls io_service.run()
Incoming messages are put asyncronously into a queue (thread-safe via CriticalSection)
The callback processing function can pull the messages from queue and process it
However, I have run into some strange exception upon running the implementation:
boost::exception_detail::clone_impl > at memory location 0x01ABFA00.
The exception arises in io_service.run() call.
Can anyone point me, please, am I missing something? The code listings for my classes are below.
NetworkClient declaration:
class NetworkClient {
public:
NetworkClient(udp::endpoint server_endpoint);
~NetworkClient();
void Send(shared_ptr<NetworkMessage> message);
inline bool HasMessages() {return incomingMessages.HasMessages();};
inline shared_ptr<NetworkMessage> GetQueuedMessage() {return incomingMessages.GetQueuedMessage();};
private:
// Network send/receive stuff
boost::asio::io_service io_service;
udp::socket socket;
udp::endpoint server_endpoint;
udp::endpoint remote_endpoint;
boost::array<char, NetworkBufferSize> recv_buffer;
// Queue for incoming messages
NetworkMessageQueue incomingMessages;
void start_receive();
void handle_receive(const boost::system::error_code& error, std::size_t bytes_transferred);
void handle_send(boost::shared_ptr<std::string> /*message*/, const boost::system::error_code& /*error*/, std::size_t /*bytes_transferred*/) {}
void run_service();
NetworkClient(NetworkClient&); // block default copy constructor
};
Methods implementation:
NetworkClient::NetworkClient(udp::endpoint server_endpoint) : socket(io_service, udp::endpoint(udp::v4(), 28465)) {
this->server_endpoint = server_endpoint;
boost::thread* th = new boost::thread(boost::bind(&NetworkClient::run_service,this));
start_receive();
}
void NetworkClient::start_receive()
{
socket.async_receive_from(boost::asio::buffer(recv_buffer), remote_endpoint,
boost::bind(&NetworkClient::handle_receive, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)
);
}
void NetworkClient::run_service()
{
this->io_service.run();
}
There's nothing wrong with your architecture that I can see. You should catch exceptions thrown from io_service::run(), that is likely the source of your problem.
void NetworkClient::run_service()
{
while(1) {
try {
this->io_service.run();
} catch( const std::exception& e ) {
std::cerr << e.what << std::endl;
}
}
}
You'll also want to fix whatever is throwing the exception.