gpt4 book ai didi

c++ - ASIO 聊天 session 类在销毁时抛出异常 : C++ ASIO

转载 作者:行者123 更新时间:2023-11-30 02:40:57 25 4
gpt4 key购买 nike

我正在使用 ASIO 开发网络应用程序并提到了Chat-Server/Client

我问过类似的问题Here

为了更好地解释,我在这里添加了更多代码:

我的 Cserver Class

class CServer {
private:

mutable tcp::acceptor acceptor_; // only in the listener
asio::io_service& io_;
CSerSessionsManager mng_;

std::string ip_;
std::string port_;

public:

CServer::CServer(asio::io_service& io_service, const std::string IP, const std::string port) : io_(io_service), acceptor_(io_service)
, ip_(IP), port_(port)
{
DEBUG_MSG("Listener Created");
}

~CServer()
{
DEBUG_MSG("Listener Destroyed");
acceptor_.close();
}

void initProtocol()
{
DEBUG_MSG(" Protocol Initiated");
std::array<unsigned char, 4> ip;
std::string delimiter = ".";

//Parse the IP String
size_t pos = 0;
auto i = 0;
std::string token;

while ((pos = ip_.find(delimiter)) != std::string::npos) {
token = ip_.substr(0, pos);
ip[i] = std::stoi(token);//what if stoi fails
i++;
ip_.erase(0, pos + delimiter.length());
}

ip[i] = std::stoi(ip_);


asio::ip::address_v4 address(ip);
tcp::endpoint ep(address, std::stoi(port_));


static std::mutex m;
std::unique_lock<std::mutex> lck(m, std::defer_lock);

//Critical Section start
lck.lock();
acceptor_ = tcp::acceptor(io_, ep);//Creating IOService
lck.unlock();
//Critical Section End

listen();
}


void listen()
{
DEBUG_MSG("!==============================================================!");

////Critical Section
static std::mutex m;
std::lock_guard<std::mutex> lock(m);

sessionPtr newSession = std::make_shared<CSerSession>(io_, mng_);

try
{
acceptor_.async_accept(newSession->socket(), std::bind(&CServer::handle_accept, /*shared_from_this()*/ this, newSession,
std::placeholders::_1));
///*asio::error_code ec;
//pSocket_->shutdown(asio::ip::tcp::socket::shutdown_send, ec);*/
}
catch (const std::bad_weak_ptr& e)
{
DEBUG_MSG(e.what());
throw e;
}

DEBUG_MSG("Listen Activated");
}


void handle_accept(sessionPtr newSession, const asio::error_code& error)
{
if (!acceptor_.is_open())
{
return;
}

if (!error)
{
DEBUG_MSG("Incoming Session accepted");
//Do I need a Lock here?
//Critical Section
static std::mutex m;
std::lock_guard<std::mutex> lock(m);
newSession->startSession();
listen();
}
else
{
DEBUG_MSG("Listen_Error");
// //throw ASIOError(Listen_Error);
DEBUG_MSG(error.message());
return;
}
}

};

我的 CSerSessionsManager Class

class CSerSessionsManager{
private:

std::set<sessionPtr> sessions_; //Active Sessions : Online Info

public:
CSerSessionsManager();
~CSerSessionsManager();

void addSession(sessionPtr session);
void dropSession(sessionPtr session);
};
CSerSessionsManager::CSerSessionsManager()
{
DEBUG_MSG("Construction");
}

CSerSessionsManager::~CSerSessionsManager()
{
DEBUG_MSG("Destruction");
}

void CSerSessionsManager::addSession(sessionPtr session)
{
DEBUG_MSG("Incoming Session Entry saved");
//Critical Section
static std::mutex m;
std::lock_guard<std::mutex> lock(m);
sessions_.insert(session);
}

void CSerSessionsManager::dropSession(sessionPtr session)
{
//Properly handle Existing connections first shutdown sockets
DEBUG_MSG("Session dropped");

//Critical Section
static std::mutex m;
std::lock_guard<std::mutex> lock(m);

std::set<sessionPtr>::iterator it;
for (it = sessions_.begin(); it != sessions_.end(); ++it)
{
if ((*it) == session)
{
sessions_.erase(session);
return;
}
}
//throw ASIOError(Session_Not_Found);
}

还有我的CSerSession Class

