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(ftxui CONFIG REQUIRED)
|
||||||
find_package(nlohmann_json REQUIRED)
|
find_package(nlohmann_json REQUIRED)
|
||||||
|
find_package(asio REQUIRED)
|
||||||
|
|
||||||
add_library(uno-game-lib
|
add_library(uno-game-lib
|
||||||
src/game/Card.cpp
|
src/game/Card.cpp
|
||||||
@@ -14,6 +15,7 @@ add_library(uno-game-lib
|
|||||||
src/common/Utils.cpp
|
src/common/Utils.cpp
|
||||||
src/network/Message.cpp
|
src/network/Message.cpp
|
||||||
src/network/MessageSerializer.cpp
|
src/network/MessageSerializer.cpp
|
||||||
|
src/network/NetworkServer.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries(uno-game-lib
|
target_link_libraries(uno-game-lib
|
||||||
PRIVATE ftxui::screen
|
PRIVATE ftxui::screen
|
||||||
@@ -23,6 +25,9 @@ target_link_libraries(uno-game-lib
|
|||||||
target_link_libraries(uno-game-lib
|
target_link_libraries(uno-game-lib
|
||||||
PRIVATE nlohmann_json::nlohmann_json
|
PRIVATE nlohmann_json::nlohmann_json
|
||||||
)
|
)
|
||||||
|
target_link_libraries(uno-game-lib
|
||||||
|
PRIVATE asio::asio
|
||||||
|
)
|
||||||
|
|
||||||
add_executable(uno-game src/main.cpp)
|
add_executable(uno-game src/main.cpp)
|
||||||
target_link_libraries(uno-game
|
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