Setting a C++ Class char* in constructor - c++

I am writing a simple client / server program to mess around with socket programming. I made two classes, one for the client and one for the server. I can run my server with no problems and also my client can connect. But now I am attempting to modify my client so it accepts the hostname and port number in the constructor.
Here is what I have so far (client.h class only the constructor and attributes):
#ifndef CLIENT_H
#define CLIENT_H
class Client
{
public:
Client(char *in_hostname, int in_port)
: hostname(&in_hostname), port(in_port)
{
}
~Client() {}
private:
char *hostname;
int port;
};
#endif
I am having a hard time setting the char * hostname from the constructor. I am obviously having a little trouble with pointers and references. Can someone help me out here, coding mostly in PHP for the past 5 years has made my C++ rusty...
Here is the C++ file I use the client.h class.
#include <iostream>
#include "client.h"
using namespace std;
int main (int argc, char * const argv[])
{
char * hostname;
int port;
if(argc == 3)
{
hostname = argv[1];
port = argv[2];
Client *client = new Client(hostname, port);
delete(client);
}
else
{
cout << "Usage: ./client hostname port" << endl;
}
return 0;
}
Thanks!

If you're going to be coding in C++ may I suggest using std::string instead of char pointers?
class Client
{
public:
Client(const string& in_hostname, int in_port)
: hostname(in_hostname), port(in_port)
{
}
~Client() {}
private:
std::string hostname;
int port;
};
Edit:
In response to your comment. If you have to pass the pointer around to another function you can get it from std::string::c_str
std::string stuff;
stuff.c_str();

I am having a hard time setting the char * hostname from the constructer.
Change &in_hostname to in_hostname
Client(char *in_hostname, int in_port)
: hostname(in_hostname), port(in_port)
{
}
However if you want your code to be clean you should use std::string (C++ style string) instead of (char *) i.e C style string

class Mahasiswa{
public:
char nama[1000];
double tinggi,berat,imb;
Mahasiswa *next;
Mahasiswa(char* nama,double tinggi,double berat){
Mahasiswa::nama = nama;
Mahasiswa::tinggi = tinggi;
Mahasiswa::berat = berat;
}
double HasilBmi(){
double tinggi_meter = tinggi / 100;
imb = berat/(tinggi_meter*tinggi_meter);
return imb;
}
char* Getname(char* nama){
return nama;
}
};

Related

How to add additional parameter in existing constructor. C++ ASIO

I need help on constructing the endpoint with 3 arguements. Currently "IP Address" & "Port" are there in the constructor. But i need to include an integer arguement to identify the connection. Ideally as mentioned below.
asio::ip::tcp::endpoint endpoint(asio::ip::make_address("127.0.0.1", ec), 7497, clientId = 0);
Could you please help whether i have to modify the base class or can i inherit the base class & add this arguement? if inheriting is easy, please guide me on that.
int main(int argc)
{
int clientId = 0;
asio::error_code ec;
// Create a "context" - essentially the platform specific interface
asio::io_context context;
// Get th addres of somewhere w wish to connect to
asio::ip::tcp::endpoint endpoint(asio::ip::make_address("127.0.0.1", ec), 7497);
// Create a socket, the context will deliver the implementation
asio::ip::tcp::socket socket(context);
// tell socket to try and connect
socket.connect(endpoint, ec);
if (!ec)
{
std::cout << "Conected!" << std::endl;
}
else
{
std::cout << "Failed to connect to address:\n" << ec.message() << std::endl;
}
if (socket.is_open())
system("pause");
return 0;
}
Inherited class:
#pragma once
#include <iostream>
#ifdef _WIN32
#define _WIN32_WINNT 0x0A00
#endif
#define ASIO_STANDALONE
#include <asio.hpp>
#include <asio/ts/buffer.hpp>
#include <asio/ts/internet.hpp>
// Get th addres of somewhere w wish to connect to
class clien : public asio::ip::tcp::endpoint, asio::ip::address
{
public:
typedef asio::ip::tcp::endpoint endpoint;
char asio::ip::address;
int clientId;
//clien(int cid);
clien(str ep, int p, int cid) : asio::ip::tcp::endpoint(ep), char asio::ip::address, int cid;
{
clientId = cid;
}
};
since the class overloading way look to be the easiest:
class clien : public asio::ip::tcp::endpoint {
// inherit endpoint (because it the class you want to change)
protected:
int __cid; // the id
public:
int clientId() const { return __cid; } // getter
void clientId(int cid) { __cid = cid; } // setter
clien(str ep, int p, int cid) :
asio::ip::tcp::endpoint(ep, p), // construct the actual endpoint
__cid(cid){} // set the cid
};
i'm not familiar with the library so some type (for the constructor) might be wrong.
You can make a new type using endpoint and id
struct MyEndpoint{
asio::ip::tcp::endpoint endpoint{};
int someId{};
}
Create the endpoint
auto const someId = 42;
auto myEndpoint = MyEndpoint{ .endpoint = { boost::asio::ip::tcp::v4 (), 7497 }, .someId = someId };
Now you can get the id and the endpoint
myEndpoint.someId; // To get the id
myEndpoint.endpoint; // To get the endpoint
Another idea is to make a pair of id and endpoint
auto const someId=42;
auto idAndEndpoint= std::make_pair(someId, asio::ip::tcp::endpoint{(asio::ip::make_address("127.0.0.1", ec), 7497)});
Now you can get the id and the endpoint
auto &[id, endpoint] = idAndEndpoint;