class CSerSession : public std::enable_shared_from_this < CSerSession > {
private:

mutable tcp::socket socket_; // client connection
CSerSessionsManager& manager_;

std::string ip_;
std::string port_;

CBuffer msg_;

public:
CSerSession(asio::io_service& io_service, CSerSessionsManager& mng) :
manager_(mng), socket_(io_service)
{
DEBUG_MSG("Server Session Created");
}

~CSerSession()
{
DEBUG_MSG("Server Session Destroyed");
}

void startSession()
{
DEBUG_MSG("Server Session Started");
//Critical Section
static std::mutex m;
std::lock_guard<std::mutex> lock(m);
manager_.addSession(shared_from_this());//Multiple threads should not try adding section
read(msg_);
}

void handle_read(const asio::error_code& error /*error*/, size_t bytes_transferred /*bytes_transferred*/)
{
if (!error)
{
DEBUG_MSG("Read");
//Critical Section
static std::mutex m;
std::lock_guard<std::mutex> lock(m);

read(msg_);
}
else
{
DEBUG_MSG("Read Error Detected : " << error.message());
//Check If shared_from_this() is valid or not
try
{
//Check if session was already dropped e.g. server object destroying
//i.e. if session object exists
DEBUG_MSG("Dropping Session");
//if (error == asio::error::operation_aborted)
manager_.dropSession(shared_from_this());
}
catch (const std::bad_weak_ptr& e)
{
DEBUG_MSG(e.what());
throw e;
}
return;
}
}

void read(CBuffer & buff)
{
DEBUG_MSG("Read");
asio::async_read(socket_, asio::buffer(const_cast<char *> (buff.getReceived()), buff.buffsize),
std::bind(&CSerSession::handle_read, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
}


tcp::socket& socket()
{
//Critical Section
static std::mutex m;
std::lock_guard<std::mutex> lock(m);
return socket_;
}
};

我创建了 CServer Object主要如下:

void main()
{
try
{
asio::io_service io_service;
//CServer server(io_service, "Default", "127.0.0.1", "8000");
auto sPtr = std::make_shared<CServer>(io_service, "127.0.0.1", "8000");
sPtr->initProtocol();
//server.initProtocol();
asio::thread t(boost::bind(&asio::io_service::run, &io_service));

}
catch (...)
{
}

system("Pause");
}

我得到的输出日志如下:

CSerSessionsManager::CSerSessionsManager                                   :  183  :    Construction
CServer::CServer : 239 : Listener Created
CServer::initProtocol : 250 : Protocol Initiated
CServer::listen : 288 : !==============================================================!
CSerSession::CSerSession : 108 : Server Session Created
CServer::listen : 309 : Listen Activated
CServer::~CServer : 244 : Listener Destroyed
CSerSessionsManager::~CSerSessionsManager : 188 : Destruction
CSerSession::~CSerSession : 113 : Server Session Destroyed

CServer Object破坏相关CSerSession Object也破坏, 所以从 ~CSerSession() 返回时它抛出异常 boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<std::system_error> > at memory location 0x0277F19C.在下面的代码行中:

#ifndef BOOST_EXCEPTION_DISABLE
throw enable_current_exception(enable_error_info(e));
#else
throw e;
#endif
}

我尝试了很多调试并尝试使用 signal mechanism也如 HTTP Server 中所讨论,但我被困在这里,无法继续。

完整的代码可以在这里查看: MyCode

如何解决?

最佳答案

来自链接代码的固定版本:Live On Coliru我明白了

CSerSessionsManager   :  184  :    Construction
CServer : 240 : Listener Created
initProtocol : 251 : Protocol Initiated
~CServer : 245 : Listener Destroyed
~CSerSessionsManager : 189 : Destruction

NOTE: this was because I already had something listening on port 8000 (yay for error reporting!)

字段的初始化顺序修复了吗?或者我的系统上有什么东西根本没有运行(因为我更快的机器上的竞争条件?)。

看起来像后者,因为我得到了 Coliru

CSerSessionsManager    :  184  :    Construction
CServer : 240 : Listener Created
initProtocol : 251 : Protocol Initiated
listen : 289 : !===================================!
CSerSession : 109 : Server Session Created
listen : 310 : Listen Activated
~CServer : 245 : Listener Destroyed
~CSerSessionsManager : 189 : Destruction
~CSerSession : 114 : Server Session Destroyed

那么,让我们仔细看看:

  1. 为什么要解析 IP 字符串?这就是 address_v4 的用途。和 ip::tcp::resolver

