muduo源码分析之使用封装的Buffer读取数据


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_使用BufferTimestamp作为参数,因此,在测试代码中,重写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++网络库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值