mirror of
https://github.com/kierankihn/uno-game.git
synced 2025-12-27 02:13:18 +08:00
feat(network): add NetworkServer for managing player sessions and communication
- Implemented `NetworkServer` and `Session` classes for handling TCP communication with players. - Added `NetworkServer.cpp` and `NetworkServer.h` to the project. - Integrated `asio` library into the build configuration in `CMakeLists.txt`.
This commit is contained in:
@@ -5,6 +5,7 @@ set(CMAKE_CXX_STANDARD 26)
|
||||
|
||||
find_package(ftxui CONFIG REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
find_package(asio REQUIRED)
|
||||
|
||||
add_library(uno-game-lib
|
||||
src/game/Card.cpp
|
||||
@@ -14,6 +15,7 @@ add_library(uno-game-lib
|
||||
src/common/Utils.cpp
|
||||
src/network/Message.cpp
|
||||
src/network/MessageSerializer.cpp
|
||||
src/network/NetworkServer.cpp
|
||||
)
|
||||
target_link_libraries(uno-game-lib
|
||||
PRIVATE ftxui::screen
|
||||
@@ -23,6 +25,9 @@ target_link_libraries(uno-game-lib
|
||||
target_link_libraries(uno-game-lib
|
||||
PRIVATE nlohmann_json::nlohmann_json
|
||||
)
|
||||
target_link_libraries(uno-game-lib
|
||||
PRIVATE asio::asio
|
||||
)
|
||||
|
||||
add_executable(uno-game src/main.cpp)
|
||||
target_link_libraries(uno-game
|
||||
|
||||
89
src/network/NetworkServer.cpp
Normal file
89
src/network/NetworkServer.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @file NetworkServer.cpp
|
||||
*
|
||||
* @author Yuzhe Guo
|
||||
* @date 2025.11.25
|
||||
*/
|
||||
#include "NetworkServer.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace UNO::NETWORK {
|
||||
Session::Session(size_t player_id, asio::ip::tcp::socket socket) : player_id_(player_id), socket_(std::move(socket)) {}
|
||||
|
||||
void Session::start(std::function<void(size_t, std::string)> callback)
|
||||
{
|
||||
this->callback_ = std::move(callback);
|
||||
read();
|
||||
}
|
||||
|
||||
void Session::send(const std::string &message)
|
||||
{
|
||||
auto buffer = std::make_shared<std::string>(message);
|
||||
asio::async_write(socket_, asio::buffer(*buffer), [this, self = shared_from_this(), buffer](const asio::error_code &ec, size_t) {
|
||||
if (ec) {}
|
||||
});
|
||||
}
|
||||
|
||||
void Session::read()
|
||||
{
|
||||
size_t messageLength;
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(&messageLength, sizeof(messageLength)),
|
||||
[this, self = shared_from_this(), messageLength](const asio::error_code &ec, size_t length) {
|
||||
if (!ec) {
|
||||
if (messageLength > 0 && messageLength <= 10 * 1024 * 1024) {
|
||||
this->readBody(messageLength);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Session::readBody(size_t length)
|
||||
{
|
||||
auto buffer = std::make_shared<std::vector<char>>(length);
|
||||
asio::async_read(
|
||||
socket_, asio::buffer(*buffer), [this, self = shared_from_this(), buffer](const asio::error_code &ec, size_t length) {
|
||||
if (!ec) {
|
||||
std::string message = {buffer->begin(), buffer->end()};
|
||||
this->callback_(this->player_id_, message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NetworkServer::accept()
|
||||
{
|
||||
this->acceptor_.async_accept([this](const asio::error_code &ec, asio::ip::tcp::socket socket) {
|
||||
if (!ec) {
|
||||
this->addPlayer(std::move(socket));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
NetworkServer::NetworkServer(uint16_t port, std::function<void(size_t, std::string)> callback) :
|
||||
acceptor_(io_context_, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)), playerCount(0), callback_(std::move(callback))
|
||||
{
|
||||
}
|
||||
|
||||
void NetworkServer::addPlayer(asio::ip::tcp::socket socket)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->mutex_);
|
||||
this->sessions_[this->playerCount] = std::make_shared<Session>(playerCount, std::move(socket));
|
||||
this->sessions_[this->playerCount]->start(callback_);
|
||||
this->playerCount++;
|
||||
}
|
||||
|
||||
void NetworkServer::send(size_t id, const std::string &message)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->mutex_);
|
||||
if (this->sessions_.contains(id) == false) {
|
||||
throw std::invalid_argument("Player session not found");
|
||||
}
|
||||
this->sessions_[id]->send(message);
|
||||
}
|
||||
|
||||
void NetworkServer::run()
|
||||
{
|
||||
this->io_context_.run();
|
||||
}
|
||||
} // namespace UNO::NETWORK
|
||||
77
src/network/NetworkServer.h
Normal file
77
src/network/NetworkServer.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @file NetworkServer.h
|
||||
*
|
||||
* @author Yuzhe Guo
|
||||
* @date 2025.11.25
|
||||
*/
|
||||
#pragma once
|
||||
#include "Message.h"
|
||||
|
||||
|
||||
#include <asio.hpp>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace UNO::NETWORK {
|
||||
|
||||
class Session : public std::enable_shared_from_this<Session> {
|
||||
private:
|
||||
size_t player_id_;
|
||||
asio::ip::tcp::socket socket_;
|
||||
std::function<void(size_t, std::string)> callback_;
|
||||
|
||||
public:
|
||||
Session(size_t player_id, asio::ip::tcp::socket socket);
|
||||
|
||||
/**
|
||||
* 开始从网络读取消息
|
||||
* @param callback 回调函数
|
||||
*/
|
||||
void start(std::function<void(size_t, std::string)> callback);
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
* @param message 要发送的消息
|
||||
*/
|
||||
void send(const std::string &message);
|
||||
|
||||
private:
|
||||
void read();
|
||||
void readBody(size_t length);
|
||||
};
|
||||
|
||||
class NetworkServer {
|
||||
private:
|
||||
asio::io_context io_context_;
|
||||
asio::ip::tcp::acceptor acceptor_;
|
||||
size_t playerCount;
|
||||
std::map<size_t, std::shared_ptr<Session>> sessions_;
|
||||
std::function<void(size_t, std::string)> callback_;
|
||||
std::mutex mutex_;
|
||||
|
||||
public:
|
||||
explicit NetworkServer(uint16_t port, std::function<void(size_t, std::string)> callback);
|
||||
|
||||
/**
|
||||
* 添加玩家
|
||||
* @param socket 玩家的连接 socket
|
||||
*/
|
||||
void addPlayer(asio::ip::tcp::socket socket);
|
||||
|
||||
/**
|
||||
* 向玩家发送消息
|
||||
* @param id 要发送到的玩家 id
|
||||
* @param message 要发送的消息
|
||||
*/
|
||||
void send(size_t id, const std::string &message);
|
||||
|
||||
/**
|
||||
* 开始网络进程
|
||||
*/
|
||||
void run();
|
||||
|
||||
private:
|
||||
void accept();
|
||||
};
|
||||
|
||||
} // namespace UNO::NETWORK
|
||||
Reference in New Issue
Block a user