를 반환 : 클래스 외부 (속성에 의해 객체의 벡터를 검색하고 내가 벡터, 사용자 정의 클래스 형의 회원이 UserAccounts, 사용자가 반복자
class User{
public:
//CONSTRUCTORS
User(){}
User(std::string username, std::string password)
//more efficient than using assignment operators
: username(username), password(password), GBPbal(0), sharesbal(0){}
//DESTRUCTOR
~User(){}
//SETTERS
void changeusername(std::string newuser){username = newuser;}
void changepassword(std::string newpassword){password = newpassword;}
void setGBP(float GBP){GBPbal = GBP;}
void setshares(int shares){sharesbal = shares;}
//GETTERS (HOLDINGS)
float getGBPbal(){return GBPbal;}
int getsharesbal(){return sharesbal;}
std::string getusername(){return username;}
//UPDATE HOLDINGS
float GBPUpdate(float adjustment){
GBPbal += adjustment;
return GBPbal;
}
int sharesUpdate(float adjustment){
sharesbal += adjustment;
return sharesbal;
}
protected:
private:
//Credentials
std::string username;
std::string password;
//Balances
float GBPbal;
int sharesbal;
friend class boost::serialization::access;
template <typename Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & username;
ar & password;
ar & GBPbal;
ar & sharesbal;
}
};
내가 문자열 주에서 선언 '이름'을 가지고을)에 이미 값이 할당되어 있습니다.
나의 목표는 사용자 이름 === 위에서 언급 한 사용자 이름을 가진 특정 사용자 객체를 벡터에서 검색하고 그것에 대한 참조를 반환합니다. 그것의 GBPbal을 인쇄 할 수 있고,이 값을 공유하고 업데이트 할 수 있어야합니다. 내 연구에서 대답은 다음과 같습니다 :
auto it = std::find_if(UserAccounts.begin(),
UserAccounts.end(), [&username](User& obj)->bool {return
obj.getusername() == username;});
//return their user account
std::cout << it->getGBPbal();
그러나 이것은 런타임시 작동하지 않는 것으로 보입니다. 나는 'obj'부분을 실제로 이해하지 못한다. 그러나 이것은 벡터 내부의 인스턴스/객체가 명시 적으로 명명되지 않았기 때문에 이것이라고 가정한다.
모든 것이 서로 연결되어 있기 때문에 최소한의 예를 제공하는 것은 어렵습니다.
//INTERNET DOMAIN SERVER: TCP.
//SERVER SIDE
//argv[1] = Port number for listening.
//argv[2] = Specify the maximum number of threads manually (optional).
// C++/STL/UNIX HEADERS
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <sys/types.h> //Datatypes used for sys calls (and used in <sys/socket.h> and <sys/socket.h>).
#include <sys/socket.h> //Definitions of structures used for sockets.
#include <netinet/in.h> //Contains constants and structures needed for internet domain addresses
#include <thread>
#include <vector>
#include <map>
#include <string>
#include <iostream>
#include <cstdlib>
#include <mutex>
//BOOST HEADERS
#include <boost/archive/text_iarchive.hpp> //Input archive.
#include <boost/archive/text_oarchive.hpp> //Output archive.
#include <boost/serialization/map.hpp> //Allows for archiving maps specifically.
#include <boost/serialization/string.hpp> //Allows for archiving strings specifically.
#include <boost/serialization/vector.hpp> //Allows for archiving vectors specifically.
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp> //Filestream for archiving
//MY HEADERS
#include "userclass.h"
//PP DIRECTIVES
void clientHandler(int sock, std::map<std::string, std::string>& userandPass, std::vector<class User>& UserAccounts);
void error(const char *msg);
void userandPassBackup(std::map<std::string, std::string>& userandPass);
void userandPassLoad(std::map<std::string, std::string>& userandPass);
template <typename SaveClass>
void saveData(const std::string filename, const SaveClass &c);
template <typename LoadClass>
void loadData(const std::string filename, LoadClass &c);//was having issues with const as second argument
//THREADING SETTINGS
unsigned int MAX_THREADS = std::thread::hardware_concurrency(); // MAX THREADS: LET COMPILER DECIDE BASED ON MACHINE RUNNING SERVER
// const unsigned int MAX_THREADS = atoi(argv[2]); // OR YOU CHOOSE
unsigned int CURR_THREADS = 1;
//LOCKS
std::mutex UserAccountsM;
std::mutex userandPassM;
// CURRENT NUMBER OF THREADS
int main(int argc, char *argv[])
{
// USER DATA
std::map<std::string, std::string> userandPass; //BANK OF CREDENTIALS
std::vector<class User> UserAccounts; //User account details
//userandPassLoad(std::ref(userandPass));
loadData< std::map<std::string, std::string> >("userandPassBackup.txt", userandPass); //LOAD IN DATA FROM BACKUP FILE
loadData<std::vector<User>>("accounts.txt", UserAccounts);
//These two variables store the values returned by the socket system call and the accept system call.
int sockfd; // sockfd and newsockfd are file descriptors ...
int newsockfd; // === array subscripts into the file descriptor table (which store pointers to iostreams).
unsigned int portno; // Portno stores the port that the server will allow connections to.
socklen_t clilen; //stores client address (needed for accept system call)
// char buffer[256]; // Socket is connected to this buffer. Server reads characters from here.
struct sockaddr_in serv_addr, cli_addr; // Structures containing internet addresses (client and server addresses).
// int n; // return value for read/write calls - ie how many characters have been read/written
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
// CREATE NEW SOCKET
// THREE ARGUMENTS:#1 . ADDRESS DOMAIN OF SOCKET - INTERNET DOMAIN FOR US, AF_UNIX IS AN ALTERNATIVE.
// #2 . TYPE OF SOCKET - EITHER STREAM (CONTINUOUS) OR DATAGRAM (CHUNK BY CHUNK).
// #3 . PROTOCOL: TCP OR UDP. LEAVE 0 AND THE OS WILL DECIDE WHAT IS APPROPRIATE.
// SOCKET CALL WILL RETURN AN ENTRY (SMALL INT > 0) TO THE FILE DESCRIPTOR TABLE.
// VALUE IS USED BY ALL REFERENCES TO THE SOCKET HEREON.
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
// SETS ALL BUFFER VALUES TO 0. ARGS ARE POINTER TO BUFFER, BUFFER SIZE.
bzero((char *) &serv_addr, sizeof(serv_addr));
// CONVERTS PORT NUMBER DEFINED BY USER FROM A STRING OF NUMBERS TO AN INTEGER
portno = atoi(argv[1]);
// SERV ADDR IS OF TYPE SOCKADDR_IN WHICH HAS FOUR FIELDS
// CODE FOR SOCK FAMILY: ALWAYS SET TO AF_INET
serv_addr.sin_family = AF_INET;
//SETS IP OF SERVER. INADDR_ANY FETCHES THIS - ITS PRESET.
serv_addr.sin_addr.s_addr = INADDR_ANY;
// PORT NO: MUST BE CONVERTED FROM HOST BYTE ORDER TO NETWORK BYTE ORDER USING HTONS
serv_addr.sin_port = htons(portno);
//BINDS SOCKET (OUR PORT) TO ADDRESS - ARGUMENTS ARE SOCKET FILE DESCRIPTOR, POINTER TO STRUCTURE OF TYPE SOCKADDR
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
// LISTEN FOR CONNECTIONS. ARGS: SOCKET FD, SIZE OF BACKLOG QUEUE - IE HOW MANY CONNECTIONS CAN WAIT IN LINE TO BE PROCESSED
listen(sockfd,5);
clilen = sizeof(cli_addr);
//vector of client threads
std::vector<std::thread> clientThreads;
// MULTITHREADING FOR SIMULTANEOUS CONNECTIONS
// extern const int maxthreads = atoi(argv[2]); //User defined maximum number of threads for server
// PUT ACCEPT STATMENT INSIDE INF WHILE LOOP SO SERVER RUNS INDEFINITELY.
while (1) {
searchAgain:
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0){
error("ERROR on accept");
}
// pid = fork();
// if (pid < 0)
// error("ERROR on fork");
if(CURR_THREADS < MAX_THREADS){
// close(sockfd); /* this was big problem before: we kept getting error 'bad file descriptor' on client side.
clientThreads.push_back(std::thread(clientHandler, newsockfd, std::ref(userandPass), std::ref(UserAccounts)));
goto searchAgain;
for(auto &t : clientThreads){
t.join();
}
exit(0);
}
else close(newsockfd);
} //end of loop
close(sockfd);
return 0;
}
void clientHandler(int sock,std::map<std::string, std::string>& userandPass, std::vector<class User>& UserAccounts)
{
int n;
char buffer[256];
// Welcome Messages
bzero(buffer,256);
write(sock, "Welcome to Chris's exchange! Write 'exit' to exit at any time.",255); // NB third argument always this value to prevent overlap.
bzero(buffer, 256);
loginmenu :
write(sock, "Do you wish to login or register a new account?",255);
bzero(buffer, 256);
while (1) {
n = read(sock,buffer,255); // NB blocks until client executes a write. Initially reads login/register request
// printf("Client message: %s",buffer); //client message
if (n < 0) error("ERROR reading from socket");
if(strcmp(buffer, "login\n") == 0){ // \n is extremely important!
bzero(buffer, 256);
n = write(sock,"Please enter your username.",255);
bzero(buffer, 256);
// read their username and password
n = read(sock,buffer,255);
std::string username(buffer);
bzero(buffer, 256);
n = write(sock,"Please enter your password.",255);
bzero(buffer, 256);
n = read(sock,buffer,255);
std::string password(buffer);
bzero(buffer, 256);
if(userandPass.find(username)->second == password){
write(sock, "Login successful. Press return to see balances.\n", 255);
auto it = std::find_if(UserAccounts.begin(), UserAccounts.end(), [&username](User& obj)->bool {return obj.getusername() == username;});
//return their user account
std::cout << it->getGBPbal();
bzero(buffer, 256);
read(sock,buffer,255);
std::string rtn(buffer);
if (rtn == "\n"){
bzero(buffer, 256);
goto loginmenu;
}
}
}
else if(strcmp(buffer, "register\n") == 0){
bzero(buffer, 256);
n = write(sock,"Please enter your desired username",255);
// Write code for reading these into strings
bzero(buffer, 256);
n = read(sock,buffer,255);
std::string username(buffer);
bzero(buffer, 256);
write(sock, "Please enter your desired password", 255);
bzero(buffer, 256);
n = read(sock,buffer,255);
std::string password(buffer);
bzero(buffer, 256);
//If it exists already try again
// std::unique_lock<std::mutex> UPlock(userandPassM); // to be exception safe
if (userandPass.find(username) != userandPass.end()){
write(sock, "That username is taken. Please try again.", 255);
}
// If it doesn't exist, happy days - lets add it to the database.
else if (userandPass.find(username) == userandPass.end()){
userandPass.emplace(username, password);
// std::unique_lock<std::mutex> UAlock(UserAccountsM);
UserAccounts.emplace_back(username, password);
//userandPassBackup(userandPass);
saveData< std::map<std::string, std::string> >("userandPassBackup.txt", userandPass); // have removed &. why is this needed. i want to pass by reference
// UPlock.unlock();
saveData< std::vector<User> >("accounts.txt", UserAccounts); // have removed &. why is this needed. i want to pass by reference
// UAlock.unlock();
while(1){
write(sock, "Account created successfully. Press return to continue", 255);
bzero(buffer, 256);
read(sock,buffer,255);
std::string rtn(buffer);
if (rtn == "\n"){
bzero(buffer, 256);
goto loginmenu;
}
}
}
}
else{
n = write(sock,"Invalid request, please try again. ",255);
bzero(buffer, 256);
}
if (n < 0) error("ERROR writing to socket");
}
--CURR_THREADS;
}
//ERROR HANDLING
void error(const char *msg) // System call error failures: Errors displayed on stderr.
{
perror(msg);
exit(1);
}
template <typename SaveClass>
void saveData(const std::string filename, const SaveClass& c)
{
// File to be written to
boost::filesystem::remove(boost::filesystem::current_path()/filename);
boost::filesystem::path myFile = boost::filesystem::current_path()/filename;
// Declare an output file stream ofs that writes serialises to our backup file.
boost::filesystem::ofstream ofs(myFile);
// Declare archive ta that will use our output file stream
boost::archive::text_oarchive ta(ofs);
// Write to file
ta << c;
// How many records have been archived?
std::cout << c.size() << " records from have been successfully backed up to " << myFile << "\n";
}
template <typename LoadClass>
void loadData(const std::string filename, LoadClass& c)
{
boost::filesystem::path myFile = boost::filesystem::current_path()/filename;
boost::filesystem::ifstream ifs(myFile);
boost::archive::text_iarchive ta(ifs);
// Write to file
ta >> c;
std::cout << c.size() << " records from have been successfully loaded from " << myFile << "\n";
}
NB는 다음 '자동 그것은 라인'후
std::cout << UserAccounts[1].getusername();
과 해당 개체에 대한 올바른 사용자 이름을 반환 내가 좋아하는 전화를 시도했습니다.
이 문제를 디버깅하려면 람다 대신 명명 된 함수를 만듭니다. 그런 다음 함수 포인터를'find_if()'에 전달하십시오. 이제 새로운 명명 된 함수 안에 중단 점을 설정하거나 그 안에'cout' 문을 추가 할 수 있습니다. –
대부분 스레드와 엉망이되었습니다. –
'goto searchAgain' 정말 사용 했나요? –