我正在使用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_;
}
};
我在main中创建了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
我该如何解决?
答案 0 :(得分:3)
从链接代码的固定版本开始:Live On Coliru我
CSerSessionsManager : 184 : Construction
CServer : 240 : Listener Created
initProtocol : 251 : Protocol Initiated
~CServer : 245 : Listener Destroyed
~CSerSessionsManager : 189 : Destruction
注意:这是因为我已经在端口8000上监听了某些内容(yay用于错误报告!)
字段的初始化顺序是否修复了它?或者我的系统上有没有运行的东西(因为我的速度更快的机器上存在竞争条件?)。
看起来后者因为我得到了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
所以,让我们仔细看看:
为什么要解析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_));
使用static mutex
很少有用。您的意思是同步访问共享资源吗?那么你也需要一个共享的互斥锁
你为什么要使用延迟锁?使用范围
{
//Critical Section start
std::lock_guard<std::mutex> lck(mutex_);
acceptor_ = tcp::acceptor(io_, ep);//Creating IOService
//Critical Section End
}
主线程刚刚退出,从未加入io线程。至少加入。或者在终止程序之前使其正确关闭:
t.join();
匈牙利语命名真的在这里没用。 sPtr
没有告诉我任何事情。 server
或者,如果你坚持,server_ptr
是你需要知道的。
你在这里写了越界:
received_[str.size()] = '\0';
你想要
received_[len] = '\0';
您的empty
无需循环
bool empty() const
{
return !received_[0];
}
为什么要循环查找有序集中的内容?
std::set<sessionPtr>::iterator it;
for (it = sessions_.begin(); it != sessions_.end(); ++it)
{
if ((*it) == session)
{
sessions_.erase(session);
return;
}
}
应该是
sessions_.erase(session);
addSession / dropSession是内部锁定的;您不需要在关键部分中访问它们
throw e
是反模式;刚刚throw;
重新投掷
几乎到处都有冗余跟踪(这是调试器的用途)。例如。 DEBUG_MSG("Read")
锁定在这里是假的:
tcp::socket& socket()
{
// Critical Section
std::lock_guard<std::mutex> lock(mutex_);
return socket_;
}
无论如何都不会保护返回的引用,socket只会被初始化一次。
所有线程锁定似乎都是多余的,因为只有一个服务线程
CBuffer msg
是read()
的伪造参数,因为始终传递相同的缓冲区。这可能很好(它在同一个会话中),所以,只需使用它。
此
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();
}
在listen
你正在捕捉甚至无法发生的bad_weak_ptr
这里:
//Do I need a Lock here?
//Critical Section
std::lock_guard<std::mutex> lock(mutex_);
newSession->startSession();
你不需要锁。 newSession
绑定了一个局部变量。除非你复制完成处理程序(你没有),否则它不可能被共享。
这是一个更加固定的版本:
<强> 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