How to fix Boost::Asio Client Http request error? - c++

I'm trying to lean Boost::Asio networking library for C++ by watching this video but I stuck at making request using threads asynchronously.
The code :
#include "stdafx.h"
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/ts/buffer.hpp>
#include <boost/asio/ts/internet.hpp>
#include <boost/system/error_code.hpp>
std::vector<char> vBuffrer(20 * 1024);
void GrabSomeData(boost::asio::ip::tcp::socket& socket) {
socket.async_read_some(boost::asio::buffer(vBuffrer.data(), vBuffrer.size()),
[&](std::error_code ec, std::size_t length)
//boost::system::error_code ec
{
if (!ec)
{
std::cout << "\n\nRead" << length << "bytes\n\n";
for (int i = 0; i < length; i++)
std::cout << vBuffrer[i];
GrabSomeData(socket);
}
});
}
int main()
{
boost::system::error_code ec;
boost::asio::io_context context;
boost::asio::io_context::work idleWork(context);
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::make_address("13.107.21.200",ec),80);
boost::asio::ip::tcp::socket socket(context);
std::thread thrContext = std::thread([&]() {context.run(); });
std::cout << "Starting " << std::endl;
socket.connect(endpoint,ec);
if (!ec)
{
std::cout << "Connected ! " << std::endl;
}
else {
std::cout << "Fail to connect ! " << ec.message() << std::endl;
}
if (socket.is_open()) {
GrabSomeData(socket);
std::string sRequest =
"GET /index.html HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Connection: close\r\n\r\n";
socket.write_some(boost::asio::buffer(sRequest.data(), sRequest.size()), ec);
using namespace std::chrono_literals;
std::this_thread::sleep_for(2800ms);
//std::this_thread::sleep_for(1ms);
context.stop();
if (thrContext.joinable()) thrContext.join();
}
system("pause");
return 0;
}
Microsoft Visual studio give me this :
Error C2752 'asio_prefer_fn::call_traits<boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context &>,boost::asio::execution::detail::blocking::never_t<0>,boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0>>,boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0>>,boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0>>,boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0>>,boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0>>> &,void (const boost::asio::execution::detail::blocking::possibly_t<0> &,boost::asio::execution::allocator_t<std::allocator<void>>),void>': more than one partial specialization matches the template argument list boostasiotest c:\boost\boost_1_75_0\boost\asio\detail\handler_work.hpp 353
Error C2893 Failed to specialize function template 'enable_if<asio_prefer_fn::call_traits<T,void(P0,P1,PN...),void>::overload==,call_traits<T,void(P0,P1,PN...),void>::result_type>::type asio_prefer_fn::impl::operator ()(T &&,P0 &&,P1 &&,PN &&...) noexcept(<expr>) const' boostasiotest c:\boost\boost_1_75_0\boost\asio\detail\handler_work.hpp 353
Everything worked fine till I added GrabSomeData function and I have absolutely no idea how to fix it , any help would be appreciated.
PS : there is an example on the Boost website on this subject, but it is object oriented and all the pointers are referring to the class and I (think) it can't help.

