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