I'm trying to develop an app that realises the communication between a gameserver and an applcation.
My code so far is:
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
using namespace std;
enum { max_length = 1024 };
class client
{
public:
boost::asio::streambuf receive_buffer;
client(boost::asio::io_service& io_service, boost::asio::ssl::context& context, boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
: socket_(io_service, context)
{
socket_.set_verify_mode(boost::asio::ssl::verify_peer);
socket_.set_verify_callback(
boost::bind(&client::verify_certificate, this, _1, _2));
boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
boost::bind(&client::handle_connect, this,
boost::asio::placeholders::error));
}
bool verify_certificate(bool preverified, boost::asio::ssl::verify_context& ctx)
{
char subject_name[256];
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
return preverified;
}
void handle_connect(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_handshake(boost::asio::ssl::stream_base::client,
boost::bind(&client::handle_handshake, this,
boost::asio::placeholders::error));
}
else
{
cout << "Connect failed: " << error.message() << "\n";
}
}
void handle_handshake(const boost::system::error_code& error)
{
if (!error)
{
cout << "trimite cmd: ";
cin.getline(request_, max_length);
size_t request_length = strlen(request_);
boost::asio::async_write( socket_,
boost::asio::buffer(request_, request_length),
boost::bind(&client::handle_write, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
cout << "Handshake failed: " << error.message() << "\n";
}
}
void handle_write(const boost::system::error_code& error, size_t bytes_transferred)
{
if (!error)
{
boost::asio::async_read_until(socket_,
receive_buffer,
"!",
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
cout << "Write failed: " << error.message() << "\n";
}
}
void handle_read( const boost::system::error_code& error, size_t bytes_transferred )
{
if( !error )
{
cout << "de la sv: " << &receive_buffer << "\n";
}
else
{
cout << "Read failed: " << error.message() << "\n";
}
}
private:
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
char request_[max_length];
char reply_[max_length];
};
int main( int argc, char* argv[] )
{
if (argc != 3)
{
cerr << "Usage: client <host> <port>\n";
return 1;
}
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query(argv[1], argv[2]);
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
ctx.load_verify_file("ca.pem");
client c( io_service, ctx, iterator );
io_service.run();
}
This is the example from the Boost site. My problem is that i want to make the connection "keep-alive" and separate it in "threads" to call it like that, and dont know if its the appropiate word.
e.g.:
in the main() i start the io_service then i should have 1 callback for ReceiveingData, and also one Function to Send Data.
Client can receive data permanently( i use here read_until ) but also he can send data anytime he wants.
These actions are done until i call the close of the socket.
for e.g.
client sends data 1
client sends data 2
client receives data 213( ReceiveingData is fired )
client receives data 125161( ReceiveingData is fired )
client receives data 136161( ReceiveingData is fired )
10 minutes pause
client sends data xxxx
client receives data zzz( ReceiveingData is fired )
SOCKET CLOSE, client disconnected from server
How to deal with this? I read something about "strand" but i don't understand what's that.
I tried to do something with strand but i have a bunch of errors:
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/strand.hpp>
#include <fstream>
using namespace std;
boost::asio::streambuf receive_buffer;
enum { max_length = 1024 };
class client
{
public:
client(boost::asio::io_service& io_service, boost::asio::ssl::context& context, boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
: strand_(io_service), socket_(io_service, context)
{
socket_.set_verify_mode(boost::asio::ssl::verify_peer);
socket_.set_verify_callback(
boost::bind(&client::verify_certificate, this, _1, _2));
boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
boost::bind(&client::handle_connect, this,
boost::asio::placeholders::error));
}
bool verify_certificate(bool preverified, boost::asio::ssl::verify_context& ctx)
{
char subject_name[256];
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
return preverified;
}
void handle_connect(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_handshake(boost::asio::ssl::stream_base::client,
boost::bind(&client::handle_handshake, this,
boost::asio::placeholders::error));
}
else
{
cout << "Connect failed: " << error.message() << "\n";
}
}
void read( )
{
boost::asio::async_read_until(socket_,
receive_buffer,
"!",
strand_.wrap(&handle_read));
}
void write( )
{
cout << "trimite cmd: ";
cin.getline(request_, max_length);
size_t request_length = strlen(request_);
boost::asio::async_write( socket_,
boost::asio::buffer(request_, request_length),
strand_.wrap(&handle_write));
}
void handle_handshake(const boost::system::error_code& error)
{
if (!error)
{
strand_.post(&read);
strand_.post(&write);
}
else
{
cout << "Handshake failed: " << error.message() << "\n";
}
}
void handle_write(const boost::system::error_code& error, size_t bytes_transferred)
{
if (!error)
{
write( );
}
}
void handle_read( const boost::system::error_code& error, size_t bytes_transferred )
{
if( !error )
{
ofstream f;
f.open( "test.txt", ios::app );
f << &receive_buffer << endl;
f.close( );
read( );
}
}
private:
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
boost::asio::io_service::strand strand_;
char request_[max_length];
char reply_[max_length];
};
int main( int argc, char* argv[] )
{
if (argc != 3)
{
cerr << "Usage: client <host> <port>\n";
return 1;
}
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query(argv[1], argv[2]);
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
ctx.load_verify_file("ca.pem");
client c( io_service, ctx, iterator );
io_service.run();
}