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.
Related
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.
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 am currently trying to get the following application to work:
Await incoming client connection.
Start async. timer in another class.
While the timer runs repeatedly, do other stuff such as async_read and async_write.
Current source code:
#define BOOST_ASIO_ENABLE_HANDLER_TRACKING
#include <WinSock2.h>
#include <Mswsock.h>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include "TimerClass.hpp"
using namespace boost::asio;
using namespace boost::asio::ip;
TimerClass *timerClass;
void acceptHandler(const boost::system::error_code &errorCode, tcp::socket *socket) {
timerClass = new TimerClass(socket);
timerClass->startTimer();
while(true) {
// Do other suff such as async_write, ...
}
}
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, &socket));
ioService.run();
return EXIT_SUCCESS;
}
TimerClass.hpp:
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
using namespace boost::asio;
using namespace boost::posix_time;
class TimerClass {
public:
TimerClass(ip::tcp::socket *socket);
void startTimer();
void timerHandler(const boost::system::error_code& errorCode);
deadline_timer timer;
};
TimerClass.cpp:
#include <boost/bind.hpp>
#include "TimerClass.hpp"
TimerClass::TimerClass(ip::tcp::socket *socket) : timer(socket->get_io_service(), boost::posix_time::seconds(1)) {}
void TimerClass::startTimer() {
timer.async_wait(boost::bind(&TimerClass::timerHandler, this, boost::asio::placeholders::error));
}
void TimerClass::timerHandler(const boost::system::error_code& errorCode) {
timer.expires_at(timer.expires_at() + boost::posix_time::seconds(1));
timer.async_wait(boost::bind(&TimerClass::timerHandler, this, boost::asio::placeholders::error));
}
Handler Tracking Output:
#asio|1461070492.111630|0*1|socket#000000000021FBD0.async_accept
#asio|1461070498.527997|>1|ec=system:0
Questions:
Why won't it even call async_wait in startTimer? Debugging shows that startTimer gets called but I can't find anything in the Handler Tracking output. Why is that?
Am I correctly passing the socket to the TimerClass?
Without the infinite while(true) loop in the acceptHandler the acceptHandler returns but the application crashes before the io_service properly returns. How is that?
I compiled your code and it works for me (using boost version 1.54).
With your code I get the following output:
#asio|1461081908.437388|0*1|socket#003BFE2C.async_accept
#asio|1461081983.220840|>1|ec=system:0
#asio|1461081983.221817|1*2|deadline_timer#001C1318.async_wait
To make it run properly I had to remove the while(true) on your acceptHandler, obtaining the following output (added a std::cout inside the handler):
#asio|1461083707.104424|0*1|socket#0030FB6C.async_accept
#asio|1461083709.061824|>1|ec=system:0
#asio|1461083709.062803|1*2|deadline_timer#00641318.async_wait
#asio|1461083709.062803|<28158494073611763|
#asio|1461083710.064992|>2|ec=system:0
#asio|1461083710.064992|2|deadline_timer#00641318.cancel
#asio|1461083710.064992|2*3|deadline_timer#00641318.async_wait
TimerHandler executed...
#asio|1461083710.065971|<28169626628843099|
#asio|1461083711.065223|>3|ec=system:0
#asio|1461083711.065223|3|deadline_timer#00641318.cancel
#asio|1461083711.065223|3*4|deadline_timer#00641318.async_wait
TimerHandler executed...
I actually did this test using only the header TimerClass.hpp (defining the methods directly within it -I was lazy-) and it worked like a charm, the problem seems to be when using the .cpp file, that's why I asked if you were using include guards (not the issue though, already tested).
You should consider changing your design approach though, i.e. do not use blocking loops in you handlers, just call another asynchronous operation if needed (like async_read or async_write).
Take a look at this question and corresponding accepted answer for a nice server implementation idea. Or try to adapt some of the boost examples to your needs.
As per the segmentation fault you get when separating declaration from definition in the corresponding header and implementation files, you might want to check this other question.