Like the commenter, I cannot repro your message: it just compiles,
MSVC 19, /std:c++14, Boost 1.75.0: compiler explorer
Now, I do see other issues:
write_some may not write all the data - you will want to ensure a composed-write operation
a race condition: since you're doing GrabSomeData on a thread, you
need to synchronize access to the tcp::socket and buffer (the
shared resources).
io_context itself is thread-safe.
In this case, it's really easy to avoid, since you don't need to
start the async operation until after you sent the request:
write(socket, boost::asio::buffer(sRequest));
GrabSomeData(socket);
async_read_some has a similar problem as the write side. You will want a composed read operation that reads the expected output so read_until(socket, buf, "\r\n\r\n") and then read how much content is expected based on Content-Length header, Connection: Close and others (think chunked encoding).
You currently have no good way to store and access the response. It would be a lot easier to use a streambuf, a single composed read.
If you want to be really solid, use Beast to receive a HTTP/1.1 response (which can even be chunked) and not worry about when it's complete (the library does it for you):
auto GrabSomeData(tcp::socket& socket) {
http::response<http::string_body> res;
auto buf = boost::asio::dynamic_buffer(vBuffer);
http::read(socket, buf, res);
return res;
}
Oh, and don't do it on a thread (why was that anyways? it literally just introduced undefined behavior for no gain):
Simplified Code
Live On Coliru
Compiles on MSVC: Godbolt
#include <boost/asio.hpp>
#include <boost/beast/http.hpp>
#include <iostream>
#include <iomanip>
using boost::asio::ip::tcp;
std::vector<char> vBuffer; // TODO FIXME global variable
auto GrabSomeData(tcp::socket& socket) {
namespace http = boost::beast::http;
http::response<http::string_body> res;
auto buf = boost::asio::dynamic_buffer(vBuffer);
http::read(socket, buf, res);
return res;
}
int main() try {
boost::asio::io_context context;
std::cout << "Starting " << std::endl;
tcp::endpoint endpoint(boost::asio::ip::make_address("13.107.21.200"), 80);
tcp::socket socket(context);
socket.connect(endpoint);
std::cout << "Connected" << std::endl;
std::string const sRequest = "GET /index.html HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Connection: close\r\n"
"\r\n";
write(socket, boost::asio::buffer(sRequest));
auto response = GrabSomeData(socket);
std::cout << "Response body length: " << response.body().size() << std::endl;
std::cout << "Response headers: " << response.base() << std::endl;
std::cout << "Response body: " << std::quoted(response.body()) << std::endl;
context.run(); // run_for(10s) e.g.
} catch (boost::system::system_error const& se) {
std::cerr << "Error: " << se.code().message() << std::endl;
}
This sample printed:
Starting
Connected
Response body length: 194
Response headers: HTTP/1.1 400 Bad Request
Transfer-Encoding: chunked
X-MSEdge-Ref: 0BstXYAAAAACeQ2y+botzQISiBe2U3iGCQ0hHRURHRTE0MDgARWRnZQ==
Date: Sun, 21 Mar 2021 22:39:02 GMT
Connection: close
Response body: "<h2>Our services aren't available right now</h2><p>We're working to restore all services as soon as possible. Please check back soon.</p>0BstXYAAAAACeQ2y+botzQISiBe2U3iGCQ0hHRURHRTE0MDgARWRnZQ=="
NOTE It does indeed use chunked encoding, which you didn't seem to be anticipating.

Thanks #sehe for the answer and recommendations, it took so long but I've upgrade to New Windows10 and Visual Studio 2019, and Boost 1_76 and the problem solved!
Those errors were totally irrelevant to the code!

Related

Unable to process boost asio:- async read buffer's callback asynchronously

I'm using boost::asio::async_read() method to asynchronously get response from server which take 10 second to process request. I am able to read response successfully. but I am attaching callback to this function to process received response which take 10 seconds. I am unable to find how i can process that callback asynchronously.
void read_response(std::string data)
{
cout << data << endl;
sleep(10);
// if you think sleep works differently if i send another rest api request from here still this function blocks the processing
}
boost::asio::async_read(socket, boost::asio::buffer(buffer), [&](const boost::system::error_code&
error,
std::size_t bytes_transferred) {
io_context.post([&]() {
read_response(buffer.data());
//read_response is not processing asynchronously
});
});
I tried posting function to io_context, i tried using
std::async(std::launch::deferred, read_handler,error,bytes_transferred,buffer.data()).wait() ;
I am new to asyn programming and c++ programming.
Indeed, don't do blocking operations on the IO service. Or grow the thread pool to accomodate for the maximum number of concurrent tasks that must be supported.
In all circumstances, copy the message into your read handler, instead of passing the buffer directly (as you did) as that invites race conditions/stale references.
Let's demonstrate using httpbin.org/delay:
Live On Coliru
#include <boost/asio.hpp>
#include <iomanip>
#include <iostream>
namespace asio = boost::asio;
using asio::ip::tcp;
using namespace std::chrono_literals;
std::string const request = "GET /delay/10 HTTP/1.1\r\nHost: httpbin.org\r\n\r\n";
void read_response(std::string data) {
std::cout << "Asynchronously received response: " << quoted(data) << std::endl;
sleep(10);
}
int main() {
asio::io_context ioc(1);
asio::thread_pool work(10); // support 10 tasks along-side async IO
tcp::socket conn(ioc);
connect(conn, tcp::resolver(ioc).resolve("httpbin.org", "80"));
write(conn, asio::buffer(request));
std::string buf;
async_read_until( //
conn, asio::dynamic_buffer(buf), "\r\n\r\n",
[&work, &buf](boost::system::error_code ec, size_t n) {
std::cout << "\n*** Completion " << ec.message() << ", " << n << std::endl;
post(work, [msg = buf.substr(0, n)] {
// NOTE: lambda owns msg, not a reference to `buf`
read_response(std::move(msg));
});
});
std::thread([&ioc] {
ioc.run();
std::cout << "\n*** IO complete" << std::endl;
}).detach();
for (int i = 0; i < 15; ++i) {
std::cout << "." << std::flush;
std::this_thread::sleep_for(1s);
}
work.join();
std::cout << "\n*** Work Done" << std::endl;
}
This shows work continuing, "asynchronously" (relative to IO) well after ioc completes:

