muduo是怎么对Buffer进行封装的介绍见:muduo源码分析之Buffer设计
使用Buffer处理数据的输入,而不是原始的char*
,并且我们要求套接字描述符可读时获取消息到达的时间,因此需要重新添加poll返回的回调类型。
为回调添加时间戳参数
class Channel :boost::noncopyable
{
public:
//...
//添加带时间戳参数的回调函数类型。
typedef boost::function<void(Timestamp)>ReadEventCallback;
//...
};
在Channel的handleEvent方法中就需要进行一些小小的修改:
void Channel::handleEvent(Timestamp receiveTime)
{
///...
if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) {
if (readCallback_) readCallback_(receiveTime);
}
//...
}
测试上述功能,对s07/test3.cc进行修改,对回调函数添加时间戳参数:
void timeout(muduo::Timestamp receiveTime)
{
//...
//...
}
当计时器的timerfd超时时,描述符可读,将会调用用户回调,此时我们可以获取时间。
使用Buffer作为输入缓冲
使用封装的Buffer替代原始的char*。
对于一个TcpConnection,将Buffer作为其数据成员,读取接收缓冲的数据,作为输入缓冲,因此,在TcpConnection中添加成员Buffer inputBuffer_;
class TcpConnection : boost::noncopyable,
public boost::enable_shared_from_this<TcpConnection>{
//....
InetAddress peerAddr_;
ConnectionCallback connectionCallback_;
MessageCallback messageCallback_;
CloseCallback closeCallback_;
Buffer inputBuffer_;
};
在对TcpConnection中handleRead回调(该回调将传递给channel对象中的回调)进行修改。
主要两点:
1.添加了时间戳参数。
2.使用Buffer::readFd()读取数据。
@@ -1,12 +1,14 @@
-void TcpConnection::handleRead()
+void TcpConnection::handleRead(Timestamp receiveTime)
{
- char buf[65536];
- ssize_t n = ::read(channel_->fd(), buf, sizeof buf);
+ int savedErrno = 0;
+ ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno);
if (n > 0) {
- messageCallback_(shared_from_this(), buf, n);//
+ messageCallback_(shared_from_this(), &inputBuffer_, receiveTime);
} else if (n == 0) {
handleClose();
} else {
+ errno = savedErrno;
+ LOG_SYSERR << "TcpConnection::handleRead";
handleError();
}
}
做了如上改动之后,在handleRead()
函数中调用messageCallback_
使用Buffer
和Timestamp
作为参数,因此,在测试代码中,重写onMessage
函数
void onMessage(const muduo::TcpConnectionPtr& conn,
muduo::Buffer* buf,
muduo::Timestamp receiveTime)
{
printf("onMessage(): received %zd bytes from connection [%s] at %s\n",
buf->readableBytes(),
conn->name().c_str(),
receiveTime.toFormattedString().c_str());
printf("onMessage(): [%s]\n", buf->retrieveAsString().c_str());
}
至于Buffer::readFd()
在muduo源码分析之Buffer设计已经说明,使用了一个栈上变量来处理大数据量的情形。
这样做的好处有:
1.使用scatter/gather IO并且一部分缓冲取自stack,这样输入缓冲足够大,通常一次
readv
调用就能取完全部数据。
2.采用电平触发,没有通过EAGAIN反复调用read,这样做高效的,因为每次读取数据只需要一次系统调用。
参考
Linux多线程服务端编程使用muduoC++网络库