    DEBUG_MSG(" Protocol Initiated");
    asio::ip::address_v4 address = asio::ip::address_v4::from_string(ip_);
    tcp::endpoint ep(address, std::stoi(port_));
  2. 使用static mutex 很少有用。您的意思是同步对共享资源的访问吗?那么你也需要一个共享的互斥体

  3. 为什么要使用延迟锁?使用范围

    {
    //Critical Section start
    std::lock_guard<std::mutex> lck(mutex_);
    acceptor_ = tcp::acceptor(io_, ep);//Creating IOService
    //Critical Section End
    }
  4. 主线程刚刚退出,从未加入 io 线程。至少加入。或者在终止程序之前让它正确关闭:

    t.join();
  5. 匈牙利语命名在这里真的没用。 sPtr 没有告诉我任何信息。 server 或者,如果你坚持,server_ptr 是你需要知道的。

  6. 你有越界写在这里:

    received_[str.size()] = '\0';

    你想要

    received_[len] = '\0';
  7. 你的empty不需要循环

    bool empty() const
    {
    return !received_[0];
    }
  8. 为什么要循环查找有序集中的东西?

    std::set<sessionPtr>::iterator it;
    for (it = sessions_.begin(); it != sessions_.end(); ++it)
    {
    if ((*it) == session)
    {
    sessions_.erase(session);
    return;
    }
    }

    应该是

    sessions_.erase(session);
  9. addSession/dropSession 在内部锁定;你不需要在关键部分访问它们

  10. throw e 是一种反模式;只是throw;被重新抛出

  11. 几乎所有地方都有冗余跟踪(这就是调试器的用途)。例如。 DEBUG_MSG("读取")

  12. 锁定这里是假的:

    tcp::socket& socket()
    {
    // Critical Section
    std::lock_guard<std::mutex> lock(mutex_);
    return socket_;
    }

    返回的引用无论如何都不会受到保护,套接字只会被初始化一次。

  13. 因为只有一个服务线程,所有的线程锁似乎都是多余的

  14. CBuffer msgread() 的虚假参数,因为始终传递相同的缓冲区。这可能很好(在同一个 session 中),所以,只需使用它。

  15. 这个

        acceptor_ = tcp::acceptor(io_, ep);

    应该是

        acceptor_.bind(ep);

    并且不在关键部分(服务器只创建一次);因此 initProtocol 函数可以是

    void initProtocol()
    {
    acceptor_.bind(tcp::endpoint(asio::ip::address_v4::from_string(ip_), std::stoi(port_)));
    listen();
    }
  16. listen 中,您捕获了 bad_weak_ptr,它甚至不会发生

  17. 此处:

    //Do I need a Lock here?
    //Critical Section
    std::lock_guard<std::mutex> lock(mutex_);
    newSession->startSession();

    你不需要锁。 newSession 是从局部变量绑定(bind)的。除非您复制了完成处理程序(您没有),否则它不可能被共享。

这是一个更固定的版本:

Live On Coliru

#include <iostream>
#include <boost/asio.hpp>
#include <memory>
#include <deque>
#include <set>
#include <iomanip>
#include <mutex>
#include <boost/bind.hpp>
#include <boost/thread.hpp>

#define DEBUG ON

#ifdef DEBUG
#define DEBUG_MSG(str) do {std::cout << std::setw(75) << std::left << __FUNCTION__ \
<< std::setw(3) << std::left << ":" << std::setw(5) << std::left << __LINE__ \
<< std::setw(5) << std::left << ":"\
<< std::left << str \
<< std::endl;} while( false )
#else
#define DEBUG_MSG(str) do { } while ( false )
#endif

namespace asio = boost::asio;
using asio::ip::tcp;

class CSerSession;
using sessionPtr = std::shared_ptr<CSerSession>;

class CSerSessionsManager {
private:
mutable std::mutex mutex_;
std::set<sessionPtr> sessions_; // Active Sessions : Online Info

public:
CSerSessionsManager();
~CSerSessionsManager();

void addSession(sessionPtr session);
void dropSession(sessionPtr session);
};

class CBuffer {

public:
enum { buffsize = 32 };

private:
char received_[buffsize];

public:
CBuffer() : received_{} {}

CBuffer(const std::string str)
{
// Truncate if Overflow
auto len = str.size();
if (len >= buffsize) {
len = buffsize - 1;
}
std::copy(str.begin(), str.begin() + len, received_);
received_[len] = '\0';
}

bool empty() const
{
return !received_[0];
}
const std::string getString() const { return std::string(received_); }
const char* getReceived() const { return received_; }
};

