封装服务器类的目的是希望全局只有一个服务器
IMServer.h
#include <list> #include "net/EventLoop.h" #include "net/EventLoopThread.h" #include "net/EventLoopThreadPool.h" #include "net/TcpServer.h" #include "base/Logging.h" #include "ClientSession.h" #include <mutex> #include <iostream> using namespace muduo; using namespace muduo::net; using namespace std; class IMServer final //final表示该类不可能派生子类 { public: IMServer() = default; IMServer(const IMServer&) = delete;//禁止使用此函数 ~IMServer() = default; IMServer& operator=(const IMServer&) = delete;//禁用此函数 bool Init(const string& ip, short port, EventLoop* loop); protected: void OnConnection(const TcpConnectionPtr& conn); void OnClose(const TcpConnectionPtr& conn); private: shared_ptr<TcpServer> m_server; map<string, ClientSessionPtr> m_mapclient; //std::list<TcpConnectionPtr> m_lstConn; mutex m_sessionlock;//保护m_mapclient的操作 }; typedef pair<string, ClientSessionPtr> ConnPair; typedef map<string, ClientSessionPtr>::iterator ConnIter;
IMServer.cpp
#include "IMServer.h" using namespace std::placeholders; bool IMServer::Init(const std::string& ip, short port, EventLoop* loop) { InetAddress addr(ip, port); m_server.reset(new TcpServer(loop, addr, "chatserver", TcpServer::kReusePort)); m_server->setConnectionCallback(std::bind(&IMServer::OnConnection, this, _1)); m_server->start(); return true; } void IMServer::OnConnection(const TcpConnectionPtr& conn) { if (conn->connected()) { ClientSessionPtr client(new ClientSession(conn)); { //防止OnConnection在多个线程中插入出现问题 std::lock_guard<std::mutex> guard(m_sessionlock); m_mapclient.insert(ConnPair((std::string) * client, client)); //m_lstConn.push_back(client); } } else { OnClose(conn); } } void IMServer::OnClose(const TcpConnectionPtr& conn) { //TODO:处理这个连接,找到这个连接,然后进行关闭 stringstream ss; ss << (void*)conn.get(); ConnIter iter = m_mapclient.find(ss.str()); if (iter != m_mapclient.end()) { //TODO:关闭连接的操作 m_mapclient.erase(iter); } else { //TODO:有问题的连接 cout << conn->name() << std::endl; } }
ClientSession.h
#include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid_generators.hpp> #include <boost/uuid/uuid_io.hpp> using namespace muduo; using namespace muduo::net; using namespace boost::uuids; using namespace std::placeholders class ClientSession { public: ClientSession(const TcpConnectionPtr& conn); //为了控制生命周期,防止提前销毁,或者销毁之后,重复销毁 ClientSession(const ClientSession&) = delete; ClientSession& operator=(const ClientSession&) = delete; ~ClientSession(); operator std::string() { return m_sessionid; } void OnRead(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time); void Send(const std::string& buf); private: string m_sessionid; }; typedef std::shared_ptr<ClientSession> ClientSessionPtr;
ClientSession.cpp
#include "ClientSession.h" ClientSessionPtr::CientSessionPtr(const TcpConnectionPtr& conn) { //此处就是两个括号,第一个表示构造对象,第二个表示()运算符重载 m_sessionid = to_string(random_generator()()); //到时候研究一下为什么这里用TcpConnectionPtr*,而不是TcpConnectionPtr TcpConnectionPtr* client = const_cast<TcpConnectionPtr*>(&conn); //使用const_cast消除const限定符 const_cast<std::string>(&conn->name()) = m_sessionid; (*client)->setMessageCallback(std::bind(&ClientSession::OnRead,this,_1,_2,_3)); } void ClientSessionPtr::OnRead(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) { //业务代码 } void ClientSession::Send(const std::string& buf) { //发送数据 }