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