How to find if the 'target' for websocket::stream::async_handshake() is not found?

For HTTP calls, you can do:
http::async_read(m_stream, m_buffer, m_res, beast::bind_front_handler(&RestSession::on_read, shared_from_this()));
// ... then
void on_read(beast::error_code ec, std::size_t /*bytes_transferred*/)
{
if (ec)
return ; // handle error_code
if (m_res.result() == http::status::not_found)
return ; // handle target not found
}
but I can't see how to do the equivalent for a websocket stream. If the stream target does not exist the on_read() is never called.
I tried getting the next stream from the websocket stream (m_websocketStream), but the lambda is never called, presumably because the websocket layer has already swallowed the HTTP response:
void on_handshake(beast::error_code ec)
{
if(ec)
return fail(ec, "handshake", m_callback);
http::async_read(m_websockStream.next_layer(), m_buffer, m_httpRes, [this, self = shared_from_this()](beast::error_code ec, std::size_t)
{
if (m_httpResponse.result() == http::status::not_found)
return fail("path not found", m_callback);
else
m_ws.async_read(m_buffer, beast::bind_front_handler(&WsSession::on_read, self->shared_from_this()));
});
}
Is this possible?
but I can't see how to do the equivalent for a websocket stream. If the stream target does not exist the on_read() is never called.
That makes a lot of sense, since the read won't ever be started. Instead the handshake fails, and the ec in fail(ec, "handshake", m_callback); will reflect that.
Getting HTTP response details
This is also supported: docs:
When a client receives an HTTP Upgrade response from the server indicating a successful upgrade, the caller may wish to perform additional validation on the received HTTP response message.
You can pass an additional response object to recive the details:
beast::error_code ec;
http::response<http::string_body> res;
s.handshake(res, host + ":" + port, path, ec);
std::cout << "handshake: " << ec.message() << " (" << ec.category().name()
<< ":" << ec.value() << ")" << std::endl;
std::cout << "Declined: " << std::boolalpha
<< (ec == websocket::error::upgrade_declined) << '\n';
std::cout << "Full response:" << res;
here's a very simple test:
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <boost/beast/websocket.hpp>
#include <istream>
#include "zlib.h"
#include <iostream>
namespace net = boost::asio;
namespace beast = boost::beast;
namespace http = beast::http;
namespace websocket = beast::websocket;
using tcp = net::ip::tcp;
using socket_t = websocket::stream<tcp::socket>;
int main() {
std::string host = "www.example.com";
auto const port = "80";
auto const path = "/this/path/will/not/exist";
net::io_context ioc;
tcp::resolver resolver{ioc};
socket_t s{ioc};
net::connect(beast::get_lowest_layer(s), resolver.resolve(host, port));
beast::error_code ec;
http::response<http::string_body> res;
s.handshake(res, host + ":" + port, path, ec);
std::cout << "handshake: " << ec.message() << " (" << ec.category().name()
<< ":" << ec.value() << ")" << std::endl;
std::cout << "Declined: " << std::boolalpha
<< (ec == websocket::error::upgrade_declined) << '\n';
std::cout << "Full response:" << res;
}
Prints
handshake: The WebSocket handshake was declined by the remote peer (boost.beast.websocket:20)
Declined: true
Full response:HTTP/1.1 200 OK
I suppose most servers will simply decline, not send HTTP Not Found.

Use Futures with Boost Thread Pool