Is there a way return and delete content of an std::string?

I am writing a socket server in C++ and need to wrapper the read function, from an std::string buffer. As you can see in the below code for reading a single byte (ClientConnection.readByte), it uses a char to store the value, delete it, then return the char. However I also want to implement a readEverything (ClientConnection.readEverything) function, which should return the entire buffer.
Right now, I just copy the buffer, but this doesn't seem memory efficient. This would be easy if I could return before readBuffer.erase(), but that can't work. Is there an efficient workaround, or do I just have to use my original method?
class ClientConnection{
private:
int connfd;
std::string writeBuffer;
std::string readBuffer;
struct sockaddr *address;
public:
ClientConnection(int fd){
connfd = fd;
}
bool available(){
char toReturn;
recv(connfd, &toReturn, 1, MSG_PEEK);
return toReturn!=-1;
}
char readByte(){
char thingy = readBuffer[0];
readBuffer.erase(0, 1);
return thingy;
}
std::string readEverything(){
std::string readBufferCopy = readBuffer;
readBuffer.erase();
return readBufferCopy;
}
void writeByte(char byte){
writeBuffer += byte;
}
void polleverything(){
write(connfd, writeBuffer.c_str(), writeBuffer.length());
char readBuffer[READOUTBUFFERSIZE];
while (recv(connfd, &toReturn, READOUTBUFFERSIZE, 0) == READOUTBUFFERSIZE){
std::cout << "HELLO";
};
}
};
The ClientConnection class is supposed to be passed file descriptors and otherwise used by a server class, which for the sake of easy-reading I omitted from this snippet.
Thanks in advance!

Unable to call function in main (Inheritance in UDP Client App using C++)

I have created a separate UDP Server Application and a Client Application, and they are communicating with each other. I have tried to implement inheritance as the next step for this application (Base class : udp, child class: udpClient). I have developed the code for the client which I have presented my code below with comments as explanation.
I am having a problem in the last line of the code where the object is used to call the derived class. I do not know what parameters to give here. I have highlighted the problem area with comments. Any help is appreciated
EDIT : Also, 50003 is the port number right? If it was around 70000, the check should give an error right? But its not. What would be the problem?
UDP Client program
#include <iostream>
#include <WS2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
class udp {
protected:
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOk = WSAStartup(version, &data);
public:
void checkudp()
{
if (wsOk != 0)
{
cout << "Can't start Winsock! " << wsOk;
return;
}
}
};
class udp_client : public udp {
private:
sockaddr_in server;
char clientIp[256];
int argc;
char* argv[];
public:
void udpworking(*int argc, char* argv[]*) { //PROBLEM HERE with call to main function
server.sin_family = AF_INET; // AF_INET = IPv4 addresses
server.sin_port = htons(50003); // Little to big endian conversion
inet_pton(AF_INET, "127.0.0.1", &server.sin_addr); // Convert from string to byte array
// Socket creation, note that the socket type is datagram
SOCKET out = socket(AF_INET, SOCK_DGRAM, 0);
// Write out to that socket
string s(argv[1]);
int sendOk = sendto(out, s.c_str(), s.size() + 1, 0, (sockaddr*)&server, sizeof(server));
if (sendOk == SOCKET_ERROR)
{
cout << "That didn't work! " << WSAGetLastError() << endl;
}
closesocket(out);
WSACleanup();
}
};
void main()
{
udp_client obj;
obj.udpworking(); //Parameter problem with function call
}
udp_client::udpworking requires two arguments, that you need to pass in parameters (in the parenthesis).
Also as mentioned in the comments void main() is not a valid signature for this function. Only int main() (which ignores all parameters) and int main(int argc, char **argv) (which takes in the command line parameters) are valid signatures.
Try something like this:
int main(int argc, char **argv) {
udp_client obj;
obj.udpworking(argc, argv);
return 0;
}
PS: I take it you added the stars surrounding the parameters in the functions when you posted it on SO? (the udpworking(*int argc, char* argv[]*))

