Make boost http client - c++

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.

Related

How to properly reconnect to a tcp socket using Boost

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.

Communicating with the COM PORT in C++

I have to write a program sending messages to the UART converter connected on the COM PORT in C++. I'm actually stuck from the very beggining. I haven't ever dome anything like that and I didn't manage to find any examples.
Could anyone help me out?
Appreciate any help ;)
Boost has a nice library and examples for it: https://www.boost.org/doc/libs/1_65_0/doc/html/boost_asio/overview/serial_ports.html
An example for the usage of the boost library was posted here: Clear input data from serial port in boost::asio
#include <boost/asio.hpp>
#include <vector>
#include <iostream>
using namespace std;
using namespace boost::asio;
int main()
{
io_service io_service;
serial_port port(io_service, "/dev/ttyACM0");
port.set_option(serial_port_base::baud_rate(9600));
vector<char> buf(1);
read(port, buffer(buf));
cout << (int) buf[0] << endl;
return 0;
}
same can be done with write:
std::string s;
write(port,buffer(s.c_str(),s.size()));

UDP Connect Always Succeeds

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.

Boost::Asio - Passing socket to second class

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.

C++ REST SDK Casablanca Client.request

I want to write a little c++ program that sends a request to a server an get some data. I found the C++ Rest-SDK and decided to use it. I searched on different websites for code-examples but many of them doesn't work an shows syntax errors. What i got now is that code but the client.request method is skipped. The program never jumps in. Hope someone can realise the problem and maybe explain what i have to change.
#include <Windows.h>
#include <iostream>
#include <sstream>
#include <string>
#include "cpprest/containerstream.h"
#include "cpprest/filestream.h"
#include "cpprest/http_client.h"
#include "cpprest/json.h"
#include "cpprest/producerconsumerstream.h"
#include "cpprest/http_client.h"
#include <string.h>
#include <conio.h>
using namespace std;
using namespace web;
using namespace web::json;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
using namespace utility::conversions;
int main() {
http_client client(L"http://httpbin.org/ip");
client.request(methods::GET).then([](http_response response)
{
if(response.status_code() == status_codes::OK)
{
auto body = response.extract_string().get();
std::wcout << body;
getch();
}
});
return 0;
}
It is possible that the main thread is terminated before the "request" task completed, so you cannot see any console outputs. I suggest you to call the task "wait()" function after ".then", like in the answer on their site
Your program runs off the end of main and terminates. You need to add wait after the then call:
client.request(methods::GET).then([](http_response response)
{
// ...
}).wait();
this code is working :
// ConsoleApplication1.cpp : Defines the entry point for the console application.
#include "StdAfx.h"
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
using namespace utility; // Common utilities like string conversions
using namespace web; // Common features like URIs.
using namespace web::http; // Common HTTP functionality
using namespace web::http::client; // HTTP client features
using namespace concurrency::streams; // Asynchronous streams
int main(int argc, char* argv[])
{
// Make the request and asynchronously process the response.
http_client client(L"http://localhost:8082/TPJAXRS/Test/test");
client.request(methods::GET).then([](http_response response){
if(response.status_code() == status_codes::OK){
auto body = response.extract_string().get();
std::wcout << body<< std::endl;
}});
std::cout << "Hello world!" << std::endl;
system("PAUSE");
return 0;
}
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
#include <cpprest/http_listener.h> // HTTP server
#include <cpprest/json.h> // JSON library
#include <cpprest/uri.h> // URI library
#include <cpprest/ws_client.h> // WebSocket client
#include <cpprest/containerstream.h> // Async streams backed by STL containers
#include <cpprest/interopstream.h> // Bridges for integrating Async streams with STL and WinRT streams
#include <cpprest/rawptrstream.h> // Async streams backed by raw pointer to memory
#include <cpprest/producerconsumerstream.h> // Async streams for producer consumer scenarios
using namespace utility; // Common utilities like string conversions
using namespace web; // Common features like URIs.
using namespace web::http; // Common HTTP functionality
using namespace web::http::client; // HTTP client features
using namespace concurrency::streams; // Asynchronous streams
using namespace web::http::experimental::listener; // HTTP server
using namespace web::experimental::web_sockets::client; // WebSockets client
using namespace web::json; // JSON library
int main(int argc, char* argv[])
{
auto fileStream = std::make_shared<ostream>();
// Open stream to output file.
pplx::task<void> requestTask = fstream::open_ostream(U("results.html")).then([=](ostream outFile)
{
*fileStream = outFile;
// Create http_client to send the request.
http_client client(U("http://www.bing.com/"));
// Build request URI and start the request.
uri_builder builder(U("/search"));
builder.append_query(U("q"), U("cpprestsdk github"));
return client.request(methods::GET, builder.to_string());
})
// Handle response headers arriving.
.then([=](http_response response)
{
printf("Received response status code:%u\n", response.status_code());
// Write response body into the file.
return response.body().read_to_end(fileStream->streambuf());
})
// Close the file stream.
.then([=](size_t)
{
return fileStream->close();
});
// Wait for all the outstanding I/O to complete and handle any exceptions
try
{
requestTask.wait();
}
catch (const std::exception &e)
{
printf("Error exception:%s\n", e.what());
}
return 0;
}
This is for setting in HTTP request
link for HTTP tutorial for further information go through this tutorial