스마트팩토리부트갬프 2기 채팅방 구현하기(client.cpp) (c++, Mysql, socket)

Chaedonghyun·2023년 5월 13일

Team project 채팅방 만들기

1.C++ MySQL설치 프로그램을 설치를 해야 한다.

https://downloads.mysql.com/archives/c-cpp/

windows(x86, 64-bit), ZIP Archive를 다운 받는다.

2.설치 파일 이동
-Documents->libraries 폴더 생성한다.
-libraries 폴더에 압축 해제 폴더를 복사 붙여놓기
-폴더 이름 변경 mysql8.0.32-64로 한다.

3.프로젝트 설정
구성:Release, 플랫폼x64 확인

C/C ++->일반->추가 포함 디렉터리-> 압축푼 mysql의 include까지의 주소를 입력한다.

C/C ++->전처리기->전처리기의 정의->STATIC_CONCPP;추가하기

C/C ++->코드 생성->런타임 라이브러리->다중 스레드 DLL(/MD)확인

링커->일반->추가 라이브러리 디렉터리->mysql파일의 lib64->vs14파일 경로를 붙여 넣는다

링커->입력->추가 종속성->mysqlcppconn-static.lib 넣기


파일을 프로젝트 main.cpp와 같은 디렉토링에 복사 붙여넣기를 한다.
이로써 기본 적인 준비는 끝났다.

이제 main.cpp로 가서 코드를 작성 한다.

#pragma comment(lib, "ws2_32.lib")
#include <WinSock2.h>
#include <WS2tcpip.h>
#include < string>
#include < sstream>
#include < iostream>
#include < thread>
#include < mysql/jdbc.h>
#include< istream>

using std::cout;
using std::endl;
using std::string;

//mysql 연결 하는 string문을 상수선언을 한다.
const string server = "tcp://127.0.0.1:3306";
const string username = "root";
const string password = "abc1234";

//서버측에서 보내주는 내용을 담는크기를 맥스사이즈를 정한다.
#define MAX_SIZE 1024

using std::cout;
using std::cin;
using std::endl;
using std::string;

sql::mysql::MySQL_Driver driver;
sql::Connection
con;
sql::Statement stmt;
sql::PreparedStatement
pstmt;
sql::ResultSet* result;

SOCKET client_sock;
string id_in;

//서버측에서 sned를 할때 받는 recv함수
int chat_recv() {
char buf [MAX_SIZE] = { };
string msg;
while (1) {
ZeroMemory(&buf, MAX_SIZE);

    if (recv(client_sock, buf, MAX_SIZE, 0) > 0) {
        msg = buf;
        std::stringstream ss(msg);
        //stringstream에서 공백과'\n'을 제외하고 문자열에서 맞는 자료형의 정보를 빼낸다
        string user;
        ss >> user;
        if (user != id_in) cout << buf << endl;
    }
    else {
        cout << "Server Off" << endl;
        return -1;
    }
}

}

//회원가입
void SignUp() {
string id, pw, name;
string check_id, check_pw;

while (1) {

 cout << "사용할 아이디를 입력하세요:";
 cin >> id;
    
    pstmt = con->prepareStatement("SELECT * FROM user where id=? ;"); //유저 id의 중복 체크를 위한 select문
    pstmt->setString(1, id);
    pstmt->execute();
  
   result = pstmt->executeQuery();
    while (result->next()) {
        check_id = result->getString(1).c_str();
    }
    if (check_id == id) {
        cout << "이미 사용중인 아이디 입니다." << endl;
    }
    else if (check_id != id) {
        cout << "사용할 비밀번호를 입력하세요: ";
        cin >> pw;
        cout << "본인의 이름을 입력하세요: ";
        cin >> name;
        break;
    }
}
//아이디 중복 체크가 끝나면 비밀번호 이름을 user테이블에 저장한다.
pstmt = con->prepareStatement("insert into user(id, pw, user_name) values(?,?,?)");
pstmt->setString(1, id);
pstmt->setString(2, pw);
pstmt->setString(3, name);
pstmt->execute();
cout << "회원가입 성공" << endl;

}

//저장된 채팅내용 가져오기
void Store(string check_id) {

string StoreUser, StoreMsg; //user테이블에서 id랑,chatting내용을 담을 변수 

bool id = true;
cout << "저장된 내용" << endl;
con->setSchema("project");
pstmt = con->prepareStatement("SELECT * FROM chatting ;");
result = pstmt->executeQuery();
while (result->next()) {
    StoreUser = result->getString("id").c_str();
    StoreMsg = result->getString("chat").c_str();
    //처음 입장해서 채팅내용이 없으면 전 내용을 못보게 설정
    if (StoreUser == check_id)
    {
        id = false;
    }
    if (id == false)
    {
        cout << StoreUser << " : " << StoreMsg << endl;
    }
}

}

//비밀번호 변경하는 함수
void Revise() {

string id, pw;
string check_id, check_pw;
cout << "아이디를 입력하세요. : ";
cin >> id;
cout << "비밀번호를 입력하세요";
cin >> pw;
pstmt = con->prepareStatement("SELECT * FROM user where id = ? and pw =?;");
pstmt->setString(1, id);
pstmt->setString(2, pw);
pstmt->execute();
result = pstmt->executeQuery();
//user의 id,pw를 while문을 이용해 check_id,check_pw에 담아서 
 입력한 아이디와 비밀번호와 비교한다.
while (result->next()) {
    check_id = result->getString(1).c_str();
    check_pw = result->getString(2).c_str();
}
if (check_id != id || check_pw != pw) {
    cout << "아이디,비밀번호가 맞지 않습니다.\n";
}
else {
    cout << "변경할 비밀번호를 입력해 주세요. : ";
    cin >> pw;
    pstmt = con->prepareStatement("select id from user");
    result = pstmt->executeQuery();
    while (result->next()) {
        pstmt = con->prepareStatement("UPDATE user SET pw = ? WHERE id = ?");
        pstmt->setString(1, pw);
        pstmt->setString(2, id);
        pstmt->executeQuery();
    }
    cout << "변경 되었습니다\n";
}

}