Dynamically generate protobuf Message and return a pointer to it

First of all I'm not very experienced with C++, so maybe I'm overseeing something here.
I'm trying to dynamically generate protobuf Messages from .proto files with the following code:
int init_msg(const std::string & filename, protobuf::Arena* arena, protobuf::Message** new_msg){
using namespace google::protobuf;
using namespace google::protobuf::compiler;
DiskSourceTree source_tree;
source_tree.MapPath("file", filename);
MuFiErCo error_mist;
Importer imp(&source_tree, &error_mist);
printf("Lade Datei:%s \n", filename.c_str());
const FileDescriptor* f_desc = imp.Import("file");
const Descriptor* desc = f_desc->FindMessageTypeByName("TestNachricht");
const Message* new_msg_proto = dmf.GetPrototype(desc);
*new_msg = new_msg_proto->New(arena);
//Debug
cout << (*new_msg)->GetTypeName() << endl;
return 0;
}
int main(int argc, char* argv[]){
protobuf::Arena arena;
protobuf::Message *adr2, *adr1;
init_msg("schema-1.proto", &arena, &adr1);
init_msg("schema-1.proto", &arena, &adr2);
printf("MSG_Pointer: %p, %p\n", adr1, adr2);
cout << adr1->GetTypeName() << endl;
arena.Reset();
return 0;
}
I thought if i use Arena, the new Message is also available outside the scope of the function.
But there is always a segfault if i try to access the Message.
I guess it's a simple error, but I couldn't figure out, how to solve this.
Here is the ouput:
Lade Datei:schema-1.proto
packet.TestNachricht
Lade Datei:schema-1.proto
packet.TestNachricht
MSG_Pointer: 0x1b293b0, 0x1b287f0
Speicherzugriffsfehler (Speicherabzug geschrieben)
The problem, I think, is that FileDescriptor et al are destroyed when
init_msg returns, leaving the newly created message with no way to
interrogate its .proto definition. You'd need to move Importer
instance to main and keep it alive. This has nothing to do with
arenas. – Igor Tandetnik
That was the solution.
Here is some working example code
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <memory>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/arena.h>
using namespace std;
using namespace google::protobuf;
class MuFiErCo : public compiler::MultiFileErrorCollector
{
public:
void AddError(const string & filename, int line, int column, const string & message){
printf("Err: %s\n", message.c_str());
}
void AddWarning(const string & filename, int line, int column, const string & message){
printf("Warn: %s\n", message.c_str());
}
};
compiler::Importer* init_proto_dir(Arena* arena, const std::string &root_dir){
using namespace compiler;
static DiskSourceTree source_tree;
source_tree.MapPath("", root_dir);
static MuFiErCo error_mist;
static Importer* imp = Arena::Create<Importer>(arena, &source_tree, &error_mist);
return imp;
}
void init_proto_def(compiler::Importer* imp, const std::string &proto_file){
using namespace compiler;
imp->Import(proto_file);
return;
}
Message* init_msg(compiler::Importer* imp, Arena* arena, const std::string &msg_name){
const DescriptorPool* pool = imp->pool();
static DynamicMessageFactory dmf;
const Descriptor* desc = pool->FindMessageTypeByName(msg_name);
const Message* msg_proto = dmf.GetPrototype(desc);
return msg_proto->New(arena);
}
int set_value(Message* msg, const char* value_name, unsigned long int value){
const Message::Reflection* reflec = msg->GetReflection();
const Descriptor* desc = msg->GetDescriptor();
const FieldDescriptor* fdesc = desc->FindFieldByName(value_name);
reflec->SetUInt64(msg, fdesc, value);
return 0;
}
int main(int argc, char* argv[]){
Arena arena;
compiler::Importer* imp = init_proto_dir(&arena, "");
init_proto_def(imp, "schema-1.proto");
Message* msg = init_msg(imp, &arena, "packet.TestNachricht");
set_value(msg, "zahl", 23434);
cout << msg->DebugString() << endl;
return 0;
}

