일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- suffix return type
- virtual function table
- conversion constructor
- placement new
- this call
- C++
- diamond inheritance
- std::vector
- constructor
- virtual function
- pointer to member data
- operator overloading
- c++ basic practice
- vector size
- member function pointer
- delete function
- base from member
- new&delete
- std::endl
- increment operator
- discord bot
- virtual inheritance
- std::cout
- return by reference
- 더 지니어스 양면포커
- std::ostream
- dynamic_cast
- virtual destructor
- c++ multi chatting room
- vector capacity
- Today
- Total
I'm FanJae.
[Two Faced Poker] Day 4. 방에 아이디 정보나 준비 상태 정보를 받아오기 본문
[Two Faced Poker] Day 4. 방에 아이디 정보나 준비 상태 정보를 받아오기
FanJae 2024. 10. 16. 23:331. 결과물
- 상대방이 접속하면 ID와 준비 여부가 나오도록 처리했다.
- 생각보다 이 과정에서 고전을 많이했다.
(준비중)
2. 서버 처리
① Getter() 추가
static std::map<std::string, std::set<SOCKET>> chatRooms;
static std::map<std::string, int> Room_count;
const std::map<std::string, std::set<SOCKET>>& GetChatRooms() {
return chatRooms;
}
const std::map<std::string, int>& GetRoomCounts() {
return Room_count;
}
- GameManager에서 사용할 용도로 getter를 만들기로 했다.
- static 특성을 그대로 유지하기 위해서이다.
② 방에 유저가 입장했을 때, 기존 유저가 새로 들어온 유저의 ID 값을 얻어오기
for (SOCKET target_socket : chatRooms[this->roomName])
{
if (socket != target_socket)
{
join_message = this->ID + " Joined.";
send(target_socket, join_message.c_str(), join_message.length(), 0);
join_message = GAME_CLIENT_EVENT + LOAD_PLAYER + this->ID;
std::cout << join_message << std::endl;
send(target_socket, join_message.c_str(), join_message.length(), 0);
}
}
③ 방에 유저가 입장했을 때, 그 유저가 방에 있던 유저의 ID 값을 얻어오기
- 여기서 생각했던 것은 크게 2가지였다. ① 서버가 유저 ID 관리 ② 접속한 클라이언트가 ID를 보내는 방식
- 나의 경우는 ②로 한번 처리해보았다. 특별한 이유가 있다기 보다는 이 방법을 써본적이 없어서 말이다.
- 다만 이 방법을 사용할 경우 ID의 무결성 확인이 필요하다. (Client 변조를 방지한다.)
- 나의 경우 서버가 ID를 만들기 때문에 이 방법을 통해 임의로 ID를 변조하지 않도록 처리하고자 한다.
※ 이 부분에 대해서는 별도 포스트에서 따로 추가해보려고 한다.
private void Pre_Call()
{
string request = Constants.GAME_CLIENT_EVENT + Constants.GAME_PRE_CALL;
byte[] buffer = Encoding.UTF8.GetBytes(request);
socket.Send(buffer);
}
- Client에서 채팅방 입장 시점(Client를 기준으로는 객체가 생성되는 시점)에서 Pre_Call()을 호출한다.
- 이것이 호출되면, 해당 방에 기존에 있던 유저에 대해서 GAME_PRE_LOAD_PLAYER라는 이벤트를 보낸다.
void Game_Manager::Handle_Game_Pre_Call(const SOCKET& socket, const std::string& message)
{
const auto& rooms = GetChatRooms();
const auto& room_counts = GetRoomCounts();
auto targetRoom = rooms.find(this->roomName);
auto targetRoom_count = room_counts.find(this->roomName);
std::string join_message;
for (SOCKET target_socket : targetRoom->second)
{
if (socket != target_socket && targetRoom_count->second > 1)
{
join_message = GAME_CLIENT_EVENT + GAME_PRE_LOAD_PLAYER;
std::cout << join_message << std::endl;
send(target_socket, join_message.c_str(), join_message.length(), 0);
}
}
}
- 방에 기존에 있던 유저가 서버 쪽으로 메시지를 보내준다.
- 이 정보를 토대로 기존 방에 있던 유저에 대한 정보를 처리해준다.
else if (message.Length >= Constants.GAME_CLIENT_EVENT.Length + Constants.GAME_PRE_LOAD_PLAYER.Length && message.Substring(Constants.GAME_CLIENT_EVENT.Length, Constants.GAME_PRE_LOAD_PLAYER.Length) == Constants.GAME_PRE_LOAD_PLAYER)
{
string request = Constants.GAME_CLIENT_EVENT + Constants.GAME_PRE_LOAD_ID + My_ID_Label.Text.Substring(6);
byte[] buffer = Encoding.UTF8.GetBytes(request);
socket.Send(buffer);
if (My_Ready.Text == "<준비>")
{
request = Constants.GAME_CLIENT_EVENT + Constants.GAME_PRE_LOAD_READY;
buffer = Encoding.UTF8.GetBytes(request);
socket.Send(buffer);
}
else
{
request = Constants.GAME_CLIENT_EVENT + Constants.GAME_PRE_LOAD_DONE;
buffer = Encoding.UTF8.GetBytes(request);
socket.Send(buffer);
}
}
- Client에서 이와 같이 보내주면 Server에서 이를 다음과 같이 처리한다.
- 이 정보를 보내준 소켓이 아닌 다른 소켓(방을 새롭게 입장한 녀석)에게 보내준다.
void Game_Manager::Handle_Game_Pre_Load(const SOCKET& socket, const std::string& message)
{
const auto& rooms = GetChatRooms();
auto it = rooms.find(this->roomName);
std::string send_message = "";
if (message.substr(0, 3) == "ID ")
{
send_message = GAME_CLIENT_EVENT + GAME_PRE_LOAD_ID_DONE + message.substr(3);
std::cout << send_message << std::endl;
}
else if (message.substr(0, 5) == "READY")
{
send_message = GAME_CLIENT_EVENT + GAME_PRE_LOAD_READY_DONE;
std::cout << send_message << std::endl;
}
else if (message.substr(0, 4) == "Done")
{
send_message = GAME_CLIENT_EVENT + GAME_PRE_LOAD_DONE_DONE;
std::cout << send_message.length() << std::endl;
std::cout << send_message << std::endl;
}
for (SOCKET target_socket : it->second)
{
if (socket != target_socket)
{
send(target_socket, send_message.c_str(), send_message.length(), 0);
}
}
}
- Client에서는 이와 같이 받아서 사용이 가능하다.
else if (message.Length >= Constants.GAME_CLIENT_EVENT.Length + Constants.GAME_PRE_LOAD_ID_DONE.Length && message.Substring(Constants.GAME_CLIENT_EVENT.Length, Constants.GAME_PRE_LOAD_ID_DONE.Length) == Constants.GAME_PRE_LOAD_ID_DONE)
{
Invoke(new Action(() =>
{
Vs_ID_Label.Text = "ID : " + message.Substring(Constants.GAME_CLIENT_EVENT.Length + Constants.GAME_PRE_LOAD_ID_DONE.Length);
}));
}
else if (message.Substring(Constants.GAME_CLIENT_EVENT.Length) == Constants.GAME_PRE_LOAD_READY_DONE)
{
Invoke(new Action(() =>
{
Vs_Ready.Text = "<준비>";
}));
}
else if (message.Substring(Constants.GAME_CLIENT_EVENT.Length) == Constants.GAME_PRE_LOAD_DONE_DONE)
{
Invoke(new Action(() =>
{
Vs_Ready.Text = "<완료>";
}));
}
3. TODO
1) Server
- 게임 로직 처리 (카드 비교 및 베팅에 따른 정보 처리 등)
- Client 패킷 검증 필요 (ID 변조 체크)
2) Client
- 게임 로직 처리
'Toy Project > Two Faced Poker' 카테고리의 다른 글
[Two Faced Poker] Day 5. Server 리팩토링 II. 서버 리팩토링에 따른 Client 대공사 (5) | 2024.10.20 |
---|---|
[Two Faced Poker] Day 5. Server 리팩토링 I. 대공사 (0) | 2024.10.17 |
[Two Faced Poker] Day 3. Server 방 인원수 제한 및 GameManager 추가, Client GUI 버튼 추가 (1) | 2024.10.15 |
[Two Faced Poker] Day 2. Server 로직 개선 및 Client Game 판 구성. (2) | 2024.10.14 |
[Two Faced Poker] Day 1. 일부 기능 추가 및 Client 로직 개선 (7) | 2024.10.08 |