simple udp client boost - c++

I am trying to write a simple client to publish a UDP message to a server. My buffer is not being sent as a udp. When I try and send the message to netcat it does not appear.
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>
int main(int argc, char *argv[])
{
boost::asio::io_service io_service;
boost::asio::ip::udp::endpoint endpoint_(boost::asio::ip::address::from_string("0.0.0.0"), 2399);
boost::asio::ip::udp::socket socket(io_service, endpoint_);
boost::asio::socket_base::broadcast option(true);
socket.set_option(option);
char* data = "hello";
socket.send_to(boost::asio::buffer(data, strlen(data)), endpoint_);
getchar();
return 0;
}

Binding the socket to an endpoint is a server function. You could notice this by the fact you may receive a "Bind error/Address already in use" error if something listens on that port already.
Instead use socket.open:
Live On Coliru
#include <iostream>
#include <boost/asio.hpp>
int main()
{
using namespace boost::asio;
using ip::udp;
io_service io_service;
udp::socket socket(io_service);
socket.open(udp::v4());
socket.set_option(socket_base::broadcast(true));
const char* data = "hello";
udp::endpoint endpoint_(ip::address::from_string("0.0.0.0"), 2399);
socket.send_to(boost::asio::buffer(data, strlen(data)), endpoint_);
}

Related

Thrift client type cannot be resolved c++