MySQL C++ Connector crashes my app at ResultSet->getString()

It's me again probably asking noob C++ questions
I had MAJOR headaches making the darn (sorry for the language) MySQL C++ connector work. I don't know if it is poorly written or something, but for my experience yet I've never had so much trouble making something to work.
Anyhow I got it to connect and throw exceptions on failed connect/query which for me is quite big thing :U :P . The actual problem comes out of me obtaining the result of the query. Regardless of what I do my application always crashes :S
I used the 32-bit installer and the libmysql.dll/lib from the 32-bit MySQL server (since i'm compiling a 32-bit application i figured this is the right thing to do)
Here's some code so you could imagine what I'm talking about
DBManager.h
#ifndef DBMANAGER_H
#define DBMANAGER_H
#define CPPCONN_PUBLIC_FUNC
#define CPPCONN_LIB_BUILD True
#include <string>
#include "mysql_connection.h"
#include "mysql_driver.h"
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
class DBManager
{
public:
static DBManager* Instance();
bool Query(const char* Query);
void Connect(const char* DbHost, unsigned short DbPort, const char* DbUser, const char* DbPass, const char* DbName);
bool ValidCredentials(const char* Username, const char* Password);
void ManageException(sql::SQLException &e);
~DBManager();
protected:
static DBManager* pInstance;
private:
DBManager() {};
DBManager(DBManager const&){};
DBManager& operator=(DBManager const&){};
sql::mysql::MySQL_Driver* driver;
sql::Connection *Con;
sql::PreparedStatement *pstmt;
sql::ResultSet *res;
sql::Statement *stmt;
bool isConnected;
};
#endif
And now the cpp file DBManager.cpp
#include "DBManager.h"
DBManager* DBManager::pInstance = NULL;
DBManager* DBManager::Instance()
{
if (!pInstance)
{
pInstance = new DBManager();
}
return pInstance;
}
bool DBManager::Query(const char* Query)
{
return true;
}
DBManager::~DBManager()
{
delete Con;
delete pstmt;
delete res;
delete stmt;
}
void DBManager::ManageException(sql::SQLException& e)
{
if (e.getErrorCode() != 0) {
std::cout << "# ERR: SQLException in " << __FILE__;
std::cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << std::endl;
std::cout << "# ERR: " << e.what();
std::cout << " (MySQL error code: " << e.getErrorCode();
std::cout << ", SQLState: " << e.getSQLState() << " )" << std::endl;
}
}
void DBManager::Connect(const char* DbHost, unsigned short DbPort, const char* DbUser, const char* DbPass, const char* DbName)
{
try {
driver = sql::mysql::get_mysql_driver_instance();
std::string connDSN = "tcp://" + std::string(DbHost) + ":3306";
Con = driver->connect(connDSN, sql::SQLString(DbUser), sql::SQLString(DbPass));
Con->setSchema(sql::SQLString(DbName));
isConnected = true;
std::cout<<"Database connection successul."<<std::endl;
} catch(sql::SQLException &e) {
ManageException(e);
isConnected = false;
return;
}
}
bool DBManager::ValidCredentials(const char* Username, const char* Password)
{
bool cred = false;
try {
pstmt = Con->prepareStatement("SELECT * FROM account WHERE account_name=? LIMIT 1"); // Smart use of indexing
pstmt->setString(1, Username);
res = pstmt->executeQuery();
while(res->next())
{
if (res->getString("password") == Password)
{
cred = true;
}
}
}
catch(sql::SQLException &e) {
ManageException(e);
return false;
}
return cred;
}
Basically, It compiles without a problem, Connects without a problem, Executes queries without a problem, but the second I try to retrieve data some breakpoint exception is thrown in a file "xutils.cpp". I really have no idea what I'm doing wrong. I'm using the DEBUG libraries while compiling for debug. Hmm libmysql.dll should be release since I extracted it from the server bundle, but I don't seem to find it as a source to compile my own.
I really have no idea why it crashes and burn like that :/
PS: Don't mind the no hashing of the password, it really is just a proof of concept to me in the way of ... getting it to work first, then securing it :U
PS: I also have Boost libraries compiled and ready in the project, if that would help :U
EDIT: Main function
bool ServerRunning = true;
int main(int argc, char** argv)
{
#ifdef _WIN32
std::string title = TEXT("Window Title Change");
SetConsoleTitle(title.c_str());
#endif;
std::cout<<"Loading Configuration File..."<<std::endl<<std::endl;
std::string path = boost::filesystem::path(boost::filesystem::current_path()).string();
path += "\\Config.ini";
INIParser* Config = new INIParser(path.c_str()); //MinINI
// Sockets data
std::string listenIP = Config->GetString("Network", "ListenIP", "127.0.0.1");
unsigned short listenPort = Config->GetInt("Network", "ListenPort", 5000);
// Database data
std::string dbHost = Config->GetString("Database", "Host", "localhost");
std::string dbUser = Config->GetString("Database", "User", "root");
std::string dbPass = Config->GetString("Database", "Password", "");
std::string dbName = Config->GetString("Database", "Database", "authserv");
unsigned short dbPort = Config->GetInt("Database", "Post", 1000);
// General settings
int sessionTimeout = Config->GetInt("Settings", "SessionTimeout", 10);
int maxClients = Config->GetInt("Settings", "MaxClients", 10);
int serverTimeout = Config->GetInt("Settings", "GameserverTimeout", 1);
// Begin Initialization
DBManager::Instance()->Connect(dbHost.c_str(), dbPort, dbUser.c_str(), dbPass.c_str(), dbName.c_str());
bool loginSuccess = DBManager::Instance()->ValidCredentials("Username", "Password");
char c;
while (ServerRunning)
{
std::cin>>c;
if (c == 'q')
{
ServerRunning = false;
}
}
return 0;
}
Assuming the password field is defined as varchar in the database, you cannot use getString() to retrieve it. You must instead use the blob function, getBlob().
This is how the while loop would look:
while(res->next())
{
std::istream * retrievedPassword_stream = res->getBlob("password");
if (retrievedPassword_stream)
{
char pws[PASSWORD_LENGTH+1]; // PASSWORD_LENGTH defined elsewhere; or use other functions to retrieve it
retrievedPassword_stream->getline(pws, PASSWORD_LENGTH);
std::string retrievedPassword(pws); // also, should handle case where Password length > PASSWORD_LENGTH
if (retrievedPassword == std::string(Password))
{
cred = true;
}
}
}
Side comments: Note that there are some other issues with the code.
The statement handle must be deleted, so you should do a delete pstmt; at the appropriate place in the ValidCredentials() function (rather than in the destructor). (But, why use a prepared statement in that case anyways? Better to initialize the prepared statement in the constructor (or somewhere else outside the function the query is called), as well as delete in the destructor or elsewhere, if you do use a prepared statement. Instead of a prepared statement, though, note that prepared statements are most useful for very high-use and high-CPU intensive queries, so using it for password validation might not be important here (you could just execute a regular query, instead of a prepared statement).)
Likewise, the ResultSet needs to be deleted (delete res) at the end of the try block, rather than in the destructor.
Be sure to check for NULL before using pstmt, res, or Con.
stmt appears to be unused and should not be deleted.
download mysql c++ connector
compile mysqlcppconn-static project use mt or mtd
your project add CPPCONN_LIB_BUILD
your project add (2) built static library