C++ Boost Asio - 如何检测断开连接并列出所有活动连接
C++ Boost Asio - How to detect disconnection and make a list of all active connections
我正在使用 Boost asio 作为 TCP 服务器解决方案。我希望我的服务器和客户端通过 TCP 二进制协议进行通信。
这是我的服务器代码:
Server.cpp:
#include "Server.h"
#include "Session.h"
using namespace Vibranium;
void Server::do_accept()
{
acceptor_.async_accept(socket_,
[this](boost::system::error_code ec)
{
if (!ec)
{
std::cout << "Connected!" << std::endl;
std::make_shared<Session>(std::move(socket_))->start();
}
do_accept();
});
}
这里是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)
{
std::cout.write(data_, length);
std::cout << "\n";
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();
}
});
}
这里是 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
以下是我启动服务器的方式:
#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");
std::string defaultPort = "8080";
MySQLConnectionInfo mySqlConnectionInfo(config, "LoginDatabaseInfo");
LoginDatabaseConnection loginDatabaseConnection(mySqlConnectionInfo);
loginDatabaseConnection.LoadDatabase();
try
{
boost::asio::io_service io_service;
Server s(io_service, std::stoi(config.GetConfigValue("AuthServerPort", defaultPort)));
io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
所以我在 Server::do_accept()
中捕获了新连接,很可能我必须在那里填充所有客户端端点的向量。因此,在后期我可以创建一个名为 Send
的函数来发送给特定的客户端,另一个名为 Broadcast
的函数来发送给所有连接的客户端。
下面是两个问题:
- 包含所有连接的向量的类型应该是什么?我应该填在哪里?
- 如何检测断开连接以便从连接的客户端向量中删除客户端?
1.What should be the type of the vector containing all connections? Where should I fill it?
您可以创建一个套接字向量来存储客户端:
vector<tcp::socket> clients; // adding by clients.push_back(move(socket)); after accept'ing
或者在套接字周围创建一些包装器 class 并使用它,例如
class Client
{
tcp::socket socket;
public:
Client (tcp::socket s) : socket{move(s)} {}
... some other logic
并使用vector<Client>
进行存储。
2.How can I detect a disconnection so I can remove a client from that vector of connected clients?
您可以使用 reading/writing 中的第一个失败作为连接断开的指标,或者定期使用某种 KEEP ALIVE 消息(如 ping 消息)来检测断开(或失效)的连接。
我正在使用 Boost asio 作为 TCP 服务器解决方案。我希望我的服务器和客户端通过 TCP 二进制协议进行通信。
这是我的服务器代码:
Server.cpp:
#include "Server.h"
#include "Session.h"
using namespace Vibranium;
void Server::do_accept()
{
acceptor_.async_accept(socket_,
[this](boost::system::error_code ec)
{
if (!ec)
{
std::cout << "Connected!" << std::endl;
std::make_shared<Session>(std::move(socket_))->start();
}
do_accept();
});
}
这里是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)
{
std::cout.write(data_, length);
std::cout << "\n";
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();
}
});
}
这里是 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
以下是我启动服务器的方式:
#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");
std::string defaultPort = "8080";
MySQLConnectionInfo mySqlConnectionInfo(config, "LoginDatabaseInfo");
LoginDatabaseConnection loginDatabaseConnection(mySqlConnectionInfo);
loginDatabaseConnection.LoadDatabase();
try
{
boost::asio::io_service io_service;
Server s(io_service, std::stoi(config.GetConfigValue("AuthServerPort", defaultPort)));
io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
所以我在 Server::do_accept()
中捕获了新连接,很可能我必须在那里填充所有客户端端点的向量。因此,在后期我可以创建一个名为 Send
的函数来发送给特定的客户端,另一个名为 Broadcast
的函数来发送给所有连接的客户端。
下面是两个问题:
- 包含所有连接的向量的类型应该是什么?我应该填在哪里?
- 如何检测断开连接以便从连接的客户端向量中删除客户端?
1.What should be the type of the vector containing all connections? Where should I fill it?
您可以创建一个套接字向量来存储客户端:
vector<tcp::socket> clients; // adding by clients.push_back(move(socket)); after accept'ing
或者在套接字周围创建一些包装器 class 并使用它,例如
class Client
{
tcp::socket socket;
public:
Client (tcp::socket s) : socket{move(s)} {}
... some other logic
并使用vector<Client>
进行存储。
2.How can I detect a disconnection so I can remove a client from that vector of connected clients?
您可以使用 reading/writing 中的第一个失败作为连接断开的指标,或者定期使用某种 KEEP ALIVE 消息(如 ping 消息)来检测断开(或失效)的连接。