C++ Muduo网络库基本流程跟踪,学习下
2015-09-24 15:44
549 查看
C++ Muduo网络库基本流程跟踪:
例子中的入口点:
int main()
{
EventLoop loop;
TcpServer server(&loop, listenAddr,"name");
server.start();
loop.loop();
}
看TcpServer构造函数:
TcpServer::TcpServer(EventLoop*
loop,
const
InetAddress& listenAddr,
const
string& nameArg,
Option
option)
: loop_(CHECK_NOTNULL(loop)),
hostport_(listenAddr.toIpPort()),
name_(nameArg),
acceptor_(new
Acceptor(loop,
listenAddr, option ==
kReusePort)),
threadPool_(new
EventLoopThreadPool(loop,
name_)),
connectionCallback_(defaultConnectionCallback),
messageCallback_(defaultMessageCallback),
nextConnId_(1)
{
acceptor_->setNewConnectionCallback(
boost::bind(&TcpServer::newConnection,
this, _1,
_2));
}
在声明server时候调用TcpServer的构造函数:
0.初始化线程池(暂不说)
1.初始化listen套接字类Acceptor
2.初始化默认的连接和接收消息回调
3.设置acceptor的新连接回调为TcpServer::newConnection
跟进server.start():
void
TcpServer::start()
{
if (started_.getAndSet(1) ==0)
{
threadPool_->start(threadInitCallback_);
assert(!acceptor_->listenning());
loop_->runInLoop(
boost::bind(&Acceptor::listen,
get_pointer(acceptor_)));
}
}
1.启动线程池
2.调用acceptor_->listen()开始监听新连接
void
Acceptor::listen()
{
loop_->assertInLoopThread();
listenning_ =
true;
acceptSocket_.listen();
acceptChannel_.enableReading();
}
acceptChannel_.enableReading();// 这里将acceptor套接字加入到loop中的poller的in事件中,当有新连接上来的时候,会回调到acceptor_->handleRead(),当连接成功,会回调到server->newConnection(),嘿嘿。
看看TcpServer::newConnection()做了什么:
void
TcpServer::newConnection(int
sockfd, const
InetAddress& peerAddr)
{
loop_->assertInLoopThread();
EventLoop*
ioLoop = threadPool_->getNextLoop();
char buf[32];
snprintf(buf,
sizeof buf,
":%s#%d", hostport_.c_str(),
nextConnId_);
++nextConnId_;
string
connName = name_ +
buf;
LOG_INFO<<
"TcpServer::newConnection ["<< name_
<< "]- new connection [" <<
connName
<< "]from " <<
peerAddr.toIpPort();
InetAddress
localAddr(sockets::getLocalAddr(sockfd));
// FIXMEpoll with zero timeout to double confirm the new connection
// FIXMEuse make_shared if necessary
TcpConnectionPtr
conn(new
TcpConnection(ioLoop,
connName,
sockfd,
localAddr,
peerAddr));
connections_[connName] =
conn;
conn->setConnectionCallback(connectionCallback_);
conn->setMessageCallback(messageCallback_);
conn->setWriteCompleteCallback(writeCompleteCallback_);
conn->setCloseCallback(
boost::bind(&TcpServer::removeConnection,
this, _1));
//FIXME: unsafe
ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished,
conn));
}
创建新连接shared_ptr对象:TcpConnectionPtr,设置Channel的读,写事件回调(TcpConnection构造函数中设置),设置接收完整的一个packet的回调messageCallback,完全写出数据时候的回调writeCompleteCallback,关闭套接字回调removeConnection,执行TcpConnection::connectEstablish(这里只是回调到用户设置的新连接上来的回调),所以当一个新连接上来的时候,流程是这样的:
Acceptor::handleRead()->TcpServer::newConnection()->TcpServer::connectionCallback_()
看看TcpConnection::connectionEstablished():
void
TcpConnection::connectEstablished()
{
loop_->assertInLoopThread();
assert(state_ ==
kConnecting);
setState(kConnected);
channel_->tie(shared_from_this());
channel_->enableReading();
connectionCallback_(shared_from_this());
}
1.设置状态为连接
2.将套接字加入到poller的in事件中
3.回调用户设置的connectionCallback_
接着看loop.loop():
void
EventLoop::loop()
{
assert(!looping_);
assertInLoopThread();
looping_ =
true;
quit_ =
false; //FIXME: what if someone calls quit() before loop() ?
LOG_TRACE<<
"EventLoop " << this <<
" start looping";
while (!quit_)
{
activeChannels_.clear();
pollReturnTime_ =
poller_->poll(kPollTimeMs, &activeChannels_);
++iteration_;
if (Logger::logLevel() <=Logger::TRACE)
{
printActiveChannels();
}
// TODOsort channel by priority
eventHandling_ =
true;
for (ChannelList::iterator
it = activeChannels_.begin();
it !=
activeChannels_.end(); ++it)
{
currentActiveChannel_ = *it;
currentActiveChannel_->handleEvent(pollReturnTime_);
}
currentActiveChannel_ = NULL;
eventHandling_ =
false;
doPendingFunctors();
}
LOG_TRACE<<
"EventLoop " << this <<
" stop looping";
looping_ =
false;
}
1.loop只能在本线程执行(assertInLoopThread())
2.循环执行网络poller
3.处理网络事件currentActiveChannel_->handleEvent(pollReturnTime_);当在poll所有channels的时候,会处理channel的读,写事件回调,这个时候会调用到TcpConnection的读写事件回调(在TcpConnection构造函数中不是设置了channel的回到么)
4.处理其他线程调用本线程事件?doPendingFunctors()
基本流程也就这样了吧,当然,里面还涉及很多细节。很多地方还是值得学习的。
例子中的入口点:
int main()
{
EventLoop loop;
TcpServer server(&loop, listenAddr,"name");
server.start();
loop.loop();
}
看TcpServer构造函数:
TcpServer::TcpServer(EventLoop*
loop,
const
InetAddress& listenAddr,
const
string& nameArg,
Option
option)
: loop_(CHECK_NOTNULL(loop)),
hostport_(listenAddr.toIpPort()),
name_(nameArg),
acceptor_(new
Acceptor(loop,
listenAddr, option ==
kReusePort)),
threadPool_(new
EventLoopThreadPool(loop,
name_)),
connectionCallback_(defaultConnectionCallback),
messageCallback_(defaultMessageCallback),
nextConnId_(1)
{
acceptor_->setNewConnectionCallback(
boost::bind(&TcpServer::newConnection,
this, _1,
_2));
}
在声明server时候调用TcpServer的构造函数:
0.初始化线程池(暂不说)
1.初始化listen套接字类Acceptor
2.初始化默认的连接和接收消息回调
3.设置acceptor的新连接回调为TcpServer::newConnection
跟进server.start():
void
TcpServer::start()
{
if (started_.getAndSet(1) ==0)
{
threadPool_->start(threadInitCallback_);
assert(!acceptor_->listenning());
loop_->runInLoop(
boost::bind(&Acceptor::listen,
get_pointer(acceptor_)));
}
}
1.启动线程池
2.调用acceptor_->listen()开始监听新连接
void
Acceptor::listen()
{
loop_->assertInLoopThread();
listenning_ =
true;
acceptSocket_.listen();
acceptChannel_.enableReading();
}
acceptChannel_.enableReading();// 这里将acceptor套接字加入到loop中的poller的in事件中,当有新连接上来的时候,会回调到acceptor_->handleRead(),当连接成功,会回调到server->newConnection(),嘿嘿。
看看TcpServer::newConnection()做了什么:
void
TcpServer::newConnection(int
sockfd, const
InetAddress& peerAddr)
{
loop_->assertInLoopThread();
EventLoop*
ioLoop = threadPool_->getNextLoop();
char buf[32];
snprintf(buf,
sizeof buf,
":%s#%d", hostport_.c_str(),
nextConnId_);
++nextConnId_;
string
connName = name_ +
buf;
LOG_INFO<<
"TcpServer::newConnection ["<< name_
<< "]- new connection [" <<
connName
<< "]from " <<
peerAddr.toIpPort();
InetAddress
localAddr(sockets::getLocalAddr(sockfd));
// FIXMEpoll with zero timeout to double confirm the new connection
// FIXMEuse make_shared if necessary
TcpConnectionPtr
conn(new
TcpConnection(ioLoop,
connName,
sockfd,
localAddr,
peerAddr));
connections_[connName] =
conn;
conn->setConnectionCallback(connectionCallback_);
conn->setMessageCallback(messageCallback_);
conn->setWriteCompleteCallback(writeCompleteCallback_);
conn->setCloseCallback(
boost::bind(&TcpServer::removeConnection,
this, _1));
//FIXME: unsafe
ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished,
conn));
}
创建新连接shared_ptr对象:TcpConnectionPtr,设置Channel的读,写事件回调(TcpConnection构造函数中设置),设置接收完整的一个packet的回调messageCallback,完全写出数据时候的回调writeCompleteCallback,关闭套接字回调removeConnection,执行TcpConnection::connectEstablish(这里只是回调到用户设置的新连接上来的回调),所以当一个新连接上来的时候,流程是这样的:
Acceptor::handleRead()->TcpServer::newConnection()->TcpServer::connectionCallback_()
看看TcpConnection::connectionEstablished():
void
TcpConnection::connectEstablished()
{
loop_->assertInLoopThread();
assert(state_ ==
kConnecting);
setState(kConnected);
channel_->tie(shared_from_this());
channel_->enableReading();
connectionCallback_(shared_from_this());
}
1.设置状态为连接
2.将套接字加入到poller的in事件中
3.回调用户设置的connectionCallback_
接着看loop.loop():
void
EventLoop::loop()
{
assert(!looping_);
assertInLoopThread();
looping_ =
true;
quit_ =
false; //FIXME: what if someone calls quit() before loop() ?
LOG_TRACE<<
"EventLoop " << this <<
" start looping";
while (!quit_)
{
activeChannels_.clear();
pollReturnTime_ =
poller_->poll(kPollTimeMs, &activeChannels_);
++iteration_;
if (Logger::logLevel() <=Logger::TRACE)
{
printActiveChannels();
}
// TODOsort channel by priority
eventHandling_ =
true;
for (ChannelList::iterator
it = activeChannels_.begin();
it !=
activeChannels_.end(); ++it)
{
currentActiveChannel_ = *it;
currentActiveChannel_->handleEvent(pollReturnTime_);
}
currentActiveChannel_ = NULL;
eventHandling_ =
false;
doPendingFunctors();
}
LOG_TRACE<<
"EventLoop " << this <<
" stop looping";
looping_ =
false;
}
1.loop只能在本线程执行(assertInLoopThread())
2.循环执行网络poller
3.处理网络事件currentActiveChannel_->handleEvent(pollReturnTime_);当在poll所有channels的时候,会处理channel的读,写事件回调,这个时候会调用到TcpConnection的读写事件回调(在TcpConnection构造函数中不是设置了channel的回到么)
4.处理其他线程调用本线程事件?doPendingFunctors()
基本流程也就这样了吧,当然,里面还涉及很多细节。很多地方还是值得学习的。
相关文章推荐
- intellij ideal 学习 maven http://www.cnblogs.com/yjmyzz/p/intellij-idea-13-getting-started.html
- 根据文件的url在网络上下载文件url.openConnection()
- 使用xmlHttprequest 发送异步请求(Ajax核心对象)
- svn学习之二(svn+httpd 部署脚本)
- 网络调试的几个命令
- 校园网络(模拟)
- Nodejs创建TCP服务器 - king0222
- 网络请求的get,post 方法,同步,异步请求
- Matlab实现网络拓补图
- 理解TCP/IP,SOCKET,HTTP,FTP,RMI,RPC,webservice等的含义和关系
- ubuntu 10.04右上角网络管理图标消失解决办法
- 生活本身就是就是一种承受(网络整理)
- 15北京网络赛 B题
- HTTP Live Streaming直播(iOS直播)技术分析与实现
- Powershell DSC 5.0 - Pull 模式 (HTTPS)
- Powershell DSC 5.0 - Pull 模式 (HTTPS)
- 同步异步网络解析方法总结
- android 手机的网络时间同步
- Java网络编程(一):服务端与客户端建立(UDP方式)
- Android HttpgetRequester+onResponse