Muduo网络库简介
muduo 是一个基于 Reactor 模式的现代 C++ 网络库,作者陈硕。它采用非阻塞 IO 模型,基于事件驱动和回调,原生支持多核多线程,适合编写 Linux 服务端多线程网络应用程序。
muduo网络库的核心代码只有数千行,在网络编程技术学习的进阶阶段,muduo是一个非常值得学习的开源库。目前我也是刚刚开始学习这个网络库的源码,希望将这个学习过程记录下来。这个网络库的源码已经发布在GitHub上,可以点击这里阅读。目前Github上这份源码已经被作者用c++11重写,我学习的版本是没有使用c++11版本的。不过二者大同小异,核心思想是没有变化的。点这里可以看我的源代码。从笔记十七开始记录muduo的net库的实现过程。如果你需要看一下基础库(base)的复现过程,可以点击这里:muduo的base库实现过程。而网络库的笔记在这里:
muduo网络库源码复现笔记(十七):什么都不做的EventLoop
muduo网络库源码复现笔记(十八):Reactor的关键结构
muduo网络库源码复现笔记(十九):TimeQueue定时器
muduo网络库源码复现笔记(二十):EventLoop::runInloop()函数和EventLoopThread类
muduo网络库源码复现笔记(二十一):Acceptor类、InetAddress类、Sockets类、SocketsOps.cc
1 TcpServer类
前面我们讲了Acceptor类,我们也说过这个类用于监听网络连接。实际上用户将不会直接使用这个类,这个类实际上是由TcpServer类来调用的。
TcpServer类的作用是管理由Acceptor获得的网络连接,并建立相应的TcpConnection连接。下面看一下它的代码:
class TcpServer : boost::noncopyable
{
public:
//typedef boost::function<void(EventLoop*)> ThreadInitCallback;
//TcpServer(EventLoop* loop,const InetAddress& listenAddr);
TcpServer(EventLoop* loop,const InetAddress& lostenAddr,
const string& nameArg);
~TcpServer();
const string& hostport() const {return hostport_;}
const string& name() const {return name_;}
//start the server
void start();
void setConnectionCallback(const ConnectionCallback& cb)
{ connectionCallback_ = cb; }
void setMessageCallback(const MessageCallback& cb)
{ messageCallback_ = cb; }
private:
void newConnection(int sockfd,const InetAddress& peerAddr);
typedef std::map<string,TcpConnectionPtr> ConnectionMap;
EventLoop* loop_;
const string hostport_;
const string name_;
boost::scoped_ptr<Acceptor> acceptor_;
ConnectionCallback connectionCallback_;
MessageCallback messageCallback_;
bool started_;
// in loop thread
int nextConnId_;
ConnectionMap connections_;
};
TcpServer通过ConnectionMap掌管连接,map的key是连接名称,value是TcpConnection类的指针。
其中最值得注意的是newConnection函数,这个函数将在TcpServer被创立的时候绑定给acceptor_,若acceptor监听到新的网络连接,newConnection将会被调用。newConnection会创建一个TcpConnection,将其指针加入map,设置相应的connectionCallback和messageCallback。代码如下:
void TcpServer::newConnection(int sockfd,const InetAddress& peerAddr)
{
loop_ -> assertInLoopThread();
char buf[32];
snprintf(buf,sizeof buf,":%s#%d",hostport_.c_str(),nextConnId_);
++nextConnId_;
string connName = name_ + buf;
LOG_INFO << "TcpServerLLnewConnection [" << name_
<< "] - new connection [" << connName
<< "] from " << peerAddr.toIpPort();
InetAddress localAddr(sockets::getLocalAddr(sockfd));
TcpConnectionPtr conn(new TcpConnection(loop_,
connName,
sockfd,
localAddr,
peerAddr));
connections_[connName] = conn;
conn -> setConnectionCallback(connectionCallback_);
conn -> setMessageCallback(messageCallback_);
conn -> connectEstablished();
}
2 TcpConnection类初步
TcpConnection类是muduo最复杂、最核心的类。它的作用如前所述,便是进行一次Tcp连接。这一节的TcpConnection还比较简陋,先初步看看它的成员。
private:
enum stateE {/*kDisConnected*/kConnecting,kConnected/*,kDisConnecting*/};
void handleRead(Timestamp receiveTime);
void setState(stateE s) { state_ = s; }
EventLoop* loop_;
string name_; //connection name
stateE state_;
boost::scoped_ptr<Socket> socket_;
boost::scoped_ptr<Channel> channel_;
InetAddress localAddr_;
InetAddress peerAddr_;
ConnectionCallback connectionCallback_;
MessageCallback messageCallback_;
TcpConnection有两个成员很重要,分别是socket_和channel_。socket_是一个Socket类指针,指向的Socket的socket的文件描述符便是与客户端通信的connfd。channel_的作用是,当建立连接时,将connfd与channel_绑定,然后将channel_加入到poller中,方便后续的通信。
connectionCallback_与messageCallback_实际上会由TcpServer设置,分别在建立连接和通信时调用。