Apache thrift multi client server - apache

I am writing simple chat in Qt + Apache Thrift but right now I need to face a problem with connecting multiple clients. On first sight everything looks good and I cannot find where the problem is.
Here is my server main.cpp:
int main(int argc, char **argv)
{
int port = 9090;
::apache::thrift::stdcxx::shared_ptr<UsersStorageHandler> handler(new UsersStorageHandler());
::apache::thrift::stdcxx::shared_ptr<TProcessor> processor(new UsersStorageProcessor(handler));
::apache::thrift::stdcxx::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
::apache::thrift::stdcxx::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
::apache::thrift::stdcxx::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
std::cout << "Users server started..." << std::endl;
std::cout << std::endl;
std::cout << std::endl;
server.serve();
return 0;
}
Here is my server handler.h:
class UsersStorageHandler : virtual public UsersStorageIf
{
public:
UsersStorageHandler();
int32_t subscribeUser(const std::string& username);
void unsubscribeUser(const int32_t userID);
private:
Users users;
};
Here is my server handler.cpp:
UsersStorageHandler::UsersStorageHandler()
{
srand(time(NULL));
}
int32_t UsersStorageHandler::subscribeUser(const std::string &username)
{
++idGenerator;
assert(username != "");
User user;
user.userId = idGenerator;
user.username = username;
user.colorR = (rand() % 255) + 0;
user.colorG = (rand() % 255) + 0;
user.colorB = (rand() % 255) + 0;
user.colorA = 0;
users[idGenerator] = user;
std::cout << "NEW USER CONNECTED" << std::endl;
std::cout << "==================" << std::endl;
std::cout << "Username:\t" << user.username << std::endl;
std::cout << "User ID:\t" << user.userId << std::endl;
std::cout << "User R:\t" << user.colorR << std::endl;
std::cout << "User G:\t" << user.colorG << std::endl;
std::cout << "User B:\t" << user.colorB << std::endl;
std::cout << "User A:\t" << user.colorA << std::endl;
std::cout << "==================" << std::endl;
std::cout << "CURRENT USERS COUNT:\t" << users.size() << std::endl;
std::cout << std::endl;
std::cout << std::endl;
/*
* SEND TO CLIENT INFO ABOUT NEW USER HERE
*/
return idGenerator;
}
void UsersStorageHandler::unsubscribeUser(const int32_t userID)
{
auto index = users.find(userID);
assert(index != users.end());
users.erase(index);
std::cout << "USER DISCONNECTED" << std::endl;
std::cout << "=================" << std::endl;
std::cout << "USER WITH ID " << userID << " ERASED" << std::endl;
std::cout << "USERS COUNT:\t" << users.size() << std::endl;
std::cout << std::endl;
std::cout << std::endl;
/*
* SEND TO CLIENT INFO ABOUT NEW USER HERE
*/
}
And right here is a method for connect to the server in client app:
void MainWindow::connectToServers(const std::string &ip, const uint32_t &port, const std::string &nick)
{
m_usersServerIP = ip;
m_usersServerPort = port;
try
{
::apache::thrift::stdcxx::shared_ptr<TTransport> socket(new TSocket(m_usersServerIP, m_usersServerPort));
::apache::thrift::stdcxx::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
::apache::thrift::stdcxx::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
m_usersServerClient = std::make_shared<UsersStorageClient>(protocol);
transport->open();
m_clientID = m_usersServerClient.get()->subscribeUser(nick);
QMessageBox::information(this, "Connected",
"You are connected "
"with users server");
createAndRegisterUsersServerReactor();
activateChatScreen();
}
catch (const std::exception &e)
{
qDebug() << e.what();
}
qDebug() << "ID FROM SERVER:\t" << m_clientID;
}
As far as I checked right now it is working like this:
Created two instances of client app. In one instance fill nickname, ip, port and clicked connect (connectToServers method). Client connected. In another instance done the same but after clicked connected ... nothing happens. App freezes at this line:
m_clientID = m_usersServerClient.get()->subscribeUser(nick);
After closing first client, second one connects to the server.

A TSimplerServer supports a single connection. You should try using TThreadedServer to support multiple simultaneous clients.

As Chris mentioned above either make a Threaded server to server multiple requests simultaneously. For me I have created a non-blocking server as below to be able to serve multiple clients in async manner for loose coupling.
public static void start(dataClass configData, String env, int port) throws TTransportException {
TNonblockingServerTransport transport = new TNonblockingServerSocket(port);
TNonblockingServer.Args nBlockServer = new TNonblockingServer.Args(transport);
ccmProviderServiceImpl impl = new ccmProviderServiceImpl(configData, env);
Processor<ccmProviderServiceImpl> processor = new ccmProviderService.Processor<>(impl);
TServer server = new TNonblockingServer(nBlockServer.processor(processor));
//custom event handling for tracking
ccmServerEventHandler cse = new ccmServerEventHandler();
server.setServerEventHandler(cse);
server.serve();
}

Related

Missing data inside the dat file after writing operation

