ABOUT ME

-

  • [018] 회원가입, 로그인 구현
    Programming/Dev 2025. 2. 27. 22:05

    DevLog

    이전 게시글에서 C++에서 데이터베이스와 통신하는 것에 대해서 작성했다.

    그래서 이번엔 회원가입과 로그인 하는 과정을 구현해보았다.

     

     

     

     

    간단히 만든 로그인, 회원가입 윈도우

    회원가입부터 보자면 일단 클라이언트에서 아이디, 비밀번호를 입력받는다.

    아이디의 경우 오른쪽 버튼을 통해 중복 체크도 하도록 했다.

     

     

     

     

    // 클라이언트
    void OnCheckIDButtonClicked()
    {
        std::wstring id;
        if (auto textBox{ GetControl<TextBox>(L"ID") })
            id = textBox->GetText();
    
        Packet packet{ Protocol::Type::Register };
        packet.Encode(Protocol::Register::Check, id);
        LoginServer::GetInstance()->Send(packet);
    }
    // 로그인 서버
    void ClientSocket::OnAccountRegister(Packet& packet)
    {
        auto subType{ packet.Decode<Protocol::Register>() };
        switch (subType)
        {
        case Protocol::Register::Check:
        {
            auto id{ packet.Decode<std::wstring>() };
            Packet outPacket{ Protocol::Type::Register };
            outPacket.Encode(Protocol::Register::Check, GetID(), id);
            CenterServer::GetInstance()->Send(outPacket);
            break;
        }
        ...
    }
    // 센터 서버
    void ServerSocket::OnRegisterAccountRequest(Packet& packet)
    {
        auto subType{ packet.Decode<Protocol::Register>() };
        switch (subType)
        {
        case Protocol::Register::Check:
        {
            auto socketID{ packet.Decode<ID>() };
    
            int32_t ret{ -1 };
            auto id{ packet.Decode<std::wstring>() };
            Database::StoredProcedure{ Database::Type::Game }
                .Statement(L"{ ? = CALL [dbo].[is_available_account_name] (?) }")
                .Out(1, &ret)
                .In(2, id)
                .Execute();
    
            Packet outPacket{ Protocol::Type::Register };
            outPacket.Encode(Protocol::Register::CheckResult, socketID, ret == 0);
            Send(outPacket);
            break;
        }
        ...
    }

    클라이언트에서 아이디 중복 체크 버튼을 누르면 로그인 서버로 패킷을 보내게 되고

    로그인 서버에서 그대로 센터 서버로 전달하게 된다.

    센터 서버에서는 받은 패킷으로 SP를 호출해서 사용 가능한 아이디인지 확인하고 결과를 로그인 서버로 보내준다.

     

     

     

     

    // 로그인 서버
    void CenterServer::OnRegisterAccountRequest(Packet& packet)
    {
        auto subType{ packet.Decode<Protocol::Register>() };
        switch (subType)
        {
        case Protocol::Register::CheckResult:
        {
            auto socketID{ packet.Decode<ID>() };
            auto sm{ SocketManager::GetInstance() };
            if (!sm)
                break;
    
            auto clientSocket{ sm->GetSocket(socketID) };
            if (!clientSocket)
                break;
    
            auto isAvailable{ packet.Decode<bool>() };
    
            Packet outPacket{ Protocol::Type::Register };
            outPacket.Encode(Protocol::Register::CheckResult, isAvailable);
            clientSocket->Send(outPacket);
            break;
        }
        ...
    }
    // 클라이언트
    void OnPacket(Packet& packet)
    {
        if (packet.GetType() != Protocol::Type::Register)
            return;
    
        auto subType{ packet.Decode<Protocol::Register>() };
        switch (subType)
        {
        case Protocol::Register::CheckResult:
        {
            m_isAvailableID = packet.Decode<bool>();
            if (m_isAvailableID)
            {
                if (auto textBox{ GetControl<TextBox>(L"ID") })
                    textBox->SetEnable(false);
            }
    
            auto popup{ std::make_shared<PopupModal>(m_isAvailableID ? L"사용 가능한 아이디입니다." : L"사용 불가능한 아이디입니다.") };
            WindowManager::GetInstance()->Register(std::static_pointer_cast<IModal>(popup));
            break;
        }
        ...
    }

    로그인 서버에서 센터 서버로 요청을 보낼 때 소켓 아이디를 같이 보내는데,

    그 이유가 센터 서버로부터 응답을 받았을 때 누구의 요청의 결과가 온건지 모르기 때문이다.

    그래서 소켓 아이디를 통해 요청을 보낸 클라이언트를 찾아 결과를 전달해준다.

    클라이언트에서는 응답을 받아 화면에 띄워준다.

     

    아이디 중복 체크 로직을 설명했는데 회원가입이나 로그인도 동일한 흐름으로 진행된다.

     

     

     

     

    USE [game]
    GO
    
    DROP PROCEDURE IF EXISTS [dbo].[register_account]
    GO
    
    CREATE PROCEDURE [dbo].[register_account]
        @name NVARCHAR(16),
        @password NVARCHAR(16)
    AS
    BEGIN
        INSERT INTO [dbo].[account]
        VALUES (@name, HASHBYTES('SHA2_256', @password), GETDATE(), NULL)
    END
    GO

    그리고 이제 데이터베이스도 다루는 만큼 SP나 테이블 스키마도 버전 관리를 하려고 한다.

    그래서 SP의 경우 위와 같은 형태로 버전 관리를 하려고 한다.

    `DROP PROCEDURE` 구문을 넣어 이미 해당 SP가 있어도 삭제하고 만들도록 했다.

     

    다음에는 로그인 성공 시 클라이언트 씬 변경하는 것을 구현하려고 한다.

    댓글