I'm learning boost. I'd like to write a simple application that allows user to store data on server. User can insert new data using PUT command followed by ID number and data value, and retrieve data using GET command followed by ID. User requests are processed in analyze_user_request function and are subsequently written to or read from array. The thing is that I want every client to refer to his own array. That means that if one client saves something under particular ID this data is visible only to him. I wonder, how can I associate array with different clients, and create a new array when a new client connects? I tried encapsulating private data in class, but it doesn't seem to work, because now a new array is created every time user enters any request. This is my code:
//CLIENT
#include <cstdlib>
#include <cstring>
#include <iostream>
#include
using boost::asio::ip::tcp;
enum { max_length = 1000000 };
int main(int argc, char* argv[])
{
while(1)
{
try
{
if (argc != 3)
{
std::cerr << "Usage: blocking_tcp_echo_client <host> <port>\n";
return 1;
}
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(tcp::v4(), argv[1], argv[2]);
tcp::resolver::iterator iterator = resolver.resolve(query);
tcp::socket s(io_service);
s.connect(*iterator);
using namespace std; // For strlen.
std::cout << "Enter message: ";
char request[max_length];
std::cin.getline(request, max_length);
if (request == "\n")
continue;
size_t request_length = strlen(request);
boost::asio::write(s, boost::asio::buffer(request, request_length));
char reply[max_length];
boost::system::error_code error;
size_t reply_length = s.read_some(boost::asio::buffer(reply), error);
if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
std::cout << "Reply is: ";
std::cout.write(reply, reply_length);
std::cout << "\n";
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
exit(1);
}
}
return 0;
}
//SERVER
#include <cstdlib>
#include <iostream>
#include
#include
#include
#include
#include
#include
#include <string>
using boost::asio::ip::tcp;
const int max_length = 1000000;
typedef boost::shared_ptrtcp::socket socket_ptr;
unsigned short analyze_user_request(std::string& user_request, short unsigned* ID, std::string* request_value)
{
// function returns:
// 0: if user request is incorrect
// 1: if user requests "PUT" operation
// 2: if user requests "GET" operation
// Furthermore, if request is correct, its value (i.e. ID number and/or string) is saved to short unsigned and string values passed by pointers.
boost::regex exp("^[[:space:]]*(PUT|GET)[[:space:]]+([[:digit:]]{1,2})(?:[[:space:]]+(.*))?$");
boost::smatch what;
if (regex_match(user_request, what, exp, boost::match_extra))
{
short unsigned id_number = boost::lexical_cast<short unsigned>(what[2]);
if (what[1] == "PUT")
{
boost::regex exp1("^[a-zA-Z0-9]+$");
std::string value = boost::lexical_caststd::string(what[3]);
if (value.length() > 4095)
return 0;
if (!regex_match(value, exp1))
return 0;
else
{
*request_value = value;
*ID = id_number;
return 1;
}
}
if (what[1] == "GET")
{
*ID = id_number;
return 2;
}
}
if (!regex_match(user_request, what, exp, boost::match_extra))
return 0;
}
class Session
{
public:
void handleRequest(socket_ptr sock)
{
try
{
for (;;)
{
char data[max_length];
boost::system::error_code error;
size_t length = sock->read_some(boost::asio::buffer(data), error);
if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
// convert buffer data to string for further procession
std::string line(boost::asio::buffers_begin(boost::asio::buffer(data)), boost::asio::buffers_begin(boost::asio::buffer(data)) + length);
std::string reply; // will be "QK", "INVALID", or "OK <value>"
unsigned short vID;
unsigned short* ID = &vID;
std::string vrequest_value;
std::string* request_value = &vrequest_value;
unsigned short output = analyze_user_request(line, ID, request_value);
if (output == 1)
{
// PUT
reply = "OK";
std::cout << "PUT operation - ID: " << *ID << " request value: " << *request_value << "\n";
user_array[*ID] = *request_value;
}
else if (output == 2)
{
// GET
std::cout << "GET operation - ID: " << *ID << " request value: " << *request_value << "\n";
reply = user_array[*ID];
if (reply == "")
reply = "EMPTY";
}
else
reply = "INVALID";
boost::system::error_code ignored_error;
size_t ans_len=reply.length();
boost::asio::write(*sock, boost::asio::buffer(reply));
}
}
catch (std::exception& e)
{
std::cerr << "Exception in thread: " << e.what() << "\n";
}
}
private:
std::string user_array[100];
};
typedef boost::shared_ptr<Session> SessionPtr;
void server(boost::asio::io_service& io_service, short port)
{
std::cout << "In \"server\" function\n";
tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port));
for (;;)
{
socket_ptr sock(new tcp::socket(io_service));
a.accept(*sock);
SessionPtr newSession(new Session());
boost::thread acceptThread(boost::bind(&Session::handleRequest, *newSession, sock));
}
}
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: blocking_tcp_echo_server <port>\n";
return 1;
}
boost::asio::io_service io_service;
using namespace std; // For atoi.
server(io_service, atoi(argv[1]));
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}