I am trying to save the data the user inputted inside a linked-list and then store those data inside a file so that I can retrieve them back when I enter the 2nd option(as per in the int main()). Unfortunately, after I wrote the data into the file and check back the file, I found out that my data is missing and the file is filled with garbage.so I cant retrieve the data back. Is there any solution to this problem?? Thank you.
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<fstream>
using namespace std;
fstream fp;
class List{
private:
struct node{
string name;
string surname;
int idNum;
string nationality;
int number;
node *next;
}nod;
node* head;
node* curr;
node* temp;
public:
List();
bool isEmpty(node *head){
if(head==NULL){
return true;
}
else
return false;
}
void AddNode(string addName,string addsurName,int addId,string addNation,int addNumber);
void insertAsFirst(string addName,string addsurName,int addId,string addNation,int addNum);
//void DeleteNode(int delData);
void printList();
void write_linky(string name,string surName,int idNum,string nation,int number);
void read_linky();
}lb;
List::List(){
head=NULL;
curr=NULL;
temp=NULL;
}
void List::insertAsFirst(string addName,string addsurName,int addId, string addNation,int addNum){
node *n = new node;
n->name=addName;
n->surname=addsurName;
n->idNum=addId;
n->nationality=addNation;
n->number=addNum;
n->next = NULL;
head = n;
//last = temp;
}
void List::AddNode(string addName,string addsurName,int addId,string addNation,int addNum){
if(isEmpty(head)){
insertAsFirst(addName,addsurName,addId,addNation,addNum);
}
else{
node* n = new node;
n->next=NULL;
n->name=addName;
n->surname=addsurName;
n->idNum=addId;
n->nationality=addNation;
n->number=addNum;
curr = head;
while(curr->next != NULL){
curr = curr->next;
}
curr->next = n;
}
}
void List::printList(){
curr=head;
cout << "\n\t\t\t\t CUSTOMER INFO" << endl << endl;
cout <<"NAME" << setw(20) << "SURNAME" << setw(20) << "ID NO. " << setw(20) << "NATIONALLITY" << setw(20) << "TELEPHONE" << endl << endl;
while(curr != NULL){
cout << curr -> name << setw(20) << curr -> surname << setw(20) << curr -> idNum << setw(20) << curr -> nationality << setw(20) << curr -> number << endl << endl;
curr=curr->next;
/*cout<<curr->number << endl;
cout<<curr->age << endl;
cout<<curr->idNum << endl;
cout<<curr->name<< endl;
cout<<curr->surname << endl;
cout<<curr->nationality << endl;
curr = curr->next;
}
*/
}
}
void List::write_linky(string name,string surName,int idNum,string nation,int number)
{
fp.open("Link.dat",ios::out|ios::app);
lb.AddNode(name,surName,idNum,nation,number);
lb.printList();
fp.write((char*)&nod,sizeof(node));
fp.close();
cout<<"\n\nThe Data Has Been Added ";
}
void List::read_linky(){
fp.open("Link.dat",ios::in);
while(fp.read((char*)&nod,sizeof(node)))
{
lb.printList();
//cout<<"\n\n=====================================================\n";
//getch();
}
fp.close();
//getch();
}
int main(){
List lb;
int idNum,number;
string name,surname,nationality;
char choice,ch;
cout<<"Please select your choice"<<endl;
cout<<"1.Book ticket"<<endl;
cout<<"2.view details"<<endl;
cin>>ch;
switch(ch){
case '1':
do{
cout<< "Enter name: ";
cin>>name;
cout<< "Enter surname: ";
cin>>surname;
cout<< "Enter identification number: ";
cin>>idNum;
cout<< "Enter your nationality: ";
cin>>nationality;
cout<< "Enter contact number: ";
cin>>number;
lb.write_linky(name,surname,idNum,nationality,number);
//lb.AddNode(number,age,idNum,name,surname,nationality);
cout<<"\n\nDo you want to add more entry?";
cin>>choice;
}while(choice=='y');
break;
case '2':
lb.read_linky();
break;
}
}
//lb.printList();
I've never done this but I'd guess string is a complex structure that doesn't lend itself to being written to disk like this. As a test change these to (say) char[255] and it might be happier.

Qt5: Sql queries failing and tables not shown

There are many similar questions on here already but unfortunately, none has solved my problem so far.
I am stuck connecting Qt to a simple sqlite database. The connection can be established, but queries fail with No query Unable to fetch row and db.tables() returns me no tables.
My code is the following:
void DBManager::connOpen()
{
m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db.setDatabaseName(m_db_path);
m_db.open();
if (!m_db.open())
{
qDebug("Error: Connection to database failed.");
}
else
{
qDebug("Connection to database established.");
QSqlQuery query(m_db);
query.prepare("SELECT * FROM data1");
if (!query.exec())
{
std::cout << query.lastError().text().toStdString() << std::endl;
std::cout << query.executedQuery().toStdString() << std::endl;
}
while (query.next())
{
std::cout << query.value("id").toString().toStdString() << ". " << query.value("one").toString().toStdString() << std::endl;
}
QSqlDriver *driver = m_db.driver();
QStringList tables = m_db.tables();
std::cout << "tables found: " << tables.count() << std::endl;
for(QString table: tables)
{
QSqlRecord record = driver->record(table);
std::cout << "name: " << table.toStdString() << std::endl;
std::cout << "count: " << record.count() << std::endl;
std::cout << record.fieldName(0).toStdString() << std::endl;
}
}
}
This leads to console output like this:
Connection to database established.
No query Unable to fetch row
SELECT * FROM data1
tables found: 0
My database should have one table (data1). Executing the query by hand returns this:
Any help is appreciated, thank you.
It came down to a very stupid mistake.
I was using a sqlite2 database that I created using sqlite mydb while QSQLITE is the driver for sqlite3 (using sqlite3 mydb).

