天天看點

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_

使用

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++網絡庫

繼續閱讀