#c #boost
#c #boost
Вопрос:
У меня есть реализация Boost Assio в моем проекте. Вот оно:
Session.h:
#ifndef VIBRANIUM_CORE_SESSION_H
#define VIBRANIUM_CORE_SESSION_H
#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
namespace Vibranium{
class Session
: public std::enable_shared_from_this<Session>
{
public:
Session(tcp::socket socket)
: socket_(std::move(socket))
{
}
void start();
private:
void do_read();
void do_write(std::size_t length);
tcp::socket socket_;
enum { max_length = 1024 };
char data_[max_length];
};
}
#endif //VIBRANIUM_CORE_SESSION_H
Session.cpp:
#include "Session.h"
void Vibranium::Session::start() {
do_read();
}
void Vibranium::Session::do_read() {
auto self(shared_from_this());
socket_.async_read_some(boost::asio::buffer(data_, max_length),
[this, self](boost::system::error_code ec, std::size_t length)
{
if (!ec)
{
do_write(length);
}
});
}
void Vibranium::Session::do_write(std::size_t length) {
auto self(shared_from_this());
boost::asio::async_write(socket_, boost::asio::buffer(data_, length),
[this, self](boost::system::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
do_read();
}
});
}
Server.h:
#ifndef VIBRANIUM_CORE_SERVER_H
#define VIBRANIUM_CORE_SERVER_H
#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
namespace Vibranium{
class Server {
public:
Server(boost::asio::io_contextamp; io_context, short port)
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
{
do_accept();
}
private:
void do_accept();
tcp::acceptor acceptor_;
};
}
Server.cpp:
#include "Server.h"
#include "Session.h"
using namespace Vibranium;
void Server::do_accept() {
acceptor_.async_accept([this](boost::system::error_code ec, tcp::socket socket)
{
if (!ec)
{
std::make_shared<Session>(std::move(socket))->start();
}
do_accept();
});
}
И вот как я запускаю сервер:
#include "Config.h"
#include "Database/MySQLConnection.h"
#include "Implementation/LoginDatabase.h"
#include "Banner.h"
#include "Server/Server.h"
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
using namespace std;
using namespace Vibranium;
int main() {
//Don't mind Logger::FatalError it's just for coloring!
Banner::Show(Logger::Error,"AuthServer");
Config config("AuthServer");
MySQLConnectionInfo mySqlConnectionInfo(config, "LoginDatabaseInfo");
LoginDatabaseConnection loginDatabaseConnection(mySqlConnectionInfo);
loginDatabaseConnection.LoadDatabase();
try
{
boost::asio::io_context io_context;
Server s(io_context, 8080);
io_context.run();
}
catch (std::exceptionamp; e)
{
std::cerr << "Exception: " << e.what() << "n";
}
std::cout << "Server Started!" << std::endl;
return 0;
}
У меня есть несколько вопросов:
- Когда я запускаю сервер, я не вижу сообщения «Сервер запущен!». Я подозреваю, что это потому, что он блокирует мой текущий поток. Как я могу запустить TCP-сервер в другом потоке? Должно ли это быть в отдельном потоке или ?
- Пример, который я реализовал, просто возвращает обратно то, что отправлено на сервер. Можете ли вы предложить какой-либо пример того, как я могу различать разные сообщения о событиях? Чего я хочу добиться, так это чего-то вроде того, когда я отправил сообщение, начинающееся с 0x001, чтобы указать, что это сообщение чата, например, или когда сообщение начинается с 0x002, мой сервер знает, что клиент сообщает, что кто-то вышел из системы.
- Я думаю, что Boost Assio использует двоичный протокол поверх TCP. Я прав?
- Можете ли вы показать мне, как я могу отправлять структуры по TCP с помощью двоичного протокола?
Если вопросов слишком много, пожалуйста, рассмотрите только вопрос 1.
Ответ №1:
1. Когда я запускаю сервер, я не вижу сообщения «Сервер запущен!». Я подозреваю, что это потому, что он блокирует мой текущий поток. Как я могу запустить TCP-сервер в другом потоке? Должно ли это быть в отдельном потоке или?
std::cout << "Server Started!" << std::endl;
вызывается после
io_context.run();
io_context.run() будет блокировать, пока есть какие-либо текущие задачи. Вам нужно вызвать «Server Started» перед io_context.run(), возможно, в конструкторе сервера
2. Пример, который я реализовал, просто возвращает обратно то, что отправлено на сервер. Можете ли вы предложить какой-либо пример того, как я могу различать разные сообщения о событиях? Чего я хочу добиться, так это чего-то вроде того, когда я отправлял сообщение, начинающееся с 0x001, чтобы указать, что это сообщение чата, например, или когда сообщение начинается с 0x002, мой сервер знает, что клиент сообщает, что кто-то вышел из системы.
Есть много способов, которыми вы могли бы это сделать, но, например. вы могли бы просто установить поле вашего сообщения для переноса этой информации.
3. Я думаю, что Boost Assio использует двоичный протокол поверх TCP. Я прав?
В вашем случае да, потому что вы используете boost::asio::ip:: tcp, но это не обязательно. Существует также boost::asio::ip::udp для поддержки udp.
4. Можете ли вы показать мне, как я могу отправлять структуры по TCP с помощью двоичного протокола?
Вы могли бы просто реализовать метод сериализации boost для вашего struct шаблона void serialize (архив amp; ar, const unsigned int version). Смотрите пример boost. или предоставьте свою собственную сериализацию (например, в текст) и отправьте эти данные.
Если вы реализуете сериализацию boost, вы можете передать свою структуру напрямую функциям asio, в противном случае вам придется отправлять сериализованные байты.
Извините, но у меня нет времени писать весь код за вас.
Комментарии:
1. Спасибо за ваш подробный ответ. Здесь: boost.org/doc/libs/1_66_0/doc/html/boost_asio/example/cpp03 /… они говорят, что
async_write
это автоматически сериализует данные для меня. Итак, в этом случае мне не нужно беспокоиться о сериализации, верно? Также. Если я отправлю struct A{} с сервера, у меня должна быть точно такая же struct A{} на стороне клиента, я прав?2. Да, но здесь библиотека сериализации boost используется неявно (путем предоставления функции сериализации в void serialize(Archive amp; ar, const unsigned int version в stock.hpp). Оператор amp; в сериализации boost выполняет и то, и другое: сериализует / десериализует, в зависимости от того, является ли входной или выходной поток.
3. @VenelinVasilev В этом примере
connection
объект обеспечивает сериализацию с помощью Boost. Сериализация, но это не часть Asio; это часть примера кода . Asio имеет дело только с протоколами транспортного уровня (т. Е. TCP, UDP); вам решать реализовать любой протокол прикладного уровня, который вы хотите, поверх выбранного вами транспортного протокола.4. Спасибо тебе @StPiere. Можете ли вы привести какой — либо пример того , как сформировать и прочитать пакет заголовка , а не его тело ?
5. Также @StPiere в моем примере. TCP-сервер асинхронный, верно? Это означает, что он может выполнять множество задач параллельно в одно и то же время?