I'm implementing a TCP client which read and send files and strings and I'm using Boost as my main library. I'd like to continue reading or sending files while I keep sending strings, which in these case are the commands to send to the server. For this purpose I thought about using a Thread Pool in order to not overload the client. My question is, can I use futures to use callbacks when on of the thread in the pool ends? In case I can't, is there any other solution?
I was doing something like this, where pool_ is a boost:asio:thread_pool
void send_file(std::string const& file_path){
boost::asio::post(pool_, [this, &file_path] {
handle_send_file(file_path);
});
// DO SOMETHING WHEN handle_send_file ENDS
}
void handle_send_file(std::string const& file_path) {
boost::array<char, 1024> buf{};
boost::system::error_code error;
std::ifstream source_file(file_path, std::ios_base::binary | std::ios_base::ate);
if(!source_file) {
std::cout << "[ERROR] Failed to open " << file_path << std::endl;
//TODO gestire errore
}
size_t file_size = source_file.tellg();
source_file.seekg(0);
std::string file_size_readable = file_size_to_readable(file_size);
// First send file name and file size in bytes to server
boost::asio::streambuf request;
std::ostream request_stream(&request);
request_stream << file_path << "\n"
<< file_size << "\n\n"; // Consider sending readable version, does it change anything?
// Send the request
boost::asio::write(*socket_, request, error);
if(error){
std::cout << "[ERROR] Send request error:" << error << std::endl;
//TODO lanciare un'eccezione? Qua dovrò controllare se il server funziona o no
}
if(DEBUG) {
std::cout << "[DEBUG] " << file_path << " size is: " << file_size_readable << std::endl;
std::cout << "[DEBUG] Start sending file content" << std::endl;
}
long bytes_sent = 0;
float percent = 0;
print_percentage(percent);
while(!source_file.eof()) {
source_file.read(buf.c_array(), (std::streamsize)buf.size());
int bytes_read_from_file = source_file.gcount(); //int is fine because i read at most buf's size, 1024 in this case
if(bytes_read_from_file<=0) {
std::cout << "[ERROR] Read file error" << std::endl;
break;
//TODO gestire questo errore
}
percent = std::ceil((100.0 * bytes_sent) / file_size);
print_percentage(percent);
boost::asio::write(*socket_, boost::asio::buffer(buf.c_array(), source_file.gcount()),
boost::asio::transfer_all(), error);
if(error) {
std::cout << "[ERROR] Send file error:" << error << std::endl;
//TODO lanciare un'eccezione?
}
bytes_sent += bytes_read_from_file;
}
std::cout << "\n" << "[INFO] File " << file_path << " sent successfully!" << std::endl;
}
The operations posted to the pool end without the threads ending. That's the whole purpose of pooling the threads.
void send_file(std::string const& file_path){
post(pool_, [this, &file_path] {
handle_send_file(file_path);
});
// DO SOMETHING WHEN handle_send_file ENDS
}
This has several issues. The largest one is that you should not capture file_path by reference, as the argument is soon out of scope, and the handle_send_file call will run at an unspecified time in another thread. That's a race condition and dangling reference. Undefined Behaviour results.
Then the
// DO SOMETHING WHEN handle_send_file ENDS
is on a line which has no sequence relation with handle_send_file. In fact, it will probably run before that operation ever has a chance to start.
Simplifying
Here's a simplified version:
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <fstream>
#include <iostream>
namespace asio = boost::asio;
using asio::ip::tcp;
static asio::thread_pool pool_;
struct X {
std::unique_ptr<tcp::socket> socket_;
explicit X(unsigned short port) : socket_(new tcp::socket{ pool_ }) {
socket_->connect({ {}, port });
}
asio::thread_pool pool_;
std::unique_ptr<tcp::socket> socket_{ new tcp::socket{ pool_ } };
void send_file(std::string file_path) {
post(pool_, [=, this] {
send_file_implementation(file_path);
// DO SOMETHING WHEN send_file_implementation ENDS
});
}
// throws system_error exception
void send_file_implementation(std::string file_path) {
std::ifstream source_file(file_path,
std::ios_base::binary | std::ios_base::ate);
size_t file_size = source_file.tellg();
source_file.seekg(0);
write(*socket_,
asio::buffer(file_path + "\n" + std::to_string(file_size) + "\n\n"));
boost::array<char, 1024> buf{};
while (source_file.read(buf.c_array(), buf.size()) ||
source_file.gcount() > 0)
{
int n = source_file.gcount();
if (n <= 0) {
using namespace boost::system;
throw system_error(errc::io_error, system_category());
}
write(*socket_, asio::buffer(buf), asio::transfer_exactly(n));
}
}
};
Now, you can indeed run several of these operations in parallel (assuming several instances of X, so you have separate socket_ connections).
To do something at the end, just put code where I moved the comment:
// DO SOMETHING WHEN send_file_implementation ENDS
If you don't know what to do there and you wish to make a future ready at that point, you can:
std::future<void> send_file(std::string file_path) {
std::packaged_task<void()> task([=, this] {
send_file_implementation(file_path);
});
return post(pool_, std::move(task));
}
This overload of post magically¹ returns the future from the packaged task. That packaged task will set the internal promise with either the (void) return value or the exception thrown.
See it in action: Live On Coliru
int main() {
// send two files simultaneously to different connections
X clientA(6868);
X clientB(6969);
std::future<void> futures[] = {
clientA.send_file("main.cpp"),
clientB.send_file("main.cpp"),
};
for (auto& fut : futures) try {
fut.get();
std::cout << "Everything completed without error\n";
} catch(std::exception const& e) {
std::cout << "Error occurred: " << e.what() << "\n";
};
pool_.join();
}
I tested this while running two netcats to listen on 6868/6969:
nc -l -p 6868 | head& nc -l -p 6969 | md5sum&
./a.out
wait
The server prints:
Everything completed without error
Everything completed without error
The netcats print their filtered output:
main.cpp
1907
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <fstream>
#include <iostream>
#include <future>
namespace asio = boost::asio;
using asio::ip::tcp;
7ecb71992bcbc22bda44d78ad3e2a5ef -
¹ not magic: see https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/reference/async_result.html