Saving input to variable so after the program closes it will remember the input

I am making a program that stores a default password that when entered correctly you can change it. Problem is when I enter the new password it doesn't save when I close and open the program.
#include<iostream>
#include<sstream>
using namespace std;
string inputC;
string yes = "yes";
string no = "no";
string password;
string input;
void correct()
{
cout << "Would you like to change the password?" << endl;
cin >> inputC;
if (inputC == yes)
{
cout << "Enter new password:" << endl;
cin >> password;
}
else
{
cout << "You now have access." << endl;
}
}
void enter()
{
cout << "Enter password: " << endl;
cin >> input;
if (input == password)
{
cout << "Correct" << endl;
correct();
}
else
{
cout << "Incorrect" << endl;
enter();
}
}
int main()
{
if (password.empty())
{
password = "password";
}
enter();
}
http://pastebin.com/zhKTW2FB
As far as I know, variables you create with code go to RAM Memory, so they are destroyed as soon as your programs finishes. In order to keep the new password, you should consider having it written in an external text file or database.

SEGV on emitting null root (yaml-cpp)

I am trying yaml-cpp (r589:2c954b1ed301), but I have a trouble with following code.
#include <iostream>
#include <yaml-cpp/yaml.h>
int main()
{
YAML::Node doc;
std::cout << doc << std::endl; // SEGV
doc["sub"] = YAML::Node();
std::cout << doc << std::endl; // OK
doc = YAML::Load("");
std::cout << doc << std::endl; // OK
std::cout << YAML::Load("") << std::endl; // SEGV
std::cout << YAML::Load("a") << std::endl; // OK
YAML::Node doc2 = YAML::Load("");
std::cout << doc2 << std::endl; // SEGV
return 0;
}
The code is compiled with g++ 4.4.7 on Scientific Linux 6.4.
I am not sure that this error occurs only on my environment.
I would appreciate your comments and suggestions.
This was a bug, but it was fixed (see the bug report).

where is boost property_tree::empty_ptree?

I'm using boots's property_tree library. I'm looking for a way to get a child node from a ptree object, but return an empty ptree if failed. I came across a nice example in property_tree/examples/empty_ptree_trick.cpp:
void process_settings(const std::string &filename)
{
ptree pt;
read_info(filename, pt);
const ptree &settings = pt.get_child("settings", empty_ptree<ptree>());
std::cout << "\n Processing " << filename << std::endl;
std::cout << " Setting 1 is " << settings.get("setting1", 0) << std::endl;
std::cout << " Setting 2 is " << settings.get("setting2", 0.0) << std::endl;
std::cout << " Setting 3 is " << settings.get("setting3", "default") << std::endl;
}
which does exactly what I need. The problem is that the compiler complains that empty_ptree() function is not a member of boost:property_tree. Any ideas where empty_ptree() is?
I'm using boost 1.44 on VS2010.
I have just blown a full day trying to answer that question!
This was my solution. Firstly I used pointers, and not references as you have to initialize them immediately. Then I just caught the exception and added a new ptree.
using namespace boost::property_tree;
ptree r_pt;
ptree *c_pt;
read_xml( "file.xml" , r_pt);
try {
c_pt = &(r_pt.get_child( "example" ));
}
catch (ptree_bad_path) {
c_pt = &(r_pt.put_child( "example", ptree() ));
}
std::cout << "Setting 1 is " << c_pt.get("setting1", 0) << std::endl;
From what I could pick up they expect us to use the boost::optional type. But I'm just a beginner..
EDIT
I just found the implementation of empty_ptree<>.
template<class Ptree>
inline const Ptree &empty_ptree()
{
static Ptree pt;
return pt;
}
I think you can just add this to your code and use it as described in the empty_ptree_trick.cpp, but I am sticking with my solution for now untill I find out how its actually supposed to be done.
void process_settings(const std::string &filename)
{
ptree pt;
read_info(filename, pt);
const ptree &settings = pt.get_child("settings", ptree());
std::cout << "\n Processing " << filename << std::endl;
std::cout << " Setting 1 is " << settings.get("setting1", 0) << std::endl;
std::cout << " Setting 2 is " << settings.get("setting2", 0.0) << std::endl;
std::cout << " Setting 3 is " << settings.get("setting3", "default") << std::endl;
}
Note, that will prevent throwing an instance of 'boost::wrapexceptboost::property_tree::ptree_bad_path'