Compare commits
6 Commits
Author | SHA1 | Date |
---|---|---|
Alexander Zhirov | 17736d56e5 | |
Alexander Zhirov | 089820116b | |
Alexander Zhirov | 7c3a27d64a | |
Alexander Zhirov | e8c1ace236 | |
Alexander Zhirov | 28e33863e4 | |
Alexander Zhirov | aa93763bb4 |
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* ap.cpp
|
||||||
|
*
|
||||||
|
* Created on: 05 сен. 2022 г.
|
||||||
|
* Author: alexander
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ap/ap.hpp>
|
||||||
|
|
||||||
|
namespace ap
|
||||||
|
{
|
||||||
|
|
||||||
|
ConfigOption::ConfigOption(const std::string &longParameter, const char shortParameter, const hasArg ha) :
|
||||||
|
_longParameter(nullptr), _shortParameter(shortParameter), _ha(ha)
|
||||||
|
{
|
||||||
|
_longParameter = new char[longParameter.length() + 1];
|
||||||
|
strcpy(_longParameter, longParameter.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ConfigOption::getLongParameter() const
|
||||||
|
{
|
||||||
|
return _longParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char& ConfigOption::getShortParameter() const
|
||||||
|
{
|
||||||
|
return _shortParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasArg& ConfigOption::getPresenceArgument() const
|
||||||
|
{
|
||||||
|
return _ha;
|
||||||
|
}
|
||||||
|
|
||||||
|
Option::Option() : _set(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Option::set()
|
||||||
|
{
|
||||||
|
_set = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Option::push(const std::string &value)
|
||||||
|
{
|
||||||
|
_values.push_back(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string>& Option::getValues()
|
||||||
|
{
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Option::isSet() const
|
||||||
|
{
|
||||||
|
return _set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hub::_createArguments(const std::vector<ConfigOption> &options, bool silence)
|
||||||
|
{
|
||||||
|
_longOptions = new struct option[options.size() + 1];
|
||||||
|
_sizeOptions = options.size();
|
||||||
|
std::string temp;
|
||||||
|
if (silence)
|
||||||
|
temp.push_back(':');
|
||||||
|
for (auto const &opt : options | boost::adaptors::indexed(0))
|
||||||
|
{
|
||||||
|
_longOptions[opt.index()].name = opt.value().getLongParameter();
|
||||||
|
_longOptions[opt.index()].has_arg = opt.value().getPresenceArgument();
|
||||||
|
_longOptions[opt.index()].flag = nullptr;
|
||||||
|
_longOptions[opt.index()].val = opt.value().getShortParameter();
|
||||||
|
|
||||||
|
temp.push_back(opt.value().getShortParameter());
|
||||||
|
switch (opt.value().getPresenceArgument())
|
||||||
|
{
|
||||||
|
case hasArg::OPTIONAL:
|
||||||
|
temp.push_back(':');
|
||||||
|
/* no break */
|
||||||
|
case hasArg::REQUIRED:
|
||||||
|
temp.push_back(':');
|
||||||
|
break;
|
||||||
|
case hasArg::NO:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_arguments[opt.value().getShortParameter()].first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_longOptions[options.size()].name = nullptr;
|
||||||
|
_longOptions[options.size()].has_arg = 0;
|
||||||
|
_longOptions[options.size()].flag = nullptr;
|
||||||
|
_longOptions[options.size()].val = 0;
|
||||||
|
|
||||||
|
_shortOptions = new char[temp.size() + 1];
|
||||||
|
strcpy(_shortOptions, temp.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
Hub::Hub(const std::vector<ConfigOption> &options, bool silence) :
|
||||||
|
_longOptions(nullptr), _shortOptions(nullptr)
|
||||||
|
{
|
||||||
|
_createArguments(options, silence);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hub::readArguments(int argc, char *argv[], void (*_callback)())
|
||||||
|
{
|
||||||
|
int next_option;
|
||||||
|
while ((next_option = getopt_long(argc, argv, _shortOptions, _longOptions, nullptr)) != -1)
|
||||||
|
{
|
||||||
|
if (_arguments.count(next_option))
|
||||||
|
{
|
||||||
|
_arguments[next_option].first = true;
|
||||||
|
_arguments[next_option].second.set();
|
||||||
|
if (optarg)
|
||||||
|
_arguments[next_option].second.push(std::string(optarg));
|
||||||
|
}
|
||||||
|
if (next_option == '?' && _callback)
|
||||||
|
_callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Option Hub::getOption(char key) const
|
||||||
|
{
|
||||||
|
return _arguments.count(key) && _arguments.at(key).first ? _arguments.at(key).second : Option();
|
||||||
|
}
|
||||||
|
|
||||||
|
Hub::~Hub()
|
||||||
|
{
|
||||||
|
delete[] _shortOptions;
|
||||||
|
for (size_t i = 0; i < _sizeOptions; ++i)
|
||||||
|
{
|
||||||
|
delete[] _longOptions[i].name;
|
||||||
|
}
|
||||||
|
delete[] _longOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* ap.hpp
|
||||||
|
*
|
||||||
|
* Created on: 05 сен. 2022 г.
|
||||||
|
* Author: alexander
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <map>
|
||||||
|
#include <boost/range/adaptors.hpp>
|
||||||
|
|
||||||
|
namespace ap
|
||||||
|
{
|
||||||
|
|
||||||
|
enum hasArg
|
||||||
|
{
|
||||||
|
NO, REQUIRED, OPTIONAL
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<std::string> (*_handler)(const std::vector<std::string>&);
|
||||||
|
|
||||||
|
class ConfigOption
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
char *_longParameter;
|
||||||
|
const char _shortParameter;
|
||||||
|
const hasArg _ha;
|
||||||
|
public:
|
||||||
|
ConfigOption(const std::string &longParameter, const char shortParameter, const hasArg ha);
|
||||||
|
const char* getLongParameter() const;
|
||||||
|
const char& getShortParameter() const;
|
||||||
|
const hasArg& getPresenceArgument() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Option
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::vector<std::string> _values;
|
||||||
|
bool _set;
|
||||||
|
public:
|
||||||
|
Option();
|
||||||
|
void push(const std::string &value);
|
||||||
|
std::vector<std::string>& getValues();
|
||||||
|
void set();
|
||||||
|
bool isSet() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Hub
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
struct option *_longOptions;
|
||||||
|
size_t _sizeOptions;
|
||||||
|
char *_shortOptions;
|
||||||
|
std::map<char, std::pair<bool, Option>> _arguments;
|
||||||
|
void _createArguments(const std::vector<ConfigOption> &options, bool silence);
|
||||||
|
public:
|
||||||
|
Hub(const std::vector<ConfigOption> &options, bool silence = true);
|
||||||
|
void readArguments(int argc, char *argv[], void (*_callback)() = nullptr);
|
||||||
|
Option getOption(char key) const;
|
||||||
|
~Hub();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<cdtprojectproperties>
|
||||||
|
<section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.IncludePaths">
|
||||||
|
<language id="org.eclipse.cdt.core.g++" name="C++ Source File">
|
||||||
|
<includepath workspace_path="true">/${ProjName}</includepath>
|
||||||
|
</language>
|
||||||
|
<language id="org.eclipse.cdt.core.gcc" name="C Source File"/>
|
||||||
|
<language name="Object File"/>
|
||||||
|
<language id="org.eclipse.cdt.core.assembly" name="Assembly Source File"/>
|
||||||
|
</section>
|
||||||
|
<section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.Macros">
|
||||||
|
<language id="org.eclipse.cdt.core.g++" name="C++ Source File"/>
|
||||||
|
<language id="org.eclipse.cdt.core.gcc" name="C Source File"/>
|
||||||
|
<language name="Object File"/>
|
||||||
|
<language id="org.eclipse.cdt.core.assembly" name="Assembly Source File"/>
|
||||||
|
</section>
|
||||||
|
</cdtprojectproperties>
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* tcp_client.cpp
|
||||||
|
*
|
||||||
|
* Created on: 21 сент. 2022 г.
|
||||||
|
* Author: alexander
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <client/tcp_client.hpp>
|
||||||
|
|
||||||
|
namespace azh
|
||||||
|
{
|
||||||
|
TCPClient::TCPClient()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* tcp_client.hpp
|
||||||
|
*
|
||||||
|
* Created on: 21 сент. 2022 г.
|
||||||
|
* Author: alexander
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace azh
|
||||||
|
{
|
||||||
|
|
||||||
|
class TCPClient
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TCPClient();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* tcp_connection.cpp
|
||||||
|
*
|
||||||
|
* Created on: 20 сент. 2022 г.
|
||||||
|
* Author: alexander
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <connection/tcp_connection.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace azh
|
||||||
|
{
|
||||||
|
TCPConnection::TCPConnection(io::ip::tcp::socket&& socket) : _socket(std::move(socket))
|
||||||
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
|
||||||
|
std::stringstream name;
|
||||||
|
name << _socket.remote_endpoint();
|
||||||
|
|
||||||
|
_username = name.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp::socket& TCPConnection::socket()
|
||||||
|
{
|
||||||
|
return _socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::start(MessageHandler&& messageHandler, ErrorHandler&& errorHandler)
|
||||||
|
{
|
||||||
|
_messageHandler = std::move(messageHandler);
|
||||||
|
_errorHandler = std::move(errorHandler);
|
||||||
|
|
||||||
|
asyncRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::post(const std::string& message)
|
||||||
|
{
|
||||||
|
bool queueIdle = _outgoingMessages.empty();
|
||||||
|
_outgoingMessages.push(message);
|
||||||
|
|
||||||
|
if (queueIdle)
|
||||||
|
asyncWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::asyncRead()
|
||||||
|
{
|
||||||
|
io::async_read_until(_socket, _streamBuf, '\n', [self = shared_from_this()]
|
||||||
|
(boost::system::error_code ec, size_t bytesTransferred) {
|
||||||
|
self->onRead(ec, bytesTransferred);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::onRead(boost::system::error_code &ec, size_t bytesTransferred)
|
||||||
|
{
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
_socket.close(ec);
|
||||||
|
|
||||||
|
_errorHandler();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream message;
|
||||||
|
message << _username << ": " << std::istream(&_streamBuf).rdbuf();
|
||||||
|
|
||||||
|
_streamBuf.consume(bytesTransferred);
|
||||||
|
|
||||||
|
_messageHandler(message.str());
|
||||||
|
|
||||||
|
asyncRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::asyncWrite()
|
||||||
|
{
|
||||||
|
io::async_write(_socket, io::buffer(_outgoingMessages.front()), [self = shared_from_this()]
|
||||||
|
(boost::system::error_code ec, size_t bytesTransferred) {
|
||||||
|
self->onWrite(ec, bytesTransferred);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::onWrite(boost::system::error_code &ec, size_t bytesTransferred)
|
||||||
|
{
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
_socket.close(ec);
|
||||||
|
|
||||||
|
_errorHandler();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_outgoingMessages.pop();
|
||||||
|
|
||||||
|
if (!_outgoingMessages.empty())
|
||||||
|
asyncWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
TCPConnection::Pointer TCPConnection::create(io::ip::tcp::socket&& socket)
|
||||||
|
{
|
||||||
|
return Pointer(new TCPConnection(std::move(socket)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* tcp_connection.hpp
|
||||||
|
*
|
||||||
|
* Created on: 20 сент. 2022 г.
|
||||||
|
* Author: alexander
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
namespace azh
|
||||||
|
{
|
||||||
|
using boost::asio::ip::tcp;
|
||||||
|
namespace io = boost::asio;
|
||||||
|
|
||||||
|
using MessageHandler = std::function<void(std::string)>;
|
||||||
|
using ErrorHandler = std::function<void()>;
|
||||||
|
|
||||||
|
class TCPConnection : public std::enable_shared_from_this<TCPConnection>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Pointer = std::shared_ptr<TCPConnection>;
|
||||||
|
|
||||||
|
static Pointer create(io::ip::tcp::socket&& socket);
|
||||||
|
|
||||||
|
inline const std::string& getUsername() const
|
||||||
|
{
|
||||||
|
return _username;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp::socket& socket();
|
||||||
|
void start(MessageHandler&& messageHandler, ErrorHandler&& errorHandler);
|
||||||
|
|
||||||
|
void post(const std::string& message);
|
||||||
|
private:
|
||||||
|
tcp::socket _socket;
|
||||||
|
std::string _username;
|
||||||
|
|
||||||
|
std::queue<std::string> _outgoingMessages;
|
||||||
|
io::streambuf _streamBuf {65536};
|
||||||
|
|
||||||
|
MessageHandler _messageHandler;
|
||||||
|
ErrorHandler _errorHandler;
|
||||||
|
private:
|
||||||
|
explicit TCPConnection(io::ip::tcp::socket&& socket);
|
||||||
|
|
||||||
|
void asyncRead();
|
||||||
|
void onRead(boost::system::error_code &ec, size_t bytesTransferred);
|
||||||
|
|
||||||
|
void asyncWrite();
|
||||||
|
void onWrite(boost::system::error_code &ec, size_t bytesTransferred);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
#include <ap/ap.hpp>
|
||||||
|
#include <server/tcp_server.hpp>
|
||||||
|
#include <connection/tcp_connection.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
void server(int port)
|
||||||
|
{
|
||||||
|
using namespace azh;
|
||||||
|
|
||||||
|
TCPServer server(IPV::V4, port);
|
||||||
|
|
||||||
|
server.onJoin = [](TCPConnection::Pointer server)
|
||||||
|
{
|
||||||
|
std::cout << "User has joined the server " << server->getUsername() << std::endl;
|
||||||
|
};
|
||||||
|
|
||||||
|
server.onLeave = [](TCPConnection::Pointer server)
|
||||||
|
{
|
||||||
|
std::cout << "User has left the server " << server->getUsername() << std::endl;
|
||||||
|
};
|
||||||
|
|
||||||
|
server.onClientMessage = [&server](const std::string& message)
|
||||||
|
{
|
||||||
|
server.broadcast(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
server.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
ap::Hub hub( { { "port", 'p', ap::REQUIRED }, { "host", 'h', ap::OPTIONAL }, { "server", 's', ap::NO }, { "client", 'c', ap::NO } });
|
||||||
|
hub.readArguments(argc, argv);
|
||||||
|
|
||||||
|
auto optionPort = hub.getOption('p');
|
||||||
|
if (!optionPort.isSet())
|
||||||
|
{
|
||||||
|
std::cerr << "Порт не был установлен!" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int port = std::stoi(optionPort.getValues()[0]);
|
||||||
|
|
||||||
|
auto optionClient = hub.getOption('c');
|
||||||
|
auto optionServer = hub.getOption('s');
|
||||||
|
|
||||||
|
if (optionClient.isSet())
|
||||||
|
{
|
||||||
|
auto optionHost = hub.getOption('h');
|
||||||
|
if (!optionHost.isSet())
|
||||||
|
{
|
||||||
|
std::cerr << "Адрес не был установлен!" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto host = optionHost.getValues()[0];
|
||||||
|
|
||||||
|
// client(port, host);
|
||||||
|
}
|
||||||
|
else if (optionServer.isSet())
|
||||||
|
server(port);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "Необходимо установить режим запуска:" << std::endl << "\t-c\t--client\tЗапуск в режиме клиента" << std::endl
|
||||||
|
<< "\t-s\t--server\tЗапуск в режиме сервера" << std::endl << "\t-h\t--host\t\tУказать IP-адрес сервера" << std::endl
|
||||||
|
<< "\t-p\t--port\t\tУказать порт" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* tcp_server.cpp
|
||||||
|
*
|
||||||
|
* Created on: 20 сент. 2022 г.
|
||||||
|
* Author: alexander
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <connection/tcp_connection.hpp>
|
||||||
|
#include <server/tcp_server.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace azh
|
||||||
|
{
|
||||||
|
using boost::asio::ip::tcp;
|
||||||
|
|
||||||
|
TCPServer::TCPServer(IPV ipv, int port) : _ipVersion(ipv), _port(port), _acceptor(_ioContext,
|
||||||
|
tcp::endpoint(_ipVersion == IPV::V4 ? tcp::v4() : tcp::v6(), _port))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int TCPServer::run()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
startAccept();
|
||||||
|
_ioContext.run();
|
||||||
|
}
|
||||||
|
catch (std::exception &e)
|
||||||
|
{
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPServer::broadcast(const std::string &message)
|
||||||
|
{
|
||||||
|
for (auto &connection : _connections)
|
||||||
|
{
|
||||||
|
connection->post(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPServer::startAccept()
|
||||||
|
{
|
||||||
|
_socket.emplace(_ioContext);
|
||||||
|
|
||||||
|
_acceptor.async_accept(*_socket, [this](const boost::system::error_code &error)
|
||||||
|
{
|
||||||
|
auto connection = TCPConnection::create(std::move(*_socket));
|
||||||
|
|
||||||
|
if (onJoin)
|
||||||
|
onJoin(connection);
|
||||||
|
|
||||||
|
_connections.insert(connection);
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
connection->start(
|
||||||
|
[this](const std::string& message)
|
||||||
|
{
|
||||||
|
if (onClientMessage) onClientMessage(message);
|
||||||
|
},
|
||||||
|
[&, weak = std::weak_ptr(connection)]
|
||||||
|
{
|
||||||
|
if (auto shared = weak.lock(); shared && _connections.erase(shared))
|
||||||
|
if (onLeave) onLeave(shared);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
startAccept();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* tcp_server.hpp
|
||||||
|
*
|
||||||
|
* Created on: 20 сент. 2022 г.
|
||||||
|
* Author: alexander
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <connection/tcp_connection.hpp>
|
||||||
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
namespace azh
|
||||||
|
{
|
||||||
|
namespace io = boost::asio;
|
||||||
|
|
||||||
|
enum class IPV
|
||||||
|
{
|
||||||
|
V4, V6
|
||||||
|
};
|
||||||
|
|
||||||
|
class TCPServer
|
||||||
|
{
|
||||||
|
using OnJoinHandler = std::function<void(TCPConnection::Pointer)>;
|
||||||
|
using OnLeaveHandler = std::function<void(TCPConnection::Pointer)>;
|
||||||
|
using OnClientMessageHandler = std::function<void(std::string)>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TCPServer(IPV ipv, int port);
|
||||||
|
|
||||||
|
int run();
|
||||||
|
|
||||||
|
void broadcast(const std::string& message);
|
||||||
|
public:
|
||||||
|
OnJoinHandler onJoin;
|
||||||
|
OnLeaveHandler onLeave;
|
||||||
|
OnClientMessageHandler onClientMessage;
|
||||||
|
private:
|
||||||
|
IPV _ipVersion;
|
||||||
|
int _port;
|
||||||
|
|
||||||
|
io::io_context _ioContext;
|
||||||
|
io::ip::tcp::acceptor _acceptor;
|
||||||
|
std::optional<io::ip::tcp::socket> _socket;
|
||||||
|
std::unordered_set<TCPConnection::Pointer> _connections;
|
||||||
|
private:
|
||||||
|
void startAccept();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue