본문 바로가기
개인공부/IOCP 서버 제작 실습

IOCP 서버 제작 실습 9

by 하고싶은건많은놈 2023. 3. 27.

서버 접속 및 로그인, 채팅방 접속, 채팅

 

채팅방 퇴장, 로그아웃, 접속해제 및 오류시 처리

추가로 로그아웃 기능을 구현

 

  • Logout 로직
    • 기본적인 작동 방식은 Login과 동일
      1. [PacketManager] LOGOUT_REQUEST 패킷을 받아 ProcessLogout() 함수 호출, REQUEST_LOGOUT Task를 생성
      2. [RedisManager] REQUEST_LOGOUT Task를 받아 ProcessLogout() 함수 호출, RESPONSE_LOGOUT 패킷을 생성
      3. [PacketManager] REQUEST_LOGOUT 패킷을 받으면 ProcessLogoutDBResult() 함수를 호출
        유저가 Room에 들어가있는 상태라면 RoomManager의 LeaveUser() 함수를 호출하여 Room에서 제거
        유저 정보도 UserManager의 DelUser() 함수를 호출하여 리스트에서 제거
    • Reference로 사용한 클라이언트에도 Logout 버튼을 추가하는 등의 수정을 가함

 


 

 

  • PakcetManager.h / cpp
void PacketManager::ProcessLogout(UINT32 clientIndex_, UINT16 packetSize_, char* pPacket_)
{
	std::cout << "********Logout Request*********\n";

	if (LOGOUT_REQUEST_PACKET_SIZE != packetSize_)
	{
		return;
	}

	auto pLogoutReqPacket = reinterpret_cast<LOGOUT_REQUEST_PACKET*>(pPacket_);

	auto pUserID = pLogoutReqPacket->UserID;

	LOGOUT_RESPONSE_PACKET logoutResPacket;
	logoutResPacket.PacketId = (UINT16)PACKET_ID::LOGOUT_RESPONSE;
	logoutResPacket.PacketLength = sizeof(LOGOUT_RESPONSE_PACKET);

	RedisLogoutReq dbReq;
	CopyMemory(dbReq.UserID, pLogoutReqPacket->UserID, (MAX_USER_ID_LEN + 1));

	RedisTask task;
	task.UserIndex = clientIndex_;
	task.TaskId = (UINT16)RedisTaskID::REQUEST_LOGOUT;
	task.DataSize = sizeof(RedisLogoutReq);
	task.pData = new char[task.DataSize];

	CopyMemory(task.pData, (char*)&dbReq, task.DataSize);
	mRedisManager->PushRequest(task);
}

void PacketManager::ProcessLogoutDBResult(UINT32 clientIndex_, UINT16 packetSize_, char* pPacket_)
{
	auto pBody = (RedisLogoutRes*)pPacket_;
	std::string userId_ = pBody->UserID;

	LOGOUT_RESPONSE_PACKET logoutResPacket;
	logoutResPacket.PacketId = (UINT16)PACKET_ID::LOGOUT_RESPONSE;
	logoutResPacket.PacketLength = sizeof(LOGOUT_RESPONSE_PACKET);
	logoutResPacket.Result = pBody->Result;

	if (pBody->Result == (UINT16)ERROR_CODE::NONE)
	{
		if (mUserManager->FindUserIndexByID(pBody->UserID) != -1)
		{
			auto user_ = mUserManager->GetUserByConnIdx(clientIndex_);
			if (user_->GetDomainState() == User::DOMAIN_STATE::ROOM)
			{
				auto roomnumber_ = user_->GetCurrentRoom();
				mRoomManager->LeaveUser(roomnumber_, user_);
			}

			mUserManager->DelUser(pBody->UserID, clientIndex_);

			std::cout << "User " << userId_ << " Logout Success!\n";
		}
		else
			logoutResPacket.Result = (UINT16)ERROR_CODE::LOGIN_USER_NOT_FIND;
	}

	SendPacketFunc(clientIndex_, sizeof(LOGOUT_RESPONSE_PACKET), (char*)&logoutResPacket);
}

 

 

  • RedisManager.h
void ProcessLogout(UINT32 userIndex_, UINT16 dataSize_, char* pData_)
{
    auto pRequest = (RedisLoginReq*)pData_;

    RedisLogoutRes bodyData;
    bodyData.Result = (UINT16)ERROR_CODE::NONE;
    CopyMemory(bodyData.UserID, pRequest->UserID, (MAX_USER_ID_LEN + 1));

    std::string value;
    if (mConn.get(pRequest->UserID, value) == -1)
    {
        bodyData.Result = (UINT16)ERROR_CODE::LOGIN_USER_NOT_FIND;
    }

    RedisTask resTask;
    resTask.UserIndex = userIndex_;
    resTask.TaskId = (UINT16)RedisTaskID::RESPONSE_LOGOUT;
    resTask.DataSize = sizeof(RedisLogoutRes);
    resTask.pData = new char[resTask.DataSize];
    CopyMemory(resTask.pData, (char*)&bodyData, resTask.DataSize);

    PushResponse(resTask);
}

 

 

  • Client에서 추가한 부분
private void button3_Click(object sender, EventArgs e)
{
    var logoutReq = new LogoutReqPacket();
    logoutReq.SetValue(textBoxUserID.Text);

    PostSendPacket(PACKET_ID.LOGOUT_REQ, logoutReq.ToBytes());
    DevLog.Write($"로그아웃 요청:  {textBoxUserID.Text}, {textBoxUserPW.Text}");
}

public class LogoutReqPacket
{
    byte[] UserID = new byte[PacketDef.MAX_USER_ID_BYTE_LENGTH];

    public void SetValue(string userID)
    {
        Encoding.UTF8.GetBytes(userID).CopyTo(UserID, 0);
    }

    public byte[] ToBytes()
    {
        List<byte> dataSource = new List<byte>();
        dataSource.AddRange(UserID);
        return dataSource.ToArray();
    }
}
 
 void PacketProcess_LogoutResponse(byte[] bodyData)
{
    var responsePkt = new LogoutResPacket();
    responsePkt.FromBytes(bodyData);

    DevLog.Write($"로그아웃 결과:  {(ERROR_CODE)responsePkt.Result}");
}

'개인공부 > IOCP 서버 제작 실습' 카테고리의 다른 글

IOCP 서버 제작 실습 10  (1) 2023.03.27
IOCP 서버 제작 실습 8  (0) 2023.03.27
IOCP 서버 제작 실습 7  (0) 2023.03.25
IOCP 서버 제작 실습 6  (0) 2023.03.23
IOCP 서버 제작 실습 5  (0) 2023.03.23

댓글