Study/Project

VV 4. 클라이언트 수신

에린_1 2024. 10. 29. 19:23
728x90

VV

  • 서버에서 로그인 과정을 거쳤으니 그 결과를 다시 클라이언트에 보내줘야 한다. 나는 결과에 따라서 다른 프로토콜을 쓰는게 아니라 같은 프로토콜로 대신에 attribute에 다른 값으로 성공했는지 실패했는지 알아볼 수 있도록 구성했다.
bool OnDataHandle(IDataBuffer* pDataBuffer, int32_t nConnID)
{
    if (pDataBuffer == nullptr)
    {
        CLog::GetInstancePtr()->LogError("Received null data buffer in OnDataHandle.");
        return false;
    }

    PacketHeader* pHeader = (PacketHeader*)pDataBuffer->GetBuffer();
    if (pHeader == nullptr)
    {
        CLog::GetInstancePtr()->LogError("Invalid packet header.");
        return false;
    }

    int32_t MsgID = pHeader->MsgID;
    switch (MsgID)
    {
    case EMessageID::LOGIN_REQUEST_MSG_ID:
    {
        string ReceiveData(pDataBuffer->GetData(), pDataBuffer->GetTotalLenth());
        vector<string> ParsedData;

        size_t pos = 0;
        string token;
        while ((pos = ReceiveData.find('|')) != string::npos)
        {
            token = ReceiveData.substr(0, pos);
            ParsedData.push_back(token);
            ReceiveData.erase(0, pos + 1);
        }
        ParsedData.push_back(ReceiveData);
        
        if (ParsedData.size() == 2)
        {
            string ID = ParsedData[0];
            string PW = ParsedData[1];

            bool bIsValid = ValidateUserCredentials(ID, PW);
         
            // TODO: Send success response to client
            hbServerEngine::PacketHeader ResponseHeader;
            ResponseHeader.MsgID = EMessageID::LOGIN_RESPONSE_MSG_ID;
            ResponseHeader.TotalSize = sizeof(hbServerEngine::PacketHeader);
            ResponseHeader.Attribute = bIsValid ? 0 : 1;

            std::vector<uint8_t> ResponsePacket(sizeof(hbServerEngine::PacketHeader));
            memcpy(ResponsePacket.data(), &ResponseHeader, sizeof(hbServerEngine::PacketHeader));

            IDataBuffer* ResponseBuffer = CBufferAllocator::GetInstancePtr()->AllocDataBuff(ResponsePacket.size());
            memcpy(ResponseBuffer->GetBuffer(), ResponsePacket.data(), ResponsePacket.size());
            ResponseBuffer->SetTotalLenth(ResponsePacket.size());

            CConnection* Connection = CConnectionMgr::GetInstancePtr()->GetConnectionByID(nConnID);
            if (Connection)
            {
                Connection->SendBuffer(ResponseBuffer);
                CNetManager::GetInstancePtr()->PostSendOperation(Connection);
            }
         
        }
        break;
    }
    default:
        CLog::GetInstancePtr()->LogWarn("Unhandled MsgID: %d", MsgID);
        break;
    }
  • 서버쪽 코드를 좀 수정했다. 처음에는 if문으로 bIsValid에 따라 확인했는데, 다른 방법을 사용해서 구현했다.
void UNetworkManager::ProcessResponse(const TArray<uint8>& ReceiveData)
{
	if (ReceiveData.Num() < sizeof(hbServerEngine::PacketHeader))
	{
		return;
	}

	hbServerEngine::PacketHeader* Header = (hbServerEngine::PacketHeader*)ReceiveData.GetData();
	switch (Header->MsgID)
	{
	case EMessageID::LOGIN_RESPONSE_MSG_ID:
	{
		if (Header->Attribute == 0)
		{
			UE_LOG(LogTemp, Log, TEXT("Login successful!"));
			//TODO 로그인 성공
		}
		else if (Header->Attribute == 1)
		{
			UE_LOG(LogTemp, Warning, TEXT("Login failed. Incorrect ID or Password."));
			//TODO 로그인 실패 로직 처리
		}
		StopReceiving();
		break;
	}

	default:
		UE_LOG(LogTemp, Warning, TEXT("Unhandled MsgID: %d"), Header->MsgID);
		break;
	}
}

void UNetworkManager::ReceiveData()
{
	if (ClientSocket)
	{
		ReceiveBuffer.SetNumUninitialized(8192);
		int32 ReceivedDataSize = 0;

		bool bReceive = ClientSocket->Recv(ReceiveBuffer.GetData(), ReceiveBuffer.Num(), ReceivedDataSize,
			ESocketReceiveFlags::None);

		if (bReceive && ReceivedDataSize > 0)
		{
			ReceiveBuffer.SetNum(ReceivedDataSize);
			ProcessResponse(ReceiveBuffer);
		}
		else if (bReceive && ReceivedDataSize == 0)
		{
			// 서버에서 데이터를 아직 보내지 않았거나 수신할 데이터가 없는 경우.
			UE_LOG(LogTemp, Log, TEXT("No data received, but connection is still active."));
		}
		else if (!bReceive)
		{
			// 데이터가 수신되지 않았거나 오류가 발생한 경우
			if (ClientSocket->GetConnectionState() == SCS_Connected)
			{
				// 연결은 유지되고 있지만 데이터가 아직 도착하지 않은 경우
				UE_LOG(LogTemp, Log, TEXT("No data received yet, connection is still valid."));
			}
			else
			{
				// 연결이 끊어진 경우
				UE_LOG(LogTemp, Error, TEXT("Connection lost with server."));
			}
		}
	}
	else
	{
		UE_LOG(LogTemp, Warning, TEXT("ClientSocket is null, cannot receive data."));
	}
	
}

void UNetworkManager::StartReceiving()
{
	if (GetWorld())
	{
		GetWorld()->GetTimerManager().SetTimer(ReceiveTimerHandle, this, &UNetworkManager::ReceiveData, 0.1f, true);
	}
}

void UNetworkManager::StopReceiving()
{
	if (GetWorld())
	{
		GetWorld()->GetTimerManager().ClearTimer(ReceiveTimerHandle);
	}
}
  • NetworkManager.cpp에 새롭게 Receive코드를 구현해주었다.

결과

성공하는 것을 볼 수 있다.(야호)

다음은 클라이언트 움직임을 구현해보도록하겠다.

728x90