I'm hoping to reuse an opened thrift connection to send/recieve multiple messages/responses over the duration of a session.
The client is created in the file
Client.h
#include <iostream>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>
#include "User.h"
#include <future>
using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
Client connect(const std::string &host, int port);
string run_command(Client client, const int32_t op_code, const std::string addr);
Client.cpp
#include <iostream>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>
#include "Client.h"
#include <future>
using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
Client connect(const std::string &host, int port) {
std::shared_ptr<TTransport> socket(new TSocket(host, port));
std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
Client client(protocol);
cout << "CONNECTING";
transport->open();
return client;
}
string run_command(Client client, const int32_t op_code, const std::string addr){
printf("CLIENT\n");
client.send_run_command(op_code, addr);
printf("CLIENT SEND_RUN_COMMAND COMPLETE\n");
string resp;
client.recv_run_command(resp);
printf("CLIENT RECV_RUN_COMMAND COMPLETE: %s\n", resp.c_str());
return resp;
}
However, I want to reuse the same client in a different file.
Shell.cpp
#include "Client.h"
#include <future>
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
Client client;
int32_t
taskset_fn(int32_t argc, char** argv) {
// stuff omitted
// auto client = connect("127.0.0.1", 9095); -> don't want to recreate client every time
string output = run_command(client, 6, string(cmd_buf));
return 0;
}
int lwshell_connect(const std::string &host, int port){
client = connect("127.0.0.1", 9095);
}
Building yields the following error:
no matching function for call to ‘ClientT<apache::thrift::protocol::TProtocol>::ClientT()’
Client client;
^~~~~~
In file included from [full path omitted]/programs/libuser/librpc/src/Client.h:7:0,
from [full path omitted]/programs/libuser
[full path omitted]/programs/libuser/librpc/src/User.h:183:3: note: candidate: ClientT<Protocol_>::ClientT(std::shared_ptr<_Tp>, std::shared_ptr<_Tp>) [with Protocol_ = apache::thrift::protocol::TProtocol]
ClientT(std::shared_ptr< Protocol_> iprot, std::shared_ptr< Protocol_> oprot) {
^~~~~~~
[full path omitted]/programs/libuser/librpc/src/User.h:183:3: note: candidate expects 2 arguments, 0 provided
[full path omitted]/programs/libuser/librpc/src/User.h:180:3: note: candidate: ClientT<Protocol_>::ClientT(std::shared_ptr<_Tp>) [with Protocol_ = apache::thrift::protocol::TProtocol]
ClientT(std::shared_ptr< Protocol_> prot) {
^~~~~~~
[full path omitted]/programs/libuser/librpc/src/User.h:180:3: note: candidate expects 1 argument, 0 provided
In short, the compiler thinks that Client client; is a function call, but I just want a static instance of the client. How can I make a reusable thrift client?
Things I've tried
1.
I have tried doing Client client(std::shared_ptr<TProtocol>);, which results in
: could not convert ‘client’ from ‘Client (*)(std::shared_ptr<apache::thrift::protocol::TProtocol>) {aka ClientT<apache::thrift::protocol::TProtocol>
(*)(std::shared_ptr<apache::thrift::protocol::TProtocol>)}’ to ‘Client {aka ClientT<apache::thrift::protocol::TProtocol>}’
2.
Making the global client a Client*:
Shell.cpp
Client* client;
...
Client client_temp = connect("127.0.0.1", 9095);
client = &client_temp;
printf("addr: %p\n", (void*) client);
...
printf("taskset ptr: %p\n", (void*) client);
string output = run_command(*client, 6, string(cmd_buf));```
causes segfault
▶ ./ShellUser
CONNECTINGaddr: 0x7fffbfdf2430
$ taskset 1
RECV:taskset 1
, 10
parsing
ARG: taskset
TASKSET
taskset ptr: 0x7fffbfdf2430
[1] 27587 segmentation fault (core dumped) ./ShellUser

no type named asio in namespace boost

I am attempting to write an asynchronous TCP server using boost::asio.
The using Tcp = boost::asio::ip::tcp directive is working correctly. However if I define
using Asio = boost::asio it doesn't seem to work. I get the error no type named asio in namespace boost. why is that?
Why is that?
#include <iostream>
#include <boost/asio.hpp>
#include <boost/optional.hpp>
using namespace std;
using Tcp = boost::asio::ip::tcp;
class session{
public:
session(Tcp::socket &&socket)
: m_socket(std::move(socket))
{
}
void async_read(){
}
private:
Tcp::socket m_socket;
boost::asio::streambuf m_streambuf;
};
class server{
public:
server(boost::asio::io_context &io_context, std::uint16_t port)
: io_context(io_context)
, m_acceptor(io_context, Tcp::endpoint(Tcp::v4(), port))
{
}
void async_accept() {
}
private:
boost::asio::io_context& io_context;
Tcp::acceptor m_acceptor;
boost::optional<Tcp::socket> m_socket;
};
int main()
{
return 0;
}
You need to do this:
namespace asio = boost::asio;
using foo = is for types, and namespaces are not types.
Ref: https://en.cppreference.com/w/cpp/language/namespace_alias

C++ Boost Assio - Start in another thread

I have Boost Assio implementation in my project. Here it is:
Session.h:
#ifndef VIBRANIUM_CORE_SESSION_H
#define VIBRANIUM_CORE_SESSION_H
#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
namespace Vibranium{
class Session
: public std::enable_shared_from_this<Session>
{
public:
Session(tcp::socket socket)
: socket_(std::move(socket))
{
}
void start();
private:
void do_read();
void do_write(std::size_t length);
tcp::socket socket_;
enum { max_length = 1024 };
char data_[max_length];
};
}
#endif //VIBRANIUM_CORE_SESSION_H
Session.cpp:
#include "Session.h"
void Vibranium::Session::start() {
do_read();
}
void Vibranium::Session::do_read() {
auto self(shared_from_this());
socket_.async_read_some(boost::asio::buffer(data_, max_length),
[this, self](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
do_write(length);
}
});
}
void Vibranium::Session::do_write(std::size_t length) {
auto self(shared_from_this());
boost::asio::async_write(socket_, boost::asio::buffer(data_, length),
[this, self](boost::system::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
do_read();
}
});
}
Server.h:
#ifndef VIBRANIUM_CORE_SERVER_H
#define VIBRANIUM_CORE_SERVER_H
#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
namespace Vibranium{
class Server {
public:
Server(boost::asio::io_context& io_context, short port)
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
{
do_accept();
}
private:
void do_accept();
tcp::acceptor acceptor_;
};
}
Server.cpp:
#include "Server.h"
#include "Session.h"
using namespace Vibranium;
void Server::do_accept() {
acceptor_.async_accept([this](boost::system::error_code ec, tcp::socket socket)
{
if (!ec)
{
std::make_shared<Session>(std::move(socket))->start();
}
do_accept();
});
}
And Here is how I start the server:
#include "Config.h"
#include "Database/MySQLConnection.h"
#include "Implementation/LoginDatabase.h"
#include "Banner.h"
#include "Server/Server.h"
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
using namespace std;
using namespace Vibranium;
int main() {
//Don't mind Logger::FatalError it's just for coloring!
Banner::Show(Logger::Error,"AuthServer");
Config config("AuthServer");
MySQLConnectionInfo mySqlConnectionInfo(config, "LoginDatabaseInfo");
LoginDatabaseConnection loginDatabaseConnection(mySqlConnectionInfo);
loginDatabaseConnection.LoadDatabase();
try
{
boost::asio::io_context io_context;
Server s(io_context, 8080);
io_context.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
std::cout << "Server Started!" << std::endl;
return 0;
}
I have several questions:
When I start the server I can't see the message "Server Started!". I suspect that is because it is blocking my current thread. How can I start the TCP server in another thread? Should it be in separate thread or ?
The example I have implemented just return back what is sent to the server. Can you suggest any example of how can I distinguish different event messages? What I want to achieve is something like when I sent message starting with 0x001 to point that this is chat message for example or when message starts with 0x002 my server to know that client is informing that somebody has logged off.
I think Boost Assio is using Binary Protocol over TCP. Am I right?
Can you show me how can I send structs over TCP with the binary protocol ?
If questions are too much, please consider only question 1.
1.When I start the server I can't see the message "Server Started!". I suspect that is because it is blocking my current thread. How can I
start the TCP server in another thread? Should it be in separate
thread or ?
std::cout << "Server Started!" << std::endl;
is called after
io_context.run();
io_context.run() will block as long there are any ongoing tasks. You need to call "Server Started" before io_context.run(), probably in Server constructor
2.The example I have implemented just return back what is sent to the server. Can you suggest any example of how can I distinguish different
event messages? What I want to achieve is something like when I sent
message starting with 0x001 to point that this is chat message for
example or when message starts with 0x002 my server to know that
client is informing that somebody has logged off.
There are many ways you could do this, but for ex. you could just set a field of your message to carry this information.
3.I think Boost Assio is using Binary Protocol over TCP. Am I right?
In your case yes, because your are using boost::asio::ip::tcp, but not necessary. There is also boost::asio::ip::udp for udp support.
4.Can you show me how can I send structs over TCP with the binary protocol ?
You could can just implement boost serialization method for your struct
template
void serialize(Archive& ar, const unsigned int version).
See boost example. or provide your own serialization (example to text) and send those data.
If you implement boost serialization, then you can pass your struct direct to asio functions, otherwise you have to send the serialized bytes.
Sorry, but having no time to write the whole code for you.

Boost ASIO socket io_service.run blocking

Before I start, I just was trying something out. I don't know yet if I want to do a big project.
I tried making a TCP Socket Server with Boost as it's much easier than winsock. At least, so I thought, but it doesn't work how I want it. What should happen:
Read configuration
Start TCP Socket Server
Run _acceptor.async_accept
Run io_service.run
Now, I got to the point my socket server works and accepts connections. However, I cannot do user input anymore as io_service.run blocks the rest of my server. I must be doing something wrong.
tcp_listener.h:
#pragma once
#include <boost/asio.hpp>
class tcp_listener
{
public:
tcp_listener(boost::asio::io_service& io_service, std::string ip, short port);
static void start(tcp_listener* ptr);
void start_accepting();
private:
boost::asio::ip::tcp::acceptor _acceptor;
boost::asio::ip::tcp::socket _socket;
};
tcp_listener.cpp:
#include "tcp_listener.h"
#include "logger.h"
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <memory>
tcp_listener::tcp_listener(boost::asio::io_service& io_service, std::string ip, short port)
: _acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4::from_string(ip), port)),
_socket(io_service)
{
logger::log_main("Network bound on %s.%d", _acceptor.local_endpoint().address().to_string().data(), _acceptor.local_endpoint().port());
start_accepting();
io_service.run();
}
void tcp_listener::start(tcp_listener* ptr)
{
ptr->start_accepting();
}
void tcp_listener::start_accepting()
{
_acceptor.async_accept(_socket, [this](boost::system::error_code ec)
{
if (!ec)
{
logger::log_main("New connection %s", _socket.remote_endpoint().address().to_string().data());
//std::make_shared<tcp_client>(std::move(socket_))->start_receiving();
}
else
{
_acceptor.close();
}
start_accepting();
});
}
engine.h:
#pragma once
#include "configuration.h"
class engine
{
public:
static void boot();
static void destroy();
static configuration* get_config();
private:
static configuration* config;
};
engine.cpp:
#include "engine.h"
#include "tcp_listener.h"
#include <boost/thread.hpp>
#include <boost/bind.hpp>
configuration* engine::config;
void engine::boot()
{
engine::config = new configuration("config.cnf");
boost::asio::io_service io_service;
tcp_listener& list = tcp_listener(io_service, engine::config->get_value("network.ip"), atoi(engine::config->get_value("network.port").data()));
}
void engine::destroy()
{
delete engine::config;
}
configuration* engine::get_config()
{
return engine::config;
}
Main.cpp:
#include "engine.h"
#include <iostream>
int main()
{
engine::boot();
for (;;)
{
std::string input;
std::cin >> input;
if (input == "exit")
{
engine::destroy();
break;
}
}
return 0;
}
I have searched for more than 5 hours, I tried a million things, nothing work. I tried putting it in a thread, resulting me in an exception. Or the socket server itself didn't work.
The user input is useful to reload certain cached data or close the application or something like that.
This is by design.
Just run the service on a separate thread.
std::thread th([&] { io_service.run(); }); // example
Beware of thread synchronization on shared resources then.
io_service is thread safe (except for special operations like construction, destruction, reset). So, if you must perform tasks that need synchronization it would be easiest to post() it to the service.
As long as you have only 1 thread run-ning the particular io_service instance, you don't need additional synchronization (what is known as a logical or implicit strand¹).
¹ Why do I need strand per connection when using boost::asio?

Boost Process library asynch_read handler not called

I am trying to use the boost process (0.5) library.
In asych_io.cpp example, the read handler is not getting called even once.
even after io_service.run() is called.
I am using Linux.
#include <boost/process.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <string>
using namespace boost::process;
using namespace boost::process::initializers;
using namespace boost::iostreams;
boost::process::pipe create_async_pipe()
{
return create_pipe();
}
int main()
{
boost::process::pipe p = create_async_pipe();
file_descriptor_sink sink(p.sink, close_handle);
child c = execute(
run_exe(search_path("nasm")),
set_cmd_line("nasm -v"),
bind_stdout(sink)
);
file_descriptor_source source(p.source, close_handle);
typedef boost::asio::posix::stream_descriptor pipe_end;
boost::asio::io_service io_service;
pipe_end pend(io_service,p.source);
boost::array<char, 4096> buffer;
boost::asio::async_read(pend, boost::asio::buffer(buffer),
[&](const boost::system::error_code&, std::size_t bytes_transferred){
std::cout << std::string(buffer.data(), bytes_transferred) << std::flush;
});
io_service.run();
}
After I replaced
boost::asio::async_read(pend...
with
pend.async_read_some(...
It worked for me.