//checkonlineplaycountcount

 上传我的文档
 下载
 收藏
免责声明:本人所有资料来自网络和个人所创,版权归原作者所有,请注意保护知识产权,如有需要请购
买正版图书,请您下载后勿作商用,于24小时内删除,本人所提供资料仅为方便学习交流。 本人如有侵
犯作者权益,请作者联系官方或本人,本人将立即删除。
 下载此文档
正在努力加载中...
vb习题47109
下载积分:1500
内容提示:vb习题47109
文档格式:DOC|
浏览次数:0|
上传日期: 07:38:30|
文档星级:
全文阅读已结束,如果下载本文需要使用
 1500 积分
下载此文档
该用户还上传了这些文档
vb习题47109
官方公共微信/ codesource
项目语言:GO
权限:read-only(如需更高权限请先加入项目)
codesource/
Index: net/poller/DefaultPoller.cc
===================================================================
--- net/poller/DefaultPoller.cc (revision 0)
+++ net/poller/DefaultPoller.cc (revision 45)
@@ -0,0 +1,27 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+#include &muduo/net/Poller.h&
+#include &muduo/net/poller/PollPoller.h&
+#include &muduo/net/poller/EPollPoller.h&
+#include &stdlib.h&
+using namespace muduo::
+Poller* Poller::newDefaultPoller(EventLoop* loop)
if (::getenv(&MUDUO_USE_POLL&))
return new PollPoller(loop);
return new EPollPoller(loop);
Index: net/poller/PollPoller.cc
===================================================================
--- net/poller/PollPoller.cc (revision 0)
+++ net/poller/PollPoller.cc (revision 45)
@@ -0,0 +1,141 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+#include &muduo/net/poller/PollPoller.h&
+#include &muduo/base/Logging.h&
+#include &muduo/base/Types.h&
+#include &muduo/net/Channel.h&
+#include &assert.h&
+#include &poll.h&
+using namespace muduo::
+PollPoller::PollPoller(EventLoop* loop)
: Poller(loop)
+PollPoller::~PollPoller()
+Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels)
// XXX pollfds_ shouldn't change
int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs);
Timestamp now(Timestamp::now());
if (numEvents & 0)
LOG_TRACE && numEvents && & events happended&;
fillActiveChannels(numEvents, activeChannels);
else if (numEvents == 0)
LOG_TRACE && & nothing happended&;
LOG_SYSERR && &PollPoller::poll()&;
+void PollPoller::fillActiveChannels(int numEvents,
ChannelList* activeChannels) const
for (PollFdList::const_iterator pfd = pollfds_.begin();
pfd != pollfds_.end() && numEvents & 0; ++pfd)
if (pfd-&revents & 0)
ChannelMap::const_iterator ch = channels_.find(pfd-&fd);
assert(ch != channels_.end());
Channel* channel = ch-&
assert(channel-&fd() == pfd-&fd);
channel-&set_revents(pfd-&revents);
// pfd-&revents = 0;
activeChannels-&push_back(channel);
+void PollPoller::updateChannel(Channel* channel)
Poller::assertInLoopThread();
LOG_TRACE && &fd = & && channel-&fd() && & events = & && channel-&events();
if (channel-&index() & 0)
+ // index & 0说明是一个新的通道
// a new one, add to pollfds_
assert(channels_.find(channel-&fd()) == channels_.end());
pfd.fd = channel-&fd();
pfd.events = static_cast&short&(channel-&events());
pfd.revents = 0;
pollfds_.push_back(pfd);
int idx = static_cast&int&(pollfds_.size())-1;
channel-&set_index(idx);
channels_[pfd.fd] =
// update existing one
assert(channels_.find(channel-&fd()) != channels_.end());
assert(channels_[channel-&fd()] == channel);
int idx = channel-&index();
assert(0 &= idx && idx & static_cast&int&(pollfds_.size()));
struct pollfd& pfd = pollfds_[idx];
assert(pfd.fd == channel-&fd() || pfd.fd == -channel-&fd()-1);
pfd.events = static_cast&short&(channel-&events());
pfd.revents = 0;
+ // 将一个通道暂时更改为不关注事件,但不从Poller中移除该通道
if (channel-&isNoneEvent())
// ignore this pollfd
// 暂时忽略该文件描述符的事件
// 这里pfd.fd 可以直接设置为-1
pfd.fd = -channel-&fd()-1; // 这样子设置是为了removeChannel优化
+void PollPoller::removeChannel(Channel* channel)
Poller::assertInLoopThread();
LOG_TRACE && &fd = & && channel-&fd();
assert(channels_.find(channel-&fd()) != channels_.end());
assert(channels_[channel-&fd()] == channel);
assert(channel-&isNoneEvent());
int idx = channel-&index();
assert(0 &= idx && idx & static_cast&int&(pollfds_.size()));
const struct pollfd& pfd = pollfds_[idx]; (void)
assert(pfd.fd == -channel-&fd()-1 && pfd.events == channel-&events());
size_t n = channels_.erase(channel-&fd());
assert(n == 1); (void)n;
if (implicit_cast&size_t&(idx) == pollfds_.size()-1)
pollfds_.pop_back();
+ // 这里移除的算法复杂度是O(1),将待删除元素与最后一个元素交换再pop_back
int channelAtEnd = pollfds_.back().
iter_swap(pollfds_.begin()+idx, pollfds_.end()-1);
if (channelAtEnd & 0)
channelAtEnd = -channelAtEnd-1;
channels_[channelAtEnd]-&set_index(idx);
pollfds_.pop_back();
Index: net/poller/PollPoller.h
===================================================================
--- net/poller/PollPoller.h (revision 0)
+++ net/poller/PollPoller.h (revision 45)
@@ -0,0 +1,52 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+// This is an internal header file, you should not include this.
+#ifndef MUDUO_NET_POLLER_POLLPOLLER_H
+#define MUDUO_NET_POLLER_POLLPOLLER_H
+#include &muduo/net/Poller.h&
+#include &map&
+#include &vector&
+namespace muduo
+namespace net
+/// IO Multiplexing with poll(2).
+class PollPoller : public Poller
PollPoller(EventLoop* loop);
virtual ~PollPoller();
virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels);
virtual void updateChannel(Channel* channel);
virtual void removeChannel(Channel* channel);
+ private:
void fillActiveChannels(int numEvents,
ChannelList* activeChannels)
typedef std::vector&struct pollfd& PollFdL
typedef std::map&int, Channel*& ChannelM // key是文件描述符,value是Channel*
PollFdList pollfds_;
ChannelMap channels_;
// MUDUO_NET_POLLER_POLLPOLLER_H
Index: net/poller/EPollPoller.cc
===================================================================
--- net/poller/EPollPoller.cc (revision 0)
+++ net/poller/EPollPoller.cc (revision 45)
@@ -0,0 +1,183 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+#include &muduo/net/poller/EPollPoller.h&
+#include &muduo/base/Logging.h&
+#include &muduo/net/Channel.h&
+#include &boost/static_assert.hpp&
+#include &assert.h&
+#include &errno.h&
+#include &poll.h&
+#include &sys/epoll.h&
+using namespace muduo::
+// On Linux, the constants of poll(2) and epoll(4)
+// are expected to be the same.
+BOOST_STATIC_ASSERT(EPOLLIN == POLLIN);
+BOOST_STATIC_ASSERT(EPOLLPRI == POLLPRI);
+BOOST_STATIC_ASSERT(EPOLLOUT == POLLOUT);
+BOOST_STATIC_ASSERT(EPOLLRDHUP == POLLRDHUP);
+BOOST_STATIC_ASSERT(EPOLLERR == POLLERR);
+BOOST_STATIC_ASSERT(EPOLLHUP == POLLHUP);
+namespace
+const int kNew = -1;
+const int kAdded = 1;
+const int kDeleted = 2;
+EPollPoller::EPollPoller(EventLoop* loop)
: Poller(loop),
epollfd_(::epoll_create1(EPOLL_CLOEXEC)),
events_(kInitEventListSize)
if (epollfd_ & 0)
LOG_SYSFATAL && &EPollPoller::EPollPoller&;
+EPollPoller::~EPollPoller()
::close(epollfd_);
+Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels)
int numEvents = ::epoll_wait(epollfd_,
&*events_.begin(),
static_cast&int&(events_.size()),
timeoutMs);
Timestamp now(Timestamp::now());
if (numEvents & 0)
LOG_TRACE && numEvents && & events happended&;
fillActiveChannels(numEvents, activeChannels);
if (implicit_cast&size_t&(numEvents) == events_.size())
events_.resize(events_.size()*2);
else if (numEvents == 0)
LOG_TRACE && & nothing happended&;
LOG_SYSERR && &EPollPoller::poll()&;
+void EPollPoller::fillActiveChannels(int numEvents,
ChannelList* activeChannels) const
assert(implicit_cast&size_t&(numEvents) &= events_.size());
for (int i = 0; i & numE ++i)
Channel* channel = static_cast&Channel*&(events_[i].data.ptr);
+#ifndef NDEBUG
int fd = channel-&fd();
ChannelMap::const_iterator it = channels_.find(fd);
assert(it != channels_.end());
assert(it-&second == channel);
channel-&set_revents(events_[i].events);
activeChannels-&push_back(channel);
+void EPollPoller::updateChannel(Channel* channel)
Poller::assertInLoopThread();
LOG_TRACE && &fd = & && channel-&fd() && & events = & && channel-&events();
const int index = channel-&index();
if (index == kNew || index == kDeleted)
// a new one, add with EPOLL_CTL_ADD
int fd = channel-&fd();
if (index == kNew)
assert(channels_.find(fd) == channels_.end());
channels_[fd] =
else // index == kDeleted
assert(channels_.find(fd) != channels_.end());
assert(channels_[fd] == channel);
channel-&set_index(kAdded);
update(EPOLL_CTL_ADD, channel);
// update existing one with EPOLL_CTL_MOD/DEL
int fd = channel-&fd();
assert(channels_.find(fd) != channels_.end());
assert(channels_[fd] == channel);
assert(index == kAdded);
if (channel-&isNoneEvent())
update(EPOLL_CTL_DEL, channel);
channel-&set_index(kDeleted);
update(EPOLL_CTL_MOD, channel);
+void EPollPoller::removeChannel(Channel* channel)
Poller::assertInLoopThread();
int fd = channel-&fd();
LOG_TRACE && &fd = & &&
assert(channels_.find(fd) != channels_.end());
assert(channels_[fd] == channel);
assert(channel-&isNoneEvent());
int index = channel-&index();
assert(index == kAdded || index == kDeleted);
size_t n = channels_.erase(fd);
assert(n == 1);
if (index == kAdded)
update(EPOLL_CTL_DEL, channel);
channel-&set_index(kNew);
+void EPollPoller::update(int operation, Channel* channel)
struct epoll_
bzero(&event, sizeof event);
event.events = channel-&events();
event.data.ptr =
int fd = channel-&fd();
if (::epoll_ctl(epollfd_, operation, fd, &event) & 0)
if (operation == EPOLL_CTL_DEL)
LOG_SYSERR && &epoll_ctl op=& && operation && & fd=& &&
LOG_SYSFATAL && &epoll_ctl op=& && operation && & fd=& &&
Index: net/poller/EPollPoller.h
===================================================================
--- net/poller/EPollPoller.h (revision 0)
+++ net/poller/EPollPoller.h (revision 45)
@@ -0,0 +1,56 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+// This is an internal header file, you should not include this.
+#ifndef MUDUO_NET_POLLER_EPOLLPOLLER_H
+#define MUDUO_NET_POLLER_EPOLLPOLLER_H
+#include &muduo/net/Poller.h&
+#include &map&
+#include &vector&
+struct epoll_
+namespace muduo
+namespace net
+/// IO Multiplexing with epoll(4).
+class EPollPoller : public Poller
EPollPoller(EventLoop* loop);
virtual ~EPollPoller();
virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels);
virtual void updateChannel(Channel* channel);
virtual void removeChannel(Channel* channel);
+ private:
static const int kInitEventListSize = 16;
void fillActiveChannels(int numEvents,
ChannelList* activeChannels)
void update(int operation, Channel* channel);
typedef std::vector&struct epoll_event& EventL
typedef std::map&int, Channel*& ChannelM
int epollfd_;
EventList events_;
ChannelMap channels_;
// MUDUO_NET_POLLER_EPOLLPOLLER_H
Index: net/Channel.h
===================================================================
--- net/Channel.h (revision 0)
+++ net/Channel.h (revision 45)
@@ -0,0 +1,108 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+// This is an internal header file, you should not include this.
+#ifndef MUDUO_NET_CHANNEL_H
+#define MUDUO_NET_CHANNEL_H
+#include &boost/function.hpp&
+#include &boost/noncopyable.hpp&
+#include &boost/shared_ptr.hpp&
+#include &boost/weak_ptr.hpp&
+#include &muduo/base/Timestamp.h&
+namespace muduo
+namespace net
+class EventL
+/// A selectable I/O channel.
+/// This class doesn't own the file descriptor.
+/// The file descriptor could be a socket,
+/// an eventfd, a timerfd, or a signalfd
+class Channel : boost::noncopyable
typedef boost::function&void()& EventC
typedef boost::function&void(Timestamp)& ReadEventC
Channel(EventLoop* loop, int fd);
~Channel();
void handleEvent(Timestamp receiveTime);
void setReadCallback(const ReadEventCallback& cb)
{ readCallback_ = }
void setWriteCallback(const EventCallback& cb)
{ writeCallback_ = }
void setCloseCallback(const EventCallback& cb)
{ closeCallback_ = }
void setErrorCallback(const EventCallback& cb)
{ errorCallback_ = }
/// Tie this channel to the owner object managed by shared_ptr,
/// prevent the owner object being destroyed in handleEvent.
void tie(const boost::shared_ptr&void&&);
int fd() const { return fd_; }
int events() const { return events_; }
void set_revents(int revt) { revents_ = } // used by pollers
// int revents() const { return revents_; }
bool isNoneEvent() const { return events_ == kNoneE }
void enableReading() { events_ |= kReadE update(); }
// void disableReading() { events_ &= ~kReadE update(); }
void enableWriting() { events_ |= kWriteE update(); }
void disableWriting() { events_ &= ~kWriteE update(); }
void disableAll() { events_ = kNoneE update(); }
bool isWriting() const { return events_ & kWriteE }
// for Poller
int index() { return index_; }
void set_index(int idx) { index_ = }
// for debug
string reventsToString()
void doNotLogHup() { logHup_ = }
EventLoop* ownerLoop() { return loop_; }
void remove();
+ private:
void update();
void handleEventWithGuard(Timestamp receiveTime);
static const int kNoneE
static const int kReadE
static const int kWriteE
EventLoop* loop_;
// 所属EventLoop
// 文件描述符,但不负责关闭该文件描述符
// 关注的事件
// poll/epoll返回的事件
// used by Poller.表示在poll的事件数组中的序号
// for POLLHUP
boost::weak_ptr&void& tie_;
bool tied_;
bool eventHandling_;
// 是否处于处理事件中
ReadEventCallback readCallback_;
EventCallback writeCallback_;
EventCallback closeCallback_;
EventCallback errorCallback_;
// MUDUO_NET_CHANNEL_H
Index: net/Timer.cc
===================================================================
--- net/Timer.cc (revision 0)
+++ net/Timer.cc (revision 45)
@@ -0,0 +1,27 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+#include &muduo/net/Timer.h&
+using namespace muduo::
+AtomicInt64 Timer::s_numCreated_;
+void Timer::restart(Timestamp now)
if (repeat_)
// 重新计算下一个超时时刻
expiration_ = addTime(now, interval_);
expiration_ = Timestamp::invalid();
Index: net/Callbacks.h
===================================================================
--- net/Callbacks.h (revision 0)
+++ net/Callbacks.h (revision 45)
@@ -0,0 +1,69 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+// This is a public header file, it must only include public header files.
+#ifndef MUDUO_NET_CALLBACKS_H
+#define MUDUO_NET_CALLBACKS_H
+#include &boost/function.hpp&
+#include &boost/shared_ptr.hpp&
+#include &muduo/base/Timestamp.h&
+namespace muduo
+// Adapted from google-protobuf stubs/common.h
+// see License in muduo/base/Types.h
+template&typename To, typename From&
+inline ::boost::shared_ptr&To& down_pointer_cast(const ::boost::shared_ptr&From&& f) {
if (false) {
implicit_cast&From*, To*&(0);
+#ifndef NDEBUG
assert(f == NULL || dynamic_cast&To*&(get_pointer(f)) != NULL);
return ::boost::static_pointer_cast&To&(f);
+namespace net
+// All client visible callbacks go here.
+class TcpC
+typedef boost::shared_ptr&TcpConnection& TcpConnectionP
+typedef boost::function&void()& TimerC
+typedef boost::function&void (const TcpConnectionPtr&)& ConnectionC
+typedef boost::function&void (const TcpConnectionPtr&)& CloseC
+typedef boost::function&void (const TcpConnectionPtr&)& WriteCompleteC
+typedef boost::function&void (const TcpConnectionPtr&, size_t)& HighWaterMarkC
+// the data has been read to (buf, len)
+typedef boost::function&void (const TcpConnectionPtr&,
Timestamp)& MessageC
+void defaultConnectionCallback(const TcpConnectionPtr& conn);
+void defaultMessageCallback(const TcpConnectionPtr& conn,
Buffer* buffer,
Timestamp receiveTime);
+/*typedef boost::function&void (const TcpConnectionPtr&,
const char* data,
ssize_t len)& MessageC*/
// MUDUO_NET_CALLBACKS_H
Index: net/TcpClient.cc
===================================================================
--- net/TcpClient.cc (revision 0)
+++ net/TcpClient.cc (revision 45)
@@ -0,0 +1,183 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+#include &muduo/net/TcpClient.h&
+#include &muduo/base/Logging.h&
+#include &muduo/net/Connector.h&
+#include &muduo/net/EventLoop.h&
+#include &muduo/net/SocketsOps.h&
+#include &boost/bind.hpp&
+#include &stdio.h&
// snprintf
+using namespace muduo::
+// TcpClient::TcpClient(EventLoop* loop)
: loop_(loop)
+// TcpClient::TcpClient(EventLoop* loop, const string& host, uint16_t port)
: loop_(CHECK_NOTNULL(loop)),
serverAddr_(host, port)
+namespace muduo
+namespace net
+namespace detail
+void removeConnection(EventLoop* loop, const TcpConnectionPtr& conn)
loop-&queueInLoop(boost::bind(&TcpConnection::connectDestroyed, conn));
+void removeConnector(const ConnectorPtr& connector)
//connector-&
+TcpClient::TcpClient(EventLoop* loop,
const InetAddress& serverAddr,
const string& name)
: loop_(CHECK_NOTNULL(loop)),
connector_(new Connector(loop, serverAddr)),
name_(name),
connectionCallback_(defaultConnectionCallback),
messageCallback_(defaultMessageCallback),
retry_(false),
connect_(true),
nextConnId_(1)
// 设置连接成功回调函数
connector_-&setNewConnectionCallback(
boost::bind(&TcpClient::newConnection, this, _1));
// FIXME setConnectFailedCallback
LOG_INFO && &TcpClient::TcpClient[& && name_
&& &] - connector & && get_pointer(connector_);
+TcpClient::~TcpClient()
LOG_INFO && &TcpClient::~TcpClient[& && name_
&& &] - connector & && get_pointer(connector_);
TcpConnectionP
MutexLockGuard lock(mutex_);
conn = connection_;
// FIXME: not 100% safe, if we are in different thread
+ // 重新设置TcpConnection中的closeCallback_为detail::removeConnection
CloseCallback cb = boost::bind(&detail::removeConnection, loop_, _1);
loop_-&runInLoop(
boost::bind(&TcpConnection::setCloseCallback, conn, cb));
// 这种情况,说明connector处于未连接状态,将connector_停止
connector_-&stop();
// FIXME: HACK
loop_-&runAfter(1, boost::bind(&detail::removeConnector, connector_));
+void TcpClient::connect()
// FIXME: check state
LOG_INFO && &TcpClient::connect[& && name_ && &] - connecting to &
&& connector_-&serverAddress().toIpPort();
connect_ =
connector_-&start(); // 发起连接
+// 用于连接已建立的情况下,关闭连接
+void TcpClient::disconnect()
connect_ =
MutexLockGuard lock(mutex_);
if (connection_)
connection_-&shutdown();
+// 停止connector_
+void TcpClient::stop()
connect_ =
connector_-&stop();
+void TcpClient::newConnection(int sockfd)
loop_-&assertInLoopThread();
InetAddress peerAddr(sockets::getPeerAddr(sockfd));
char buf[32];
snprintf(buf, sizeof buf, &:%s#%d&, peerAddr.toIpPort().c_str(), nextConnId_);
++nextConnId_;
string connName = name_ +
InetAddress localAddr(sockets::getLocalAddr(sockfd));
// FIXME poll with zero timeout to double confirm the new connection
// FIXME use make_shared if necessary
TcpConnectionPtr conn(new TcpConnection(loop_,
localAddr,
peerAddr));
conn-&setConnectionCallback(connectionCallback_);
conn-&setMessageCallback(messageCallback_);
conn-&setWriteCompleteCallback(writeCompleteCallback_);
conn-&setCloseCallback(
boost::bind(&TcpClient::removeConnection, this, _1)); // FIXME: unsafe
MutexLockGuard lock(mutex_);
connection_ =
// 保存TcpConnection
conn-&connectEstablished();
// 这里回调connectionCallback_
+void TcpClient::removeConnection(const TcpConnectionPtr& conn)
loop_-&assertInLoopThread();
assert(loop_ == conn-&getLoop());
MutexLockGuard lock(mutex_);
assert(connection_ == conn);
connection_.reset();
loop_-&queueInLoop(boost::bind(&TcpConnection::connectDestroyed, conn));
if (retry_ && connect_)
LOG_INFO && &TcpClient::connect[& && name_ && &] - Reconnecting to &
&& connector_-&serverAddress().toIpPort();
// 这里的重连是指连接建立成功之后被断开的重连
connector_-&restart();
Index: net/TimerQueue.cc
===================================================================
--- net/TimerQueue.cc (revision 0)
+++ net/TimerQueue.cc (revision 45)
@@ -0,0 +1,290 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+#define __STDC_LIMIT_MACROS
+#include &muduo/net/TimerQueue.h&
+#include &muduo/base/Logging.h&
+#include &muduo/net/EventLoop.h&
+#include &muduo/net/Timer.h&
+#include &muduo/net/TimerId.h&
+#include &boost/bind.hpp&
+#include &sys/timerfd.h&
+namespace muduo
+namespace net
+namespace detail
+// 创建定时器
+int createTimerfd()
int timerfd = ::timerfd_create(CLOCK_MONOTONIC,
TFD_NONBLOCK | TFD_CLOEXEC);
if (timerfd & 0)
LOG_SYSFATAL && &Failed in timerfd_create&;
+// 计算超时时刻与当前时间的时间差
+struct timespec howMuchTimeFromNow(Timestamp when)
int64_t microseconds = when.microSecondsSinceEpoch()
- Timestamp::now().microSecondsSinceEpoch();
if (microseconds & 100)
microseconds = 100;
ts.tv_sec = static_cast&time_t&(
microseconds / Timestamp::kMicroSecondsPerSecond);
ts.tv_nsec = static_cast&long&(
(microseconds % Timestamp::kMicroSecondsPerSecond) * 1000);
+// 清除定时器,避免一直触发
+void readTimerfd(int timerfd, Timestamp now)
ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
LOG_TRACE && &TimerQueue::handleRead() & && howmany && & at & && now.toString();
if (n != sizeof howmany)
LOG_ERROR && &TimerQueue::handleRead() reads & && n && & bytes instead of 8&;
+// 重置定时器的超时时间
+void resetTimerfd(int timerfd, Timestamp expiration)
// wake up loop by timerfd_settime()
struct itimerspec newV
struct itimerspec oldV
bzero(&newValue, sizeof newValue);
bzero(&oldValue, sizeof oldValue);
newValue.it_value = howMuchTimeFromNow(expiration);
int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
LOG_SYSERR && &timerfd_settime()&;
+using namespace muduo::
+using namespace muduo::net::
+TimerQueue::TimerQueue(EventLoop* loop)
: loop_(loop),
timerfd_(createTimerfd()),
timerfdChannel_(loop, timerfd_),
timers_(),
callingExpiredTimers_(false)
timerfdChannel_.setReadCallback(
boost::bind(&TimerQueue::handleRead, this));
// we are always reading the timerfd, we disarm it with timerfd_settime.
timerfdChannel_.enableReading();
+TimerQueue::~TimerQueue()
::close(timerfd_);
// do not remove channel, since we're in EventLoop::dtor();
for (TimerList::iterator it = timers_.begin();
it != timers_.end(); ++it)
delete it-&
+TimerId TimerQueue::addTimer(const TimerCallback& cb,
Timestamp when,
double interval)
Timer* timer = new Timer(cb, when, interval);
loop_-&runInLoop(
boost::bind(&TimerQueue::addTimerInLoop, this, timer));
//addTimerInLoop(timer);
return TimerId(timer, timer-&sequence());
+void TimerQueue::cancel(TimerId timerId)
loop_-&runInLoop(
boost::bind(&TimerQueue::cancelInLoop, this, timerId));
//cancelInLoop(timerId);
+void TimerQueue::addTimerInLoop(Timer* timer)
loop_-&assertInLoopThread();
// 插入一个定时器,有可能会使得最早到期的定时器发生改变
bool earliestChanged = insert(timer);
if (earliestChanged)
// 重置定时器的超时时刻(timerfd_settime)
resetTimerfd(timerfd_, timer-&expiration());
+void TimerQueue::cancelInLoop(TimerId timerId)
loop_-&assertInLoopThread();
assert(timers_.size() == activeTimers_.size());
ActiveTimer timer(timerId.timer_, timerId.sequence_);
// 查找该定时器
ActiveTimerSet::iterator it = activeTimers_.find(timer);
if (it != activeTimers_.end())
size_t n = timers_.erase(Entry(it-&first-&expiration(), it-&first));
assert(n == 1); (void)n;
delete it-& // FIXME: no delete please,如果用了unique_ptr,这里就不需要手动删除了
activeTimers_.erase(it);
else if (callingExpiredTimers_)
// 已经到期,并且正在调用回调函数的定时器
cancelingTimers_.insert(timer);
assert(timers_.size() == activeTimers_.size());
+void TimerQueue::handleRead()
loop_-&assertInLoopThread();
Timestamp now(Timestamp::now());
readTimerfd(timerfd_, now);
// 清除该事件,避免一直触发
// 获取该时刻之前所有的定时器列表(即超时定时器列表)
std::vector&Entry& expired = getExpired(now);
callingExpiredTimers_ =
cancelingTimers_.clear();
// safe to callback outside critical section
for (std::vector&Entry&::iterator it = expired.begin();
it != expired.end(); ++it)
// 这里回调定时器处理函数
it-&second-&run();
callingExpiredTimers_ =
// 不是一次性定时器,需要重启
reset(expired, now);
+std::vector&TimerQueue::Entry& TimerQueue::getExpired(Timestamp now)
assert(timers_.size() == activeTimers_.size());
std::vector&Entry&
Entry sentry(now, reinterpret_cast&Timer*&(UINTPTR_MAX));
// 返回第一个未到期的Timer的迭代器
// lower_bound的含义是返回第一个值&=sentry的元素的iterator
// 即*end &= sentry,从而end-&first & now
TimerList::iterator end = timers_.lower_bound(sentry);
assert(end == timers_.end() || now & end-&first);
// 将到期的定时器插入到expired中
std::copy(timers_.begin(), end, back_inserter(expired));
// 从timers_中移除到期的定时器
timers_.erase(timers_.begin(), end);
// 从activeTimers_中移除到期的定时器
for (std::vector&Entry&::iterator it = expired.begin();
it != expired.end(); ++it)
ActiveTimer timer(it-&second, it-&second-&sequence());
size_t n = activeTimers_.erase(timer);
assert(n == 1); (void)n;
assert(timers_.size() == activeTimers_.size());
+void TimerQueue::reset(const std::vector&Entry&& expired, Timestamp now)
Timestamp nextE
for (std::vector&Entry&::const_iterator it = expired.begin();
it != expired.end(); ++it)
ActiveTimer timer(it-&second, it-&second-&sequence());
// 如果是重复的定时器并且是未取消定时器,则重启该定时器
if (it-&second-&repeat()
&& cancelingTimers_.find(timer) == cancelingTimers_.end())
it-&second-&restart(now);
insert(it-&second);
// 一次性定时器或者已被取消的定时器是不能重置的,因此删除该定时器
// FIXME move to a free list
delete it-& // FIXME: no delete please
if (!timers_.empty())
// 获取最早到期的定时器超时时间
nextExpire = timers_.begin()-&second-&expiration();
if (nextExpire.valid())
// 重置定时器的超时时刻(timerfd_settime)
resetTimerfd(timerfd_, nextExpire);
+bool TimerQueue::insert(Timer* timer)
loop_-&assertInLoopThread();
assert(timers_.size() == activeTimers_.size());
// 最早到期时间是否改变
bool earliestChanged =
Timestamp when = timer-&expiration();
TimerList::iterator it = timers_.begin();
// 如果timers_为空或者when小于timers_中的最早到期时间
if (it == timers_.end() || when & it-&first)
earliestChanged =
// 插入到timers_中
std::pair&TimerList::iterator, bool& result
= timers_.insert(Entry(when, timer));
assert(result.second); (void)
// 插入到activeTimers_中
std::pair&ActiveTimerSet::iterator, bool& result
= activeTimers_.insert(ActiveTimer(timer, timer-&sequence()));
assert(result.second); (void)
assert(timers_.size() == activeTimers_.size());
return earliestC
Index: net/TimerQueue.h
===================================================================
--- net/TimerQueue.h (revision 0)
+++ net/TimerQueue.h (revision 45)
@@ -0,0 +1,95 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+// This is an internal header file, you should not include this.
+#ifndef MUDUO_NET_TIMERQUEUE_H
+#define MUDUO_NET_TIMERQUEUE_H
+#include &set&
+#include &vector&
+#include &boost/noncopyable.hpp&
+#include &muduo/base/Mutex.h&
+#include &muduo/base/Timestamp.h&
+#include &muduo/net/Callbacks.h&
+#include &muduo/net/Channel.h&
+namespace muduo
+namespace net
+class EventL
+class TimerId;
+/// A best efforts timer queue.
+/// No guarantee that the callback will be on time.
+class TimerQueue : boost::noncopyable
TimerQueue(EventLoop* loop);
~TimerQueue();
/// Schedules the callback to be run at given time,
/// repeats if @c interval & 0.0.
/// Must be thread safe. Usually be called from other threads.
// 一定是线程安全的,可以跨线程调用。通常情况下被其它线程调用。
TimerId addTimer(const TimerCallback& cb,
Timestamp when,
double interval);
void cancel(TimerId timerId);
+ private:
// FIXME: use unique_ptr&Timer& instead of raw pointers.
// unique_ptr是C++ 11标准的一个独享所有权的智能指针
// 无法得到指向同一对象的两个unique_ptr指针
// 但可以进行移动构造与移动赋值操作,即所有权可以移动到另一个对象(而非拷贝构造)
typedef std::pair&Timestamp, Timer*& E
typedef std::set&Entry& TimerL
typedef std::pair&Timer*, int64_t& ActiveT
typedef std::set&ActiveTimer& ActiveTimerS
// 以下成员函数只可能在其所属的I/O线程中调用,因而不必加锁。
// 服务器性能杀手之一是锁竞争,所以要尽可能少用锁
void addTimerInLoop(Timer* timer);
void cancelInLoop(TimerId timerId);
// called when timerfd alarms
void handleRead();
// move out all expired timers
// 返回超时的定时器列表
std::vector&Entry& getExpired(Timestamp now);
void reset(const std::vector&Entry&& expired, Timestamp now);
bool insert(Timer* timer);
EventLoop* loop_;
// 所属EventLoop
const int timerfd_;
Channel timerfdChannel_;
// Timer list sorted by expiration
TimerList timers_; // timers_是按到期时间排序
// for cancel()
// timers_与activeTimers_保存的是相同的数据
// timers_是按到期时间排序,activeTimers_是按对象地址排序
ActiveTimerSet activeTimers_;
bool callingExpiredTimers_; /* atomic */
ActiveTimerSet cancelingTimers_; // 保存的是被取消的定时器
// MUDUO_NET_TIMERQUEUE_H
Index: net/TcpClient.h
===================================================================
--- net/TcpClient.h (revision 0)
+++ net/TcpClient.h (revision 45)
@@ -0,0 +1,88 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+// This is a public header file, it must only include public header files.
+#ifndef MUDUO_NET_TCPCLIENT_H
+#define MUDUO_NET_TCPCLIENT_H
+#include &boost/noncopyable.hpp&
+#include &muduo/base/Mutex.h&
+#include &muduo/net/TcpConnection.h&
+namespace muduo
+namespace net
+typedef boost::shared_ptr&Connector& ConnectorP
+class TcpClient : boost::noncopyable
// TcpClient(EventLoop* loop);
// TcpClient(EventLoop* loop, const string& host, uint16_t port);
TcpClient(EventLoop* loop,
const InetAddress& serverAddr,
const string& name);
~TcpClient();
// force out-line dtor, for scoped_ptr members.
void connect();
void disconnect();
void stop();
TcpConnectionPtr connection() const
MutexLockGuard lock(mutex_);
return connection_;
bool retry()
void enableRetry() { retry_ = }
/// Set connection callback.
/// Not thread safe.
void setConnectionCallback(const ConnectionCallback& cb)
{ connectionCallback_ = }
/// Set message callback.
/// Not thread safe.
void setMessageCallback(const MessageCallback& cb)
{ messageCallback_ = }
/// Set write complete callback.
/// Not thread safe.
void setWriteCompleteCallback(const WriteCompleteCallback& cb)
{ writeCompleteCallback_ = }
+ private:
/// Not thread safe, but in loop
void newConnection(int sockfd);
/// Not thread safe, but in loop
void removeConnection(const TcpConnectionPtr& conn);
EventLoop* loop_;
ConnectorPtr connector_; // 用于主动发起连接
const string name_;
ConnectionCallback connectionCallback_;
// 连接建立回调函数
MessageCallback messageCallback_;
// 消息到来回调函数
WriteCompleteCallback writeCompleteCallback_; // 数据发送完毕回调函数
bool retry_;
// 重连,是指连接建立之后又断开的时候是否重连
bool connect_; // atomic
// always in loop thread
int nextConnId_;
// name_ + nextConnId_用于标识一个连接
mutable MutexLock mutex_;
TcpConnectionPtr connection_; // Connector连接成功以后,得到一个TcpConnection
// MUDUO_NET_TCPCLIENT_H
Index: net/Socket.cc
===================================================================
--- net/Socket.cc (revision 0)
+++ net/Socket.cc (revision 45)
@@ -0,0 +1,76 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+#include &muduo/net/Socket.h&
+#include &muduo/net/InetAddress.h&
+#include &muduo/net/SocketsOps.h&
+#include &netinet/in.h&
+#include &netinet/tcp.h&
+#include &strings.h&
+using namespace muduo::
+Socket::~Socket()
sockets::close(sockfd_);
+void Socket::bindAddress(const InetAddress& addr)
sockets::bindOrDie(sockfd_, addr.getSockAddrInet());
+void Socket::listen()
sockets::listenOrDie(sockfd_);
+int Socket::accept(InetAddress* peeraddr)
struct sockaddr_
bzero(&addr, sizeof addr);
int connfd = sockets::accept(sockfd_, &addr);
if (connfd &= 0)
peeraddr-&setSockAddrInet(addr);
+void Socket::shutdownWrite()
sockets::shutdownWrite(sockfd_);
+void Socket::setTcpNoDelay(bool on)
int optval = on ? 1 : 0;
::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY,
&optval, sizeof optval);
// FIXME CHECK
+void Socket::setReuseAddr(bool on)
int optval = on ? 1 : 0;
::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR,
&optval, sizeof optval);
// FIXME CHECK
+void Socket::setKeepAlive(bool on)
int optval = on ? 1 : 0;
::setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE,
&optval, sizeof optval);
// FIXME CHECK
Index: net/Connector.cc
===================================================================
--- net/Connector.cc (revision 0)
+++ net/Connector.cc (revision 45)
@@ -0,0 +1,238 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+#include &muduo/net/Connector.h&
+#include &muduo/base/Logging.h&
+#include &muduo/net/Channel.h&
+#include &muduo/net/EventLoop.h&
+#include &muduo/net/SocketsOps.h&
+#include &boost/bind.hpp&
+#include &errno.h&
+using namespace muduo::
+const int Connector::kMaxRetryDelayMs;
+Connector::Connector(EventLoop* loop, const InetAddress& serverAddr)
: loop_(loop),
serverAddr_(serverAddr),
connect_(false),
state_(kDisconnected),
retryDelayMs_(kInitRetryDelayMs)
LOG_DEBUG && &ctor[& && this && &]&;
+Connector::~Connector()
LOG_DEBUG && &dtor[& && this && &]&;
assert(!channel_);
+// 可以跨线程调用
+void Connector::start()
connect_ =
loop_-&runInLoop(boost::bind(&Connector::startInLoop, this)); // FIXME: unsafe
+void Connector::startInLoop()
loop_-&assertInLoopThread();
assert(state_ == kDisconnected);
if (connect_)
connect();
LOG_DEBUG && &do not connect&;
+void Connector::stop()
connect_ =
loop_-&runInLoop(boost::bind(&Connector::stopInLoop, this)); // FIXME: unsafe
// FIXME: cancel timer
+void Connector::stopInLoop()
loop_-&assertInLoopThread();
if (state_ == kConnecting)
setState(kDisconnected);
int sockfd = removeAndResetChannel(); // 将通道从poller中移除关注,并将channel置空
retry(sockfd);
// 这里并非要重连,只是调用sockets::close(sockfd);
+void Connector::connect()
int sockfd = sockets::createNonblockingOrDie(); // 创建非阻塞套接字
int ret = sockets::connect(sockfd, serverAddr_.getSockAddrInet());
int savedErrno = (ret == 0) ? 0 :
switch (savedErrno)
case EINPROGRESS: // 非阻塞套接字,未连接成功返回码是EINPROGRESS表示正在连接
case EINTR:
case EISCONN:
// 连接成功
connecting(sockfd);
case EAGAIN:
case EADDRINUSE:
case EADDRNOTAVAIL:
case ECONNREFUSED:
case ENETUNREACH:
retry(sockfd);
case EACCES:
case EPERM:
case EAFNOSUPPORT:
case EALREADY:
case EBADF:
case EFAULT:
case ENOTSOCK:
LOG_SYSERR && &connect error in Connector::startInLoop & && savedE
sockets::close(sockfd); // 不能重连,关闭sockfd
LOG_SYSERR && &Unexpected error in Connector::startInLoop & && savedE
sockets::close(sockfd);
// connectErrorCallback_();
+// 不能跨线程调用
+void Connector::restart()
loop_-&assertInLoopThread();
setState(kDisconnected);
retryDelayMs_ = kInitRetryDelayMs;
connect_ =
startInLoop();
+void Connector::connecting(int sockfd)
setState(kConnecting);
assert(!channel_);
// Channel与sockfd关联
channel_.reset(new Channel(loop_, sockfd));
// 设置可写回调函数,这时候如果socket没有错误,sockfd就处于可写状态
channel_-&setWriteCallback(
boost::bind(&Connector::handleWrite, this)); // FIXME: unsafe
// 设置错误回调函数
channel_-&setErrorCallback(
boost::bind(&Connector::handleError, this)); // FIXME: unsafe
// channel_-&tie(shared_from_this()); is not working,
// as channel_ is not managed by shared_ptr
channel_-&enableWriting();
// 让Poller关注可写事件
+int Connector::removeAndResetChannel()
channel_-&disableAll();
channel_-&remove();
// 从poller移除关注
int sockfd = channel_-&fd();
// Can't reset channel_ here, because we are inside Channel::handleEvent
// 不能在这里重置channel_,因为正在调用Channel::handleEvent
loop_-&queueInLoop(boost::bind(&Connector::resetChannel, this)); // FIXME: unsafe
+void Connector::resetChannel()
channel_.reset();
// channel_ 置空
+void Connector::handleWrite()
LOG_TRACE && &Connector::handleWrite & && state_;
if (state_ == kConnecting)
int sockfd = removeAndResetChannel(); // 从poller中移除关注,并将channel置空
// socket可写并不意味着连接一定建立成功
// 还需要用getsockopt(sockfd, SOL_SOCKET, SO_ERROR, ...)再次确认一下。
int err = sockets::getSocketError(sockfd);
LOG_WARN && &Connector::handleWrite - SO_ERROR = &
&& err && & & && strerror_tl(err);
retry(sockfd);
else if (sockets::isSelfConnect(sockfd))
LOG_WARN && &Connector::handleWrite - Self connect&;
retry(sockfd);
else // 连接成功
setState(kConnected);
if (connect_)
newConnectionCallback_(sockfd);
sockets::close(sockfd);
// what happened?
assert(state_ == kDisconnected);
+void Connector::handleError()
LOG_ERROR && &Connector::handleError&;
assert(state_ == kConnecting);
int sockfd = removeAndResetChannel();
// 从poller中移除关注,并将channel置空
int err = sockets::getSocketError(sockfd);
LOG_TRACE && &SO_ERROR = & && err && & & && strerror_tl(err);
retry(sockfd);
+// 采用back-off策略重连,即重连时间逐渐延长,0.5s, 1s, 2s, ...直至30s
+void Connector::retry(int sockfd)
sockets::close(sockfd);
setState(kDisconnected);
if (connect_)
LOG_INFO && &Connector::retry - Retry connecting to & && serverAddr_.toIpPort()
&& & in & && retryDelayMs_ && & milliseconds. &;
// 注册一个定时操作,重连
loop_-&runAfter(retryDelayMs_/1000.0,
boost::bind(&Connector::startInLoop, shared_from_this()));
retryDelayMs_ = std::min(retryDelayMs_ * 2, kMaxRetryDelayMs);
LOG_DEBUG && &do not connect&;
Index: net/http/HttpResponse.cc
===================================================================
--- net/http/HttpResponse.cc (revision 0)
+++ net/http/HttpResponse.cc (revision 45)
@@ -0,0 +1,52 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+#include &muduo/net/http/HttpResponse.h&
+#include &muduo/net/Buffer.h&
+#include &stdio.h&
+using namespace muduo::
+void HttpResponse::appendToBuffer(Buffer* output) const
char buf[32];
// 添加响应头
snprintf(buf, sizeof buf, &HTTP/1.1 %d &, statusCode_);
output-&append(buf);
output-&append(statusMessage_);
output-&append(&\r\n&);
if (closeConnection_)
// 如果是短连接,不需要告诉浏览器Content-Length,浏览器也能正确处理
output-&append(&Connection: close\r\n&);
snprintf(buf, sizeof buf, &Content-Length: %zd\r\n&, body_.size()); // 实体长度
output-&append(buf);
output-&append(&Connection: Keep-Alive\r\n&);
// header列表
for (std::map&string, string&::const_iterator it = headers_.begin();
it != headers_.end();
output-&append(it-&first);
output-&append(&: &);
output-&append(it-&second);
output-&append(&\r\n&);
output-&append(&\r\n&); // header与body之间的空行
output-&append(body_);
Index: net/http/tests/HttpServer_test.cc
===================================================================
--- net/http/tests/HttpServer_test.cc (revision 0)
+++ net/http/tests/HttpServer_test.cc (revision 45)
@@ -0,0 +1,154 @@
+#include &muduo/net/http/HttpServer.h&
+#include &muduo/net/http/HttpRequest.h&
+#include &muduo/net/http/HttpResponse.h&
+#include &muduo/net/EventLoop.h&
+#include &muduo/base/Logging.h&
+#include &iostream&
+#include &map&
+using namespace muduo::
+extern char favicon[555];
+bool benchmark =
+// 实际的请求处理
+void onRequest(const HttpRequest& req, HttpResponse* resp)
std::cout && &Headers & && req.methodString() && & & && req.path() && std::
if (!benchmark)
const std::map&string, string&& headers = req.headers();
for (std::map&string, string&::const_iterator it = headers.begin();
it != headers.end();
std::cout && it-&first && &: & && it-&second && std::
if (req.path() == &/&)
resp-&setStatusCode(HttpResponse::k200Ok);
resp-&setStatusMessage(&OK&);
resp-&setContentType(&text/html&);
resp-&addHeader(&Server&, &Muduo&);
string now = Timestamp::now().toFormattedString();
resp-&setBody(&&html&&head&&title&This is title&/title&&/head&&
&&body&&h1&Hello&/h1&Now is & + now +
&&/body&&/html&&);
else if (req.path() == &/favicon.ico&)
resp-&setStatusCode(HttpResponse::k200Ok);
resp-&setStatusMessage(&OK&);
resp-&setContentType(&image/png&);
resp-&setBody(string(favicon, sizeof favicon));
else if (req.path() == &/hello&)
resp-&setStatusCode(HttpResponse::k200Ok);
resp-&setStatusMessage(&OK&);
resp-&setContentType(&text/plain&);
resp-&addHeader(&Server&, &Muduo&);
resp-&setBody(&hello, world!\n&);
resp-&setStatusCode(HttpResponse::k404NotFound);
resp-&setStatusMessage(&Not Found&);
resp-&setCloseConnection(true);
+int main(int argc, char* argv[])
int numThreads = 0;
if (argc & 1)
benchmark =
Logger::setLogLevel(Logger::WARN);
numThreads = atoi(argv[1]);
HttpServer server(&loop, InetAddress(8000), &dummy&);
server.setHttpCallback(onRequest);
server.setThreadNum(numThreads);
server.start();
loop.loop();
+// 这是一个图片数据
+char favicon[555] = {
'\x89', 'P', 'N', 'G', '\xD', '\xA', '\x1A', '\xA',
'\x0', '\x0', '\x0', '\xD', 'I', 'H', 'D', 'R',
'\x0', '\x0', '\x0', '\x10', '\x0', '\x0', '\x0', '\x10',
'\x8', '\x6', '\x0', '\x0', '\x0', '\x1F', '\xF3', '\xFF',
'a', '\x0', '\x0', '\x0', '\x19', 't', 'E', 'X',
't', 'S', 'o', 'f', 't', 'w', 'a', 'r',
'e', '\x0', 'A', 'd', 'o', 'b', 'e', '\x20',
'I', 'm', 'a', 'g', 'e', 'R', 'e', 'a',
'd', 'y', 'q', '\xC9', 'e', '\x3C', '\x0', '\x0',
'\x1', '\xCD', 'I', 'D', 'A', 'T', 'x', '\xDA',
'\x94', '\x93', '9', 'H', '\x3', 'A', '\x14', '\x86',
'\xFF', '\x5D', 'b', '\xA7', '\x4', 'R', '\xC4', 'm',
'\x22', '\x1E', '\xA0', 'F', '\x24', '\x8', '\x16', '\x16',
'v', '\xA', '6', '\xBA', 'J', '\x9A', '\x80', '\x8',
'A', '\xB4', 'q', '\x85', 'X', '\x89', 'G', '\xB0',
'I', '\xA9', 'Q', '\x24', '\xCD', '\xA6', '\x8', '\xA4',
'H', 'c', '\x91', 'B', '\xB', '\xAF', 'V', '\xC1',
'F', '\xB4', '\x15', '\xCF', '\x22', 'X', '\x98', '\xB',
'T', 'H', '\x8A', 'd', '\x93', '\x8D', '\xFB', 'F',
'g', '\xC9', '\x1A', '\x14', '\x7D', '\xF0', 'f', 'v',
'f', '\xDF', '\x7C', '\xEF', '\xE7', 'g', 'F', '\xA8',
'\xD5', 'j', 'H', '\x24', '\x12', '\x2A', '\x0', '\x5',
'\xBF', 'G', '\xD4', '\xEF', '\xF7', '\x2F', '6', '\xEC',
'\x12', '\x20', '\x1E', '\x8F', '\xD7', '\xAA', '\xD5', '\xEA',
'\xAF', 'I', '5', 'F', '\xAA', 'T', '\x5F', '\x9F',
'\x22', 'A', '\x2A', '\x95', '\xA', '\x83', '\xE5', 'r',
'9', 'd', '\xB3', 'Y', '\x96', '\x99', 'L', '\x6',
'\xE9', 't', '\x9A', '\x25', '\x85', '\x2C', '\xCB', 'T',
'\xA7', '\xC4', 'b', '1', '\xB5', '\x5E', '\x0', '\x3',
'h', '\x9A', '\xC6', '\x16', '\x82', '\x20', 'X', 'R',
'\x14', 'E', '6', 'S', '\x94', '\xCB', 'e', 'x',
'\xBD', '\x5E', '\xAA', 'U', 'T', '\x23', 'L', '\xC0',
'\xE0', '\xE2', '\xC1', '\x8F', '\x0', '\x9E', '\xBC', '\x9',
'A', '\x7C', '\x3E', '\x1F', '\x83', 'D', '\x22', '\x11',
'\xD5', 'T', '\x40', '\x3F', '8', '\x80', 'w', '\xE5',
'3', '\x7', '\xB8', '\x5C', '\x2E', 'H', '\x92', '\x4',
'\x87', '\xC3', '\x81', '\x40', '\x20', '\x40', 'g', '\x98',
'\xE9', '6', '\x1A', '\xA6', 'g', '\x15', '\x4', '\xE3',
'\xD7', '\xC8', '\xBD', '\x15', '\xE1', 'i', '\xB7', 'C',
'\xAB', '\xEA', 'x', '\x2F', 'j', 'X', '\x92', '\xBB',
'\x18', '\x20', '\x9F', '\xCF', '3', '\xC3', '\xB8', '\xE9',
'N', '\xA7', '\xD3', 'l', 'J', '\x0', 'i', '6',
'\x7C', '\x8E', '\xE1', '\xFE', 'V', '\x84', '\xE7', '\x3C',
'\x9F', 'r', '\x2B', '\x3A', 'B', '\x7B', '7', 'f',
'w', '\xAE', '\x8E', '\xE', '\xF3', '\xBD', 'R', '\xA9',
'd', '\x2', 'B', '\xAF', '\x85', '2', 'f', 'F',
'\xBA', '\xC', '\xD9', '\x9F', '\x1D', '\x9A', 'l', '\x22',
'\xE6', '\xC7', '\x3A', '\x2C', '\x80', '\xEF', '\xC1', '\x15',
'\x90', '\x7', '\x93', '\xA2', '\x28', '\xA0', 'S', 'j',
'\xB1', '\xB8', '\xDF', '\x29', '5', 'C', '\xE', '\x3F',
'X', '\xFC', '\x98', '\xDA', 'y', 'j', 'P', '\x40',
'\x0', '\x87', '\xAE', '\x1B', '\x17', 'B', '\xB4', '\x3A',
'\x3F', '\xBE', 'y', '\xC7', '\xA', '\x26', '\xB6', '\xEE',
'\xD9', '\x9A', '\x60', '\x14', '\x93', '\xDB', '\x8F', '\xD',
'\xA', '\x2E', '\xE9', '\x23', '\x95', '\x29', 'X', '\x0',
'\x27', '\xEB', 'n', 'V', 'p', '\xBC', '\xD6', '\xCB',
'\xD6', 'G', '\xAB', '\x3D', 'l', '\x7D', '\xB8', '\xD2',
'\xDD', '\xA0', '\x60', '\x83', '\xBA', '\xEF', '\x5F', '\xA4',
'\xEA', '\xCC', '\x2', 'N', '\xAE', '\x5E', 'p', '\x1A',
'\xEC', '\xB3', '\x40', '9', '\xAC', '\xFE', '\xF2', '\x91',
'\x89', 'g', '\x91', '\x85', '\x21', '\xA8', '\x87', '\xB7',
'X', '\x7E', '\x7E', '\x85', '\xBB', '\xCD', 'N', 'N',
'b', 't', '\x40', '\xFA', '\x93', '\x89', '\xEC', '\x1E',
'\xEC', '\x86', '\x2', 'H', '\x26', '\x93', '\xD0', 'u',
'\x1D', '\x7F', '\x9', '2', '\x95', '\xBF', '\x1F', '\xDB',
'\xD7', 'c', '\x8A', '\x1A', '\xF7', '\x5C', '\xC1', '\xFF',
'\x22', 'J', '\xC3', '\x87', '\x0', '\x3', '\x0', 'K',
'\xBB', '\xF8', '\xD6', '\x2A', 'v', '\x98', 'I', '\x0',
'\x0', '\x0', '\x0', 'I', 'E', 'N', 'D', '\xAE',
'B', '\x60', '\x82',
Index: net/http/tests/HttpRequest_unittest.cc
===================================================================
--- net/http/tests/HttpRequest_unittest.cc (revision 0)
+++ net/http/tests/HttpRequest_unittest.cc (revision 45)
@@ -0,0 +1,92 @@
+#include &muduo/net/http/HttpContext.h&
+#include &muduo/net/Buffer.h&
+//#define BOOST_TEST_MODULE BufferTest
+#define BOOST_TEST_MAIN
+#define BOOST_TEST_DYN_LINK
+#include &boost/test/unit_test.hpp&
+using muduo::
+using muduo::T
+using muduo::net::B
+using muduo::net::HttpC
+using muduo::net::HttpR
+namespace muduo
+namespace net
+namespace detail
+bool parseRequest(Buffer* buf, HttpContext* context, Timestamp receiveTime);
+using muduo::net::detail::parseR
+BOOST_AUTO_TEST_CASE(testParseRequestAllInOne)
input.append(&GET /index.html HTTP/1.1\r\n&
&Host: \r\n&
BOOST_CHECK(parseRequest(&input, &context, Timestamp::now()));
BOOST_CHECK(context.gotAll());
const HttpRequest& request = context.request();
BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet);
BOOST_CHECK_EQUAL(request.path(), string(&/index.html&));
BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11);
BOOST_CHECK_EQUAL(request.getHeader(&Host&), string(&&));
BOOST_CHECK_EQUAL(request.getHeader(&User-Agent&), string(&&));
+BOOST_AUTO_TEST_CASE(testParseRequestInTwoPieces)
string all(&GET /index.html HTTP/1.1\r\n&
&Host: \r\n&
for (size_t sz1 = 0; sz1 & all.size(); ++sz1)
input.append(all.c_str(), sz1);
BOOST_CHECK(parseRequest(&input, &context, Timestamp::now()));
BOOST_CHECK(!context.gotAll());
size_t sz2 = all.size() - sz1;
input.append(all.c_str() + sz1, sz2);
BOOST_CHECK(parseRequest(&input, &context, Timestamp::now()));
BOOST_CHECK(context.gotAll());
const HttpRequest& request = context.request();
BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet);
BOOST_CHECK_EQUAL(request.path(), string(&/index.html&));
BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11);
BOOST_CHECK_EQUAL(request.getHeader(&Host&), string(&&));
BOOST_CHECK_EQUAL(request.getHeader(&User-Agent&), string(&&));
+BOOST_AUTO_TEST_CASE(testParseRequestEmptyHeaderValue)
input.append(&GET /index.html HTTP/1.1\r\n&
&Host: \r\n&
&User-Agent:\r\n&
&Accept-Encoding: \r\n&
BOOST_CHECK(parseRequest(&input, &context, Timestamp::now()));
BOOST_CHECK(context.gotAll());
const HttpRequest& request = context.request();
BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet);
BOOST_CHECK_EQUAL(request.path(), string(&/index.html&));
BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11);
BOOST_CHECK_EQUAL(request.getHeader(&Host&), string(&&));
BOOST_CHECK_EQUAL(request.getHeader(&User-Agent&), string(&&));
BOOST_CHECK_EQUAL(request.getHeader(&Accept-Encoding&), string(&&));
Index: net/http/HttpResponse.h
===================================================================
--- net/http/HttpResponse.h (revision 0)
+++ net/http/HttpResponse.h (revision 45)
@@ -0,0 +1,80 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+// This is a public header file, it must only include public header files.
+#ifndef MUDUO_NET_HTTP_HTTPRESPONSE_H
+#define MUDUO_NET_HTTP_HTTPRESPONSE_H
+#include &muduo/base/copyable.h&
+#include &muduo/base/Types.h&
+#include &map&
+namespace muduo
+namespace net
+class HttpResponse : public muduo::copyable
enum HttpStatusCode
k200Ok = 200,
k301MovedPermanently = 301,
// 301重定向,请求的页面永久性移至另一个地址
k400BadRequest = 400,
// 错误的请求,语法格式有错,服务器无法处理此请求
k404NotFound = 404,
// 请求的网页不存在
explicit HttpResponse(bool close)
: statusCode_(kUnknown),
closeConnection_(close)
void setStatusCode(HttpStatusCode code)
{ statusCode_ = }
void setStatusMessage(const string& message)
{ statusMessage_ = }
void setCloseConnection(bool on)
{ closeConnection_ = }
bool closeConnection() const
{ return closeConnection_; }
// 设置文档媒体类型(MIME)
void setContentType(const string& contentType)
{ addHeader(&Content-Type&, contentType); }
// FIXME: replace string with StringPiece
void addHeader(const string& key, const string& value)
{ headers_[key] = }
void setBody(const string& body)
{ body_ = }
void appendToBuffer(Buffer* output) // 将HttpResponse添加到Buffer
+ private:
std::map&string, string& headers_; // header列表
HttpStatusCode statusCode_;
// 状态响应码
// FIXME: add http version
string statusMessage_;
// 状态响应码对应的文本信息
bool closeConnection_;
// 是否关闭连接
string body_;
// MUDUO_NET_HTTP_HTTPRESPONSE_H
Index: net/http/HttpContext.h
===================================================================
--- net/http/HttpContext.h (revision 0)
+++ net/http/HttpContext.h (revision 45)
@@ -0,0 +1,81 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+// This is an internal header file, you should not include this.
+#ifndef MUDUO_NET_HTTP_HTTPCONTEXT_H
+#define MUDUO_NET_HTTP_HTTPCONTEXT_H
+#include &muduo/base/copyable.h&
+#include &muduo/net/http/HttpRequest.h&
+namespace muduo
+namespace net
+class HttpContext : public muduo::copyable
enum HttpRequestParseState
kExpectRequestLine,
kExpectHeaders,
kExpectBody,
HttpContext()
: state_(kExpectRequestLine)
// default copy-ctor, dtor and assignment are fine
bool expectRequestLine() const
{ return state_ == kExpectRequestL }
bool expectHeaders() const
{ return state_ == kExpectH }
bool expectBody() const
{ return state_ == kExpectB }
bool gotAll() const
{ return state_ == kGotA }
void receiveRequestLine()
{ state_ = kExpectH }
void receiveHeaders()
{ state_ = kGotA }
// 重置HttpContext状态
void reset()
state_ = kExpectRequestL
request_.swap(dummy);
const HttpRequest& request() const
{ return request_; }
HttpRequest& request()
{ return request_; }
+ private:
HttpRequestParseState state_;
// 请求解析状态
HttpRequest request_;
// http请求
// MUDUO_NET_HTTP_HTTPCONTEXT_H
Index: net/http/HttpServer.cc
===================================================================
--- net/http/HttpServer.cc (revision 0)
+++ net/http/HttpServer.cc (revision 45)
@@ -0,0 +1,203 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+#include &muduo/net/http/HttpServer.h&
+#include &muduo/base/Logging.h&
+#include &muduo/net/http/HttpContext.h&
+#include &muduo/net/http/HttpRequest.h&
+#include &muduo/net/http/HttpResponse.h&
+#include &boost/bind.hpp&
+using namespace muduo::
+namespace muduo
+namespace net
+namespace detail
+// FIXME: move to HttpContext class
+bool processRequestLine(const char* begin, const char* end, HttpContext* context)
bool succeed =
const char* start =
const char* space = std::find(start, end, ' ');
HttpRequest& request = context-&request();
if (space != end && request.setMethod(start, space))
// 解析请求方法
start = space+1;
space = std::find(start, end, ' ');
if (space != end)
request.setPath(start, space); // 解析PATH
start = space+1;
succeed = end-start == 8 && std::equal(start, end-1, &HTTP/1.&);
if (succeed)
if (*(end-1) == '1')
request.setVersion(HttpRequest::kHttp11);
// HTTP/1.1
else if (*(end-1) == '0')
request.setVersion(HttpRequest::kHttp10);
// HTTP/1.0
+// FIXME: move to HttpContext class
+// return false if any error
+bool parseRequest(Buffer* buf, HttpContext* context, Timestamp receiveTime)
bool hasMore =
while (hasMore)
if (context-&expectRequestLine()) // 处于解析请求行状态
const char* crlf = buf-&findCRLF();
ok = processRequestLine(buf-&peek(), crlf, context); // 解析请求行
context-&request().setReceiveTime(receiveTime);
// 设置请求时间
buf-&retrieveUntil(crlf + 2);
// 将请求行从buf中取回,包括\r\n
context-&receiveRequestLine(); // 将HttpContext状态改为kExpectHeaders
else if (context-&expectHeaders())
// 解析header
const char* crlf = buf-&findCRLF();
const char* colon = std::find(buf-&peek(), crlf, ':');
//冒号所在位置
if (colon != crlf)
context-&request().addHeader(buf-&peek(), colon, crlf);
// empty line, end of header
context-&receiveHeaders();
// HttpContext将状态改为kGotAll
hasMore = !context-&gotAll();
buf-&retrieveUntil(crlf + 2);
// 将header从buf中取回,包括\r\n
else if (context-&expectBody())
// 当前还不支持请求中带body
+void defaultHttpCallback(const HttpRequest&, HttpResponse* resp)
resp-&setStatusCode(HttpResponse::k404NotFound);
resp-&setStatusMessage(&Not Found&);
resp-&setCloseConnection(true);
+HttpServer::HttpServer(EventLoop* loop,
const InetAddress& listenAddr,
const string& name)
: server_(loop, listenAddr, name),
httpCallback_(detail::defaultHttpCallback)
server_.setConnectionCallback(
boost::bind(&HttpServer::onConnection, this, _1));
server_.setMessageCallback(
boost::bind(&HttpServer::onMessage, this, _1, _2, _3));
+HttpServer::~HttpServer()
+void HttpServer::start()
LOG_WARN && &HttpServer[& && server_.name()
&& &] starts listenning on & && server_.hostport();
server_.start();
+void HttpServer::onConnection(const TcpConnectionPtr& conn)
if (conn-&connected())
conn-&setContext(HttpContext()); // TcpConnection与一个HttpContext绑定
+void HttpServer::onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime)
HttpContext* context = boost::any_cast&HttpContext&(conn-&getMutableContext());
if (!detail::parseRequest(buf, context, receiveTime))
conn-&send(&HTTP/1.1 400 Bad Request\r\n\r\n&);
conn-&shutdown();
// 请求消息解析完毕
if (context-&gotAll())
onRequest(conn, context-&request());
context-&reset();
// 本次请求处理完毕,重置HttpContext,适用于长连接
+void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req)
const string& connection = req.getHeader(&Connection&);
bool close = connection == &close& ||
(req.getVersion() == HttpRequest::kHttp10 && connection != &Keep-Alive&);
HttpResponse response(close);
httpCallback_(req, &response);
response.appendToBuffer(&buf);
conn-&send(&buf);
if (response.closeConnection())
conn-&shutdown();
Index: net/http/HttpServer.h
===================================================================
--- net/http/HttpServer.h (revision 0)
+++ net/http/HttpServer.h (revision 45)
@@ -0,0 +1,68 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+// This is a public header file, it must only include public header files.
+#ifndef MUDUO_NET_HTTP_HTTPSERVER_H
+#define MUDUO_NET_HTTP_HTTPSERVER_H
+#include &muduo/net/TcpServer.h&
+#include &boost/noncopyable.hpp&
+namespace muduo
+namespace net
+class HttpR
+class HttpR
+/// A simple embeddable HTTP server designed for report status of a program.
+/// It is not a fully HTTP 1.1 compliant server, but provides minimum features
+/// that can communicate with HttpClient and Web browser.
+/// It is synchronous, just like Java Servlet.
+class HttpServer : boost::noncopyable
typedef boost::function&void (const HttpRequest&,
HttpResponse*)& HttpC
HttpServer(EventLoop* loop,
const InetAddress& listenAddr,
const string& name);
~HttpServer();
// force out-line dtor, for scoped_ptr members.
/// Not thread safe, callback be registered before calling start().
void setHttpCallback(const HttpCallback& cb)
httpCallback_ =
void setThreadNum(int numThreads)
server_.setThreadNum(numThreads);
void start();
+ private:
void onConnection(const TcpConnectionPtr& conn);
void onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime);
void onRequest(const TcpConnectionPtr&, const HttpRequest&);
TcpServer server_;
HttpCallback httpCallback_; // 在处理http请求(即调用onRequest)的过程中回调此函数,对请求进行具体的处理
// MUDUO_NET_HTTP_HTTPSERVER_H
Index: net/http/CMakeLists.txt
===================================================================
--- net/http/CMakeLists.txt (revision 0)
+++ net/http/CMakeLists.txt (revision 45)
@@ -0,0 +1,28 @@
+set(http_SRCS
HttpServer.cc
HttpResponse.cc
+add_library(muduo_http ${http_SRCS})
+target_link_libraries(muduo_http muduo_net)
+install(TARGETS muduo_http DESTINATION lib)
+set(HEADERS
HttpRequest.h
HttpResponse.h
HttpServer.h
+install(FILES ${HEADERS} DESTINATION include/muduo/net/http)
+if(NOT CMAKE_BUILD_NO_EXAMPLES)
+add_executable(httpserver_test tests/HttpServer_test.cc)
+target_link_libraries(httpserver_test muduo_http)
+if(BOOSTTEST_LIBRARY)
+add_executable(httprequest_unittest tests/HttpRequest_unittest.cc)
+target_link_libraries(httprequest_unittest muduo_http boost_unit_test_framework)
+# add_subdirectory(tests)
Index: net/http/HttpRequest.h
===================================================================
--- net/http/HttpRequest.h (revision 0)
+++ net/http/HttpRequest.h (revision 45)
@@ -0,0 +1,178 @@
+// Copyright 2010, Shuo Chen.
All rights reserved.
+// /p/muduo/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the License file.
+// Author: Shuo Chen (chenshuo at chenshuo dot com)
+// This is a public header file, it must only include public header files.
+#ifndef MUDUO_NET_HTTP_HTTPREQUEST_H
+#define MUDUO_NET_HTTP_HTTPREQUEST_H
+#include &muduo/base/copyable.h&
+#include &muduo/base/Timestamp.h&
+#include &muduo/base/Types.h&
+#include &map&
+#include &assert.h&
+#include &stdio.h&
+namespace muduo
+namespace net
+class HttpRequest : public muduo::copyable
enum Method
kInvalid, kGet, kPost, kHead, kPut, kDelete
enum Version
kUnknown, kHttp10, kHttp11
HttpRequest()
: method_(kInvalid),
version_(kUnknown)
void setVersion(Version v)
version_ =
Version getVersion() const
{ return version_; }
bool setMethod(const char* start, const char* end)
assert(method_ == kInvalid);
string m(start, end);
if (m == &GET&)
method_ = kG
else if (m == &POST&)
method_ = kP
else if (m == &HEAD&)
method_ = kH
else if (m == &PUT&)
method_ = kP
else if (m == &DELETE&)
method_ = kD
method_ = kI
return method_ != kI
Method method() const
{ return method_; }
const char* methodString() const
const char* result = &UNKNOWN&;
switch(method_)
case kGet:
result = &GET&;
case kPost:
result = &POST&;
case kHead:
result = &HEAD&;
case kPut:
result = &PUT&;
case kDelete:
result = &DELETE&;
void setPath(const char* start, const char* end)
path_.assign(start, end);
const string& path() const
{ return pat

我要回帖

更多关于 checkslavecount 的文章

 

随机推荐