Consider the following MWE class foo, which has a send member function that allows sending strings to the loopback address on port 1337 over UDP:
Header file: foo.h
#include <boost/asio.hpp>
class foo
{
public:
foo(); // Constructor.
void send(std::string const& message);
private:
boost::asio::io_service ios;
boost::asio::ip::udp::socket sock;
boost::asio::ip::udp::endpoint endp;
};
Implementation file: foo.cc
#include "foo.h"
foo::foo() : sock{ios}, endp{boost::asio::ip::address::from_string("127.0.0.1"), 1337}
{
sock.connect(endp);
}
void foo::send(std::string const& message)
{
sock.send(boost::asio::buffer(message));
}
Now I want to use the foo class to send the string Hello, World!\n to myself. So in the main function I instatiate a foo object and then I call foo.send() 5 times (waiting 1 second between bursts) using a for loop.
Main function:
#include "foo.h"
#include <iostream>
#include <chrono>
#include <thread>
int main(int argc, char* argv[])
{
foo foo;
for(int i = 0; i<5; i++)
{
foo.send("Hello, World!\n");
std::cout << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
std::cout << "Done" << std::endl;
return 0;
}
The code compiles successfully. However, at runtime the program crashes and throws the following error:
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >'
what(): send: Connection refused
Aborted (`core' dumped)
The Connection refused error message is very confusing since UDP is connectionless by design. So the program should send 5 UDP messages whether the recipient is listening or not.
What am I doing wrong here?
UDP is connectionless by design. So the program should send 5 UDP messages whether the recipient is listening or not.
The first does not imply the second. With UDP, error reporting is not guaranteed, which is quite different from a guarantee of no error reporting. Typically, a packet arriving on a port where there is no listener will trigger an ICMP Port Unreachable message back to the sender, and most implementations of the Sockets API will report that to the application on the next attempt to transmit to the same destination. With loopback, detecting an error is even easier for the network stack.
Related
There are similar questions, although none of them quite capture what I'm doing. I haven't setup multiple functions, just a single while loop in my main() function.
I was following a tutorial and have managed to establish a tcp websocket connection for my c++ application, that can accept multiple clients. However if one of those are closed then the application closes and throws this error:
terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>'
terminate called recursively
what(): The WebSocket stream was gracefully closed at both endpoints
Aborted
I'm not sure how to reconnect to the ip, or to have the system constantly listening.
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <iostream>
#include <stdio.h>
#include <string>
#include <thread>
using tcp = boost::asio::ip::tcp;
int main() {
auto const address = boost::asio::ip::make_address("127.0.0.1");
auto const port = static_cast<unsigned short>(std::atoi("8080"));
boost::asio::io_context ioc { 1 };
tcp::acceptor acceptor { ioc, { address, port } };
while(1)
{
tcp::socket socket { ioc };
acceptor.accept(socket);
std::cout << "socket accepted" << std::endl;
}
}
I'd like to have the application stay running and attempt to reconnect if the client gets disconnected. At the moment the application just shuts down and has to be restarted.
I am using Boost ASIO to connect to an Arduino Nano with an Ethernet Shield over ethernet. This is the Arduino setup:
#include <EtherCard.h>
ether.staticSetup("10.0.0.4", "10.0.0.1");
ether.udpServerListenOnPort(&callback_function, 1337);
This is my C++ code that connects to it:
Header
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
boost::system::error_code error_1;
boost::shared_ptr <boost::asio::io_service> io_service_1;
boost::shared_ptr <boost::asio::ip::udp::socket> socket_1;
Initialize
// 1. reset io service
io_service_1.reset();
io_service_1 = boost::make_shared <boost::asio::io_service> ();
// 2. create endpoint
boost::asio::ip::udp::endpoint remote_endpoint(
boost::asio::ip::address::from_string("10.0.0.4"),
1337
);
// 3. reset socket
socket_1.reset(new boost::asio::ip::udp::socket(*io_service_1));
// 4. connect socket
socket_1->async_connect(remote_endpoint, socket_1_connect_callback);
// 5. start io_service_1 run thread after giving it work
boost::thread t(boost::bind(&boost::asio::io_service::run, *&io_service_1));
Callback
function socket_1_connect_callback (const boost::system::error_code& error_1)
{
// 1. check for errors
if (error_1)
{
std::cerr << "error_1.message() >> " << error_1.message().c_str() << std::endl;
return;
}
else
{
INFO << "connection succeeded";
}
return;
}
The socket connects every time, even if the Arduino is not powered. Why does it not fail to connect?
By definition, UDP is connection-less protocol. 'Connecting' a UDP socket is simply a convenience operation, which allows you to than send datagrams on that socket without specifying recipient - it uses the one you gave to a connect call.
But other than that, it does nothing. There is really no way to check if someone is listening on the other side of UDP, unless you implement a request/response scheme yourself.
The fact that you are using Boost.Asio adds nothing to this basic fact.
I am new to boost library so my question is probably not the first one in this forum but I couldn't find a similar case.
Currently I am trying to implement a simple HTTP client which calls REST API.
I inspired my self from the example given on the boost's web site: HTTP client with boost
The example is clear enough for a newbie like me but I would like to make the client to be able to execute multiple requests one by one because the example is a one shot: the client sends a GET request to the server, than it receives the response and after that the io_service.run() returns.
So my question is what I need to use from boost in way to make my client always waiting for new requests to send.
I read something about a io_service::work but I am not sure if it is the right way.
Does anybody have done something similar to the client I am trying to make?
Thanks in advance !
Best regard,
Anton
I do not know if asynchronous version is a must, so I would recommend you to give a try to synchronous version, since it's easier to follow the execution path:
/*
Compile with
g++ -lpthread -lboost_system -lboost_thread -ohttp http.cpp
*/
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>
using std::cout;
using std::endl;
using std::vector;
using std::string;
using boost::asio::ip::tcp;
using boost::asio::ip::address;
using boost::asio::io_service;
using boost::asio::buffer;
using boost::system::error_code;
using boost::system::system_error;
int main()
{
try
{
unsigned int PORT = 80;
const string HOST = "216.58.214.238";
const string HTTP_REQUEST = "GET /index.html HTTP/1.0\n\n";
io_service ios;
tcp::endpoint ip_port(address::from_string(HOST), PORT);
while (true)
{
tcp::socket client(ios);
client.connect(ip_port);
const int BUFLEN = 1024;
vector<char> buf(BUFLEN);
client.send(buffer(HTTP_REQUEST, HTTP_REQUEST.size()));
error_code error;
int len = client.receive(buffer(buf, BUFLEN), 0, error);
cout << "main(): buf.data()=";
cout.write(buf.data(), len);
cout << endl;
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
}
}
catch (system_error& exc)
{
cout << "main(): exc.what()=" << exc.what() << endl;
}
return EXIT_SUCCESS;
}
The socket is created each time within the loop because Google (it's IP address is used) closes the connection after each request (status 302 is returned).
In some other cases, HTTP connection does not have to be closed by a server, so socket can be reused.
I am currently trying to create a server application using Boost::Asio that does two simple things:
Accept a client's incoming connection
Once the client has been accepted, start a boost::asio::deadline_timer which repeats itself
The following code shows my current attempt:
#define BOOST_ASIO_ENABLE_HANDLER_TRACKING
#include <WinSock2.h>
#include <Mswsock.h>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
using namespace boost::asio;
using namespace boost::asio::ip;
void timerHandler(const boost::system::error_code& errorCode, deadline_timer* timer) {
timer->expires_at(timer->expires_at() + boost::posix_time::seconds(1));
timer->async_wait(boost::bind(timerHandler, _1, timer));
}
void acceptHandler(const boost::system::error_code &errorCode, io_service *ioService) {
deadline_timer timer(*ioService, boost::posix_time::seconds(1));
timer.async_wait(boost::bind(timerHandler, _1, &timer));
}
int main(int argc, char** argv) {
io_service ioService;
tcp::socket socket(ioService);
tcp::acceptor acceptor{ ioService, tcp::endpoint{ tcp::v4(), 12345 } };
acceptor.listen();
acceptor.async_accept(socket, boost::bind(acceptHandler, _1, &ioService));
ioService.run();
return EXIT_SUCCESS;
}
Problem:
The timer somehow does not work as expected in the acceptHandler. Somehow it gets cancelled twice, triggers an error on top of that and eventually crashes the entire application.
Handler Tracking Output:
#asio|1460922050.075890|0*1|socket#000000000015FAD0.async_accept
#asio|1460922051.153952|>1|ec=system:0
#asio|1460922051.153952|1*2|deadline_timer#000000000015F608.async_wait
#asio|1460922051.153952|1|deadline_timer#000000000015F608.cancel
#asio|1460922051.153952|<1|
#asio|1460922051.153952|>2|ec=system:995
#asio|1460922051.153952|2|deadline_timer#000000000015F608.cancel
Questions:
What causes the acceptHandler to cancel the deadline_timer in line 4 of the Handler Tracking output?
What casues the error 995 in line 6 of the Handler Tracking output? Error message is: The I/O operation has been aborted because of either a thread exit or an application request
What causes the timerHandler to cancel the deadline_timer in line 7 of the Handler Tracking output?
timer is allocated on the stack in the acceptHandler and is therefore not valid by the time timerHandler is called. You need to allocate the timer dynamically.
Also, you should check for error codes in both handlers. This is especially important when you want to end the program and cancel the timer.
I'm trying to asynchronously resolve a ftp host using Boost.Asio.
Here's what I've tried so far:
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
using boost::asio::ip::tcp;
class FtpSession {
public:
void Connect(std::string& host) {
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(host, "ftp");
resolver.async_resolve(query,
boost::bind(&FtpSession::OnResolve, this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator));
}
private:
void OnResolve(const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator) {
if (!err)
{
std::cout << "resolved!";
}
else
{
std::cout << "error.";
}
}
};
int main() {
FtpSession session;
std::string host("ftp.remotesensing.org");
session.Connect(host);
return 0;
}
But for some reason, when I execute it, it just doesn't print anything:
alon#alon-GA-73PVM-S2H:~/Desktop$ g++ -o test -lboost_system test.cc
alon#alon-GA-73PVM-S2H:~/Desktop$ ./test
alon#alon-GA-73PVM-S2H:~/Desktop$
No errors or warnings at the compilation though.
How can I fix this?
You need to call io_service.run() to actually do the work methinks. Think of the async_resolve as a request in a request queue - you need something (the io_service) to process the requests in the queue, and to do that, you actually need to run() it! In this case, it will see one request, execute it, call the handler and then exit.
Your io_service and ip::tcp::resolver object are going out of scope. Move both of them into members of the FtpSession class, then invoke io_service::run inside of main after session.Connect(host) to start the event loop.
I answered a similar question a few days ago that may help you as well.