sword_game/server/Session.cpp

110 lines
3.4 KiB
C++

#include "Session.h"
#include "PacketHandler.h"
#include "SessionManager.h"
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <cstring>
Session::Session(tcp::socket socket) : socket_(std::move(socket)) {}
Session::~Session() {
// 필요한 경우 정리 작업 수행
}
void Session::SetNickname(const std::string &nickname) { nickname_ = nickname; }
const std::string &Session::GetNickname() const { return nickname_; }
void Session::SetGold(uint64_t gold) { gold_ = gold; }
uint64_t Session::GetGold() const { return gold_; }
void Session::SetSwordLevel(uint32_t level) { swordLevel_ = level; }
uint32_t Session::GetSwordLevel() const { return swordLevel_; }
void Session::Start() { DoReadHeader(); }
void Session::SendPacket(PacketID id) {
PacketHeader header;
header.id = static_cast<uint16_t>(id);
header.size = 0;
std::vector<uint8_t> buffer(sizeof(PacketHeader));
std::memcpy(buffer.data(), &header, sizeof(PacketHeader));
Send(buffer);
}
void Session::Send(std::span<const uint8_t> data) {
auto self(shared_from_this());
boost::asio::post(
socket_.get_executor(),
[this, self,
msg = std::vector<uint8_t>(data.begin(), data.end())]() mutable {
bool writeInProgress = !writeQueue_.empty();
writeQueue_.push_back(std::move(msg));
if (!writeInProgress) {
DoWrite();
}
});
}
void Session::DoReadHeader() {
auto self(shared_from_this());
boost::asio::async_read(
socket_, boost::asio::buffer(&packetHeader_, sizeof(PacketHeader)),
[this, self](boost::system::error_code ec, std::size_t /*length*/) {
if (!ec) {
// 바디 크기 결정
// 안전 확인: 메모리 고갈을 방지하기 위해 최대 패킷 크기 제한
if (packetHeader_.size > 1024 * 10) {
socket_.close();
return;
}
packetBody_.resize(packetHeader_.size);
DoReadBody();
} else {
// 연결 끊김 또는 에러 발생 시 매니저에서 제거
SessionManager::GetInstance().Leave(self);
}
});
}
void Session::DoReadBody() {
auto self(shared_from_this());
boost::asio::async_read(
socket_, boost::asio::buffer(packetBody_.data(), packetBody_.size()),
[this, self](boost::system::error_code ec, std::size_t /*length*/) {
if (!ec) {
Packet packet;
packet.header = packetHeader_;
packet.payload = packetBody_;
// 패킷 핸들러 코루틴 실행
boost::asio::co_spawn(
socket_.get_executor(),
PacketHandler::HandlePacket(self, std::move(packet)),
boost::asio::detached);
// 계속해서 읽기
DoReadHeader();
} else {
// 에러 발생 시 매니저에서 제거
SessionManager::GetInstance().Leave(self);
}
});
}
void Session::DoWrite() {
auto self(shared_from_this());
boost::asio::async_write(
socket_, boost::asio::buffer(writeQueue_.front()),
[this, self](boost::system::error_code ec, std::size_t /*length*/) {
if (!ec) {
writeQueue_.pop_front();
if (!writeQueue_.empty()) {
DoWrite();
}
} else {
// 에러 발생 시 매니저에서 제거
SessionManager::GetInstance().Leave(self);
}
});
}