class CSerSession : public std::enable_shared_from_this<CSerSession> {
private:
mutable std::mutex mutex_;
mutable tcp::socket socket_; // client connection
CSerSessionsManager& manager_;

std::string ip_;
std::string port_;

CBuffer msg_;

public:
CSerSession(asio::io_service& io_service, CSerSessionsManager& mng) : socket_(io_service), manager_(mng)
{
DEBUG_MSG("Server Session Created");
}

~CSerSession() { DEBUG_MSG("Server Session Destroyed"); }

void startSession()
{
DEBUG_MSG("Server Session Started");
manager_.addSession(shared_from_this()); // Multiple threads should not try adding section

read();
}

tcp::socket& socket() { return socket_; }
private:
void handle_read(const boost::system::error_code& error /*error*/, size_t /*bytes_transferred*/)
{
if (!error) {
read();
} else {
DEBUG_MSG("Read Error Detected : " << error.message());
manager_.dropSession(shared_from_this()); // might throw
}
}

void read()
{
std::lock_guard<std::mutex> lock(mutex_);
DEBUG_MSG("Read");
asio::async_read(socket_, asio::buffer(const_cast<char*>(msg_.getReceived()), msg_.buffsize),
std::bind(&CSerSession::handle_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}
};


CSerSessionsManager::CSerSessionsManager()
{
DEBUG_MSG("Construction");
}

CSerSessionsManager::~CSerSessionsManager()
{
DEBUG_MSG("Destruction");
}

void CSerSessionsManager::addSession(sessionPtr session)
{
std::lock_guard<std::mutex> lock(mutex_);
DEBUG_MSG("Incoming Session Entry saved");
sessions_.insert(session);
}

void CSerSessionsManager::dropSession(sessionPtr session)
{
std::lock_guard<std::mutex> lock(mutex_);
DEBUG_MSG("Session dropped");
sessions_.erase(session);
}

class CServer {
private:
mutable std::mutex mutex_;
asio::io_service& io_;
mutable tcp::acceptor acceptor_; // only in the listener
CSerSessionsManager mng_;
public:

CServer(asio::io_service& io_service, const std::string& IP, int port)
: io_(io_service), acceptor_(io_, tcp::endpoint(asio::ip::address::from_string(IP), port))
{
DEBUG_MSG("Listener Created");
}

~CServer()
{
DEBUG_MSG("Listener Destroyed");
acceptor_.close(); // likely to be redundant
}

void initProtocol()
{
listen();
}

private:
void listen()
{
DEBUG_MSG("!==============================================================!");

sessionPtr newSession = std::make_shared<CSerSession>(io_, mng_);

std::lock_guard<std::mutex> lock(mutex_);
acceptor_.async_accept(newSession->socket(), std::bind(&CServer::handle_accept, this, newSession,
std::placeholders::_1));
}

void handle_accept(sessionPtr newSession, const boost::system::error_code& error)
{
if (error || !acceptor_.is_open()) {
DEBUG_MSG("Listen_Error");
DEBUG_MSG(error.message());
return;
}

DEBUG_MSG("Incoming Session accepted");
newSession->startSession();
listen();
}
};

int main()
{
try
{
asio::io_service io_service;
auto server = std::make_shared<CServer>(io_service, "127.0.0.1", 8973);
server->initProtocol();
boost::thread t(boost::bind(&asio::io_service::run, &io_service));

boost::this_thread::sleep_for(boost::chrono::seconds(3));

t.join();
}
catch (...)
{
}
}

打印(对于单个连接):

CSerSessionsManager :  123  :    Construction
CServer : 156 : Listener Created
listen : 173 : !==============================================================!
CSerSession : 86 : Server Session Created
handle_accept : 190 : Incoming Session accepted
startSession : 93 : Server Session Started
addSession : 134 : Incoming Session Entry saved
read : 114 : Read
listen : 173 : !==============================================================!
CSerSession : 86 : Server Session Created
handle_read : 106 : Read Error Detected : End of file
dropSession : 141 : Session dropped
~CSerSession : 89 : Server Session Destroyed

关于c++ - ASIO 聊天 session 类在销毁时抛出异常 : C++ ASIO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28564029/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com