HTTP Get Request using Boost Asio C++

I'm new to C++ and Boost Asio, I wanted to use Boost Asio to create a simple HTTP Get request to a website having oAthn2 (bearer token) in my program but it doesn't work and I don't know why, I have tried to libCurl and separate Http request in Clion and they worked well without any problems.
#include "netCommon/net_Common.h"
#include <chrono>
#include <thread>
using namespace boost;
typedef asio::ip::tcp ip;
int main() {
boost::system::error_code ec;
asio::io_service ios;
//The website
std::string host_name = "api-fxpractice.oanda.com";
std::string port = "443";
//resolve DNS
ip::resolver resolver_dns(ios);
ip::resolver::query query_dns(host_name,port,asio::ip::tcp::resolver::numeric_service);
ip::resolver::iterator it = resolver_dns.resolve(query_dns,ec);
//Create a socket
ip::socket sock(ios);
//Connect to endpoint
asio::connect(sock,it);
if (ec){
std::cout << " Failed to connect: " << ec.message() << std::endl;
return ec.value();
}
std::cout << "Connected successfully !!! " << std::endl;
if (sock.is_open()) {
//Create a stream buffer
std::stringstream request_stream;
request_stream << "GET https://api-fxpractice.oanda.com/v3/accounts HTTP/1.1\r\n"
"Authorization: Bearer <my token>\r\n"
"Connection: close\r\n\r\n";
//Tried to change to Host: https://api-fxpractice.oanda.com, doesn't work either
const auto request = request_stream.str();
asio::write(sock, asio::buffer(request));
using namespace std::chrono_literals;
std::this_thread::sleep_for(2000ms);
size_t bytes = sock.available();
if (bytes > 0) {
std::vector<char> vBuffer(bytes);
std::cout << "Have something to read !" << std::endl;
asio::read(sock, asio::buffer(vBuffer));
for (auto c: vBuffer) {
std::cout << c;
}
}
}
It's connected to the site but I can't get any data.
It keeps sending me either "HTTP/1.1 400 Bad Request" or "The plain HTTP request ... send to HTTPS port"
I'm not sure what I'm doing wrong here. :(
thank you guys so much.

boost/asio: Very simple chat server can't access the messages that are recieved

I am learning about boost and was messing around with its server and client communication to make a simple chat server, where anything that a client sends, is just displayed on the server. The server itself doesn't send anything and starts the receiving part. It is pretty straight-forward.
Server code:
#include <boost\asio\placeholders.hpp>
#include <boost\bind.hpp>
#include <boost\asio\ip\tcp.hpp>
#include <boost\asio\io_context.hpp>
#include <iostream>
class Server
{
private :
boost::asio::ip::tcp::socket server_socket;
boost::asio::ip::tcp::endpoint server_endpoint;
boost::asio::ip::tcp::acceptor acceptor;
std::string msg;
public :
Server(boost::asio::io_context &io) :
server_socket(io),
server_endpoint(boost::asio::ip::make_address("127.0.0.1"), 27015),
acceptor(io, server_endpoint)
{
acceptor.async_accept(server_socket,
boost::bind(&Server::async_acceptor_handler, this,
boost::asio::placeholders::error));
}
void async_acceptor_handler(const boost::system::error_code &ec)
{
if (!ec)
{
std::cout << "One client connected...\n";
server_socket.async_read_some(boost::asio::buffer(msg),
boost::bind(&Server::async_read_some_handler, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "async_acceptor failed with error code : " << ec.value() << std::endl;
std::cout << "Error description : " << ec.message() << std::endl;
}
}
void async_read_some_handler(const boost::system::error_code &ec)
{
if (!ec)
{
std::cout << msg << std::endl;
server_socket.async_read_some(boost::asio::buffer(msg),
boost::bind(&Server::async_read_some_handler, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "async_acceptor failed with error code : " << ec.value() << std::endl;
std::cout << "Error description : " << ec.message() << std::endl;
}
}
};
int main()
{
boost::asio::io_context io;
Server s(io);
io.run();
return 0;
}
In the client part, it is again a pretty straight-forward code, simply connects to the server and starts taking input from user and sends to server.
Client code:
#include <boost\asio\placeholders.hpp>
#include <boost\bind.hpp>
#include <boost\asio\ip\tcp.hpp>
#include <boost\asio\io_context.hpp>
#include <iostream>
class Client
{
private :
boost::asio::ip::tcp::socket client_socket;
boost::asio::ip::tcp::endpoint server_endpoint;
std::string msg;
public :
Client(boost::asio::io_context &iocontext) :
client_socket(iocontext),
server_endpoint(boost::asio::ip::make_address("127.0.0.1"), 27015)
{
//connect to server endpoint
client_socket.async_connect(server_endpoint,
boost::bind(&Client::async_connect_handler, this,
boost::asio::placeholders::error));
}
void async_connect_handler(const boost::system::error_code &ec)
{
if (!ec)
{
std::cout << "Connected to chat server...\n";
//wait for user input
std::cin >> msg;
std::cout << "\rC : " << msg << std::endl;
client_socket.async_write_some(boost::asio::buffer(msg),
boost::bind(&Client::async_write_some_handler, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "async_connect failed with error code : " << ec.value() << std::endl;
std::cout << "Error description : " << ec.message() << std::endl;
}
}
void async_write_some_handler(const boost::system::error_code &ec)
{
//wait for user input
std::cin >> msg;
std::cout << "\rC : " << msg << std::endl;
client_socket.async_write_some(boost::asio::buffer(msg),
boost::bind(&Client::async_write_some_handler, this,
boost::asio::placeholders::error));
}
};
int main()
{
boost::asio::io_context io;
Client c(io);
io.run();
return 0;
}
Now the problem:
It works fine, and connects to the server too. I get the proper "Connected to chat server..." in client and "One client connected..." in server. The problem arises after that :
In the server console, after the "One client" message, it just starts printing nothing and goes on and on.
The messages sent by the client are never showed in the server console.
Problem 1 can be a issue on my part as I am yet to check the wait functions and other calls which make the server wait. If you can guide me on that, it will be more than amazing. But the major problem is the part 2 of the problem, since, I have no idea why the server is always receiving nothing from client.
PS: This is an incomplete code and I plan to play a bit more with it, so, if there are some major flaws, please tell me so... :)
PPS: Before you say check other questions similar to this, I went through all the similar questions. For ex: this and this, but this are not relevant.
What is the size of string msg in the server side? It is 0. So the server reads always 0 bytes.
When you want to read to string and you call buffer::asio::buffer string must have some size, for example 10. It means you want to read 10 bytes into msg. You can call msg.resize(10) (before reading operation is initiated), then some data will be read into msg by async_read_some (it could be 1,2 bytes, whatever - it is how async_read_some works, but the maximum read characters is 10). But it is poor solution.
You are sending text, so you may consider using read data into streambuf instead of string, when you don't know how many bytes can come from the client side. Then you can call async_read_until with delimiter - it can be for example new line character.
Another solution is to use dynamic buffer. Where data is appened into string and you don't care about the initial size of string buffer. But dynamic buffer doesn't work with member functions of socket like async_read_some, it could be used with async_read as free function.