//회원탈퇴
void Leave() {

string id, pw, name;
string check_id, check_pw, check_name;
cout << "아이디를 입력해주세요: ";
cin >> id;
cout << "비밀번호를 입력해주세요: ";
cin >> pw;
cout << "이름을 입력해주세요: ";
cin >> name;
pstmt = con->prepareStatement("SELECT * FROM user where id = ? and pw = ? and user_name = ?");
pstmt->setString(1, id);
pstmt->setString(2, pw);
pstmt->setString(3, name);
pstmt->execute();
result = pstmt->executeQuery();

while (result->next()) {
    check_id = result->getString(1).c_str();
    check_pw = result->getString(2).c_str();
    check_name = result->getString(3).c_str();
}
if (check_id != id || check_pw != pw || check_name != name) {
    cout << "회원 정보가 일치하지 않습니다.\n";
}
else {
    pstmt = con->prepareStatement("DELETE FROM user WHERE id = ?");
    pstmt->setString(1, id);
    result = pstmt->executeQuery();
    pstmt = con->prepareStatement("DELETE FROM chatting WHERE id = ?");
    pstmt->setString(1, id);
    result = pstmt->executeQuery();
    cout << "탈퇴되었습니다.\n";
}
//회원 탈퇴시 저장된 대화 내용도 삭제된다.

}

//테이블을 생성 하는 함수
void Createtable() {

stmt->execute("CREATE TABLE user (id varchar(50) PRIMARY KEY not null, pw VARCHAR(50), user_name VARCHAR(50));");
stmt->execute("create table chatting(id varchar(50), chat varchar(250) not null, foreign key(id) references user(id) on update cascade on delete cascade);");
stmt->execute("create table direct_msg(send_id varchar(50), recv_id varchar(50), msg varchar(250), foreign key(send_id) references user(id) on update cascade on delete cascade);");
delete stmt;

}
//메인문
int main()
{

WSADATA wsa;
int choice = 0;
bool log = true;
int code = WSAStartup(MAKEWORD(2, 2), &wsa);
// sql 연결
try {
    driver = sql::mysql::get_mysql_driver_instance();
    con = driver->connect(server, username, password);
}
catch (sql::SQLException& e) {
    cout << "Could not connect to server. Error message: " << e.what() << endl;
    exit(1);
}
con->setSchema("project");
//한국어를 받기위한 설정문
stmt = con->createStatement();
stmt->execute("set names euckr");
if (stmt) { delete stmt; stmt = nullptr; }
stmt = con->createStatement();
delete stmt; 

// show tables을 해서 테이블이 없으면 Createtable()문을 실행한다.
string check_usertable;
stmt = con->createStatement();
pstmt = con->prepareStatement("show tables");
result = pstmt->executeQuery();

while (result->next()) {
    check_usertable = result->getString(1).c_str();
}
if (check_usertable == "") {
    Createtable();
}
if (!code) {
    //client측 소켓을 만드는 문
    client_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    SOCKADDR_IN client_addr = {};
    client_addr.sin_family = AF_INET;
    client_addr.sin_port = htons(8080); 
    InetPton(AF_INET, TEXT("127.0.0.1"), &client_addr.sin_addr);
    
    while (true) {
        cout << "1: 로그인하기 2: 회원가입하기 3: 비밀번호 수정 4:회원탈퇴" << endl;
        cin >> choice;
        // 로그인
        if (choice == 1) {
            string pw;
            string check_id, check_pw;
            cout << "ID:";
            cin >> id_in;
            cout << "PW:";
            cin >> pw;
            pstmt = con->prepareStatement("SELECT * FROM user where id=? and pw=?;");
            pstmt->setString(1, id_in);
            pstmt->setString(2, pw);
            pstmt->execute();
            result = pstmt->executeQuery();
            while (result->next()) {
                check_id = result->getString(1).c_str();
                check_pw = result->getString(2).c_str();
            }
            if (check_id == id_in && check_pw == pw) {
                cout << "로그인 되었습니다." << endl;
                //로그인후 서버와 커넥트 한다.
                while (1) {
                    if (!connect(client_sock, (SOCKADDR*)&client_addr, sizeof(client_addr))) {
                        cout << "Server Connect" << endl;
                        send(client_sock, id_in.c_str(), id_in.length(), 0);
                        break;
                    }
                    cout << "Connecting..." << endl;
                }
                std::thread th2(chat_recv);
                Store(check_id);
                while (1) {
                    string text;
                    std::getline(cin, text);
                    //대화 내용을 getline을 이용해 띄어쓰기가 있어도 buffer에 담아 서버로 보내준다.
                    const char* buffer = text.c_str(); // string형을 char* 타입으로 변환
                    send(client_sock, buffer, strlen(buffer), 0);
                }
                th2.join();
                closesocket(client_sock);
            }
            else {
                cout << "로그인에 실패했습니다." << endl;
                continue;
            }
        }
        if (choice == 2)
        {
            SignUp();
            continue;
        }
        if (choice == 3)
        {
            Revise();
            continue;
        }
        if (choice == 4) {
            int num;
            cout << "정말 탈퇴하시겠습니까? (예: 1 아니오: 2)\n";
            cin >> num;
            if (num == 1) {
                Leave();
            }
            else {
                choice = 0;
            }
            continue;
        }
    }
    WSACleanup();
}

}

profile
SMF 일기

0개의 댓글