1. 程式人生 > >muduo網路庫原始碼解析 五

muduo網路庫原始碼解析 五

TcpConnection用來管理連線,包括連線的狀態、訊息的處理(發、收),該類是muduo中唯一一個實用shared_ptr來進行管理的類,也是唯一繼承enable_shared_from_this的類,這源於TcpConnection類的模糊的生命期。在本章的結尾我們會進行分析。

我們首先來分析一下私有成員:

enum StateE { kConnecting, kConnected, kDisconnected};    //連線的狀態
void setState(StateE s) { state_ = s; }   //設定狀態
//處理讀、寫、關閉、錯誤事件
void handleRead();
void handleWrite();
void handleClose();
void handleError();

EventLoop *loop_;  //記錄所屬的EventLoop
std::string name_;  //記錄連線的名稱
StateE state_;  //記錄連線的狀態
std::unique_ptr<Socket> socket_;  //不明所以,暫且認為記錄檔案描述符fd
std::unique_ptr<Channel> channel_;  //管理fd,設定各種型別的回撥,並加入poller佇列
InetAddress localAddr_;  //記錄本地地址
InetAddress peerAddr_;   //記錄對端地址
ConnectionCallback connectionCallback_;  //連接回調函式
MessageCallback messageCallback_;  //訊息到來回調函式
CloseCallback closeCallback_;  //關閉回撥
建構函式如下:
TcpConnection::TcpConnection(EventLoop *loop, const std::string name,
	int sockfd, const InetAddress &localAddr, const InetAddress &peerAddr)
	:loop_(loop),
	name_(name),
	socket_(new Socket(sockfd)),
	localAddr_(localAddr),
	peerAddr_(peerAddr),
	channel_(new Channel(loop_, socket_->fd())),
	state_(kConnecting)
{
	std::cout << "TcpConnection::ctor[" << name_ << "] at " << this
		<< " fd=" << sockfd<<"\n";
	channel_->setReadCallback(
		std::bind(&TcpConnection::handleRead, this)
	);
	channel_->setCloseCallback(
		std::bind(&TcpConnection::handleClose, this));
	/*
	channel_->setErrorCallback(
		std::bind(&TcpConnection::handleError, this));
	*/
}
除了對成員進行初始化外,在Channel中設定了讀、寫(當前程式碼沒有加上)、關閉、錯誤回撥函式。

另外還有兩個重要的public成員函式:

void connectEstablished();
void connectDestroyed();
一個是連線建立,一個是連線銷燬,定義如下:
void TcpConnection::connectEstablished()
{
	loop_->assertInLoopThread();
	setState(kConnected);
	channel_->enableReading();
	connectionCallback_(shared_from_this());
}

void TcpConnection::connectDestroyed()
{
	loop_->assertInLoopThread();
	setState(kDisconnected);
	channel_->disableAll();
	loop_->removeChannel(channel_.get());
}
連線建立,首先設定狀態為kConnected,接著呼叫channel的enableReading,將connfd加入poller佇列,最後呼叫connectionCallback_回撥,注意,這裡用的是shared_from_this()。

連線銷燬,同樣,首先設定狀態為kDisconnected,然後呼叫channel的disableAll,將connfd從polle佇列中刪除,最後呼叫loop的removeChannel將channel刪除

這兩個函式供上層呼叫,即TcpServer呼叫。
下面我們來分析一下TcpConnection的生命期。首先TcpConnectionPtr是一個智慧指標型別——shared_ptr,TcpConnection首次建立是在TcpServer::newConnection函式中

TcpConnectionPtr conn(
		new TcpConnection(loop_, connName, sockfd, localAddr, peerAddr)
	);
此時,引用計數為1,而後為了管理,conn被放入connections_(是一個map)中,引用計數為2。又由於onConnection和onMessage都是傳入的shared_from_this(),所以引用計數都會增加。TcpServer::newConnection結束後,引用計數會減1。就是說,如果沒有呼叫回撥函式,那麼conn的引用計數最終為1,即存在於connections_中。那麼什麼時候引用計數為0,conn被析構呢?上層TcpServer呼叫removeConnection,該函式會接受一個conn的引用,會增加引用計數,接著呼叫connections_刪除map中的conn,引用計數減1,接著呼叫conn的connectionDestroy,處理與conn相關的channel,當次函式結束的時候,引用計數減為0(如果此時沒有呼叫messageCallback或者其它回撥的話),conn會被析構。

我們開始的時候提到,用shared_ptr來管理TcpConnection,是因為TcpConnection的生命期比較模糊。在完整的muduo中,主執行緒只負責接受連線,然後在TcpConnection::newConnection中啟動一個執行緒,把TcpConnection放入該執行緒處理。conn的各種事件都在新的執行緒中處理。比如當conn正在處理一個request,此時執行緒是“阻塞”在這個處理上的,客戶端這時候斷開連線,執行緒的EventLoop會收到close事件,但是此時執行緒“阻塞”在處理request中,並不能馬上處理close事件,只有當request結束後,才會處理close事件。所以,對伺服器端來說,只有當conn不在被使用且客戶端斷開連線的時候,conn才會被析構。書上說使用shared_ptr管理連線,可以防止串話。
關於TcpConnection生命期分析的不知道對不對,如果有不正確的地方,見諒。

相關推薦

muduo網路原始碼解析

TcpConnection用來管理連線,包括連線的狀態、訊息的處理(發、收),該類是muduo中唯一一個實用shared_ptr來進行管理的類,也是唯一繼承enable_shared_from_this的類,這源於TcpConnection類的模糊的生命期。在本章的結尾我們

muduo網路原始碼解析

這一章節,我們來分析多執行緒TcpServer,首先分析muduo one loop per thread的基石——EventLoopThread class,EventLoopThread會啟動自己的執行緒,並在其中執行EventLoop::loop(),關鍵的start

muduo網路原始碼解析

這一章節我們首先來解析用到的socket的基礎函式: 1、位元組序轉換函式封裝為HostToNetwork16、HostToNetwork32類似命名,原函式為htons、htonl,封裝後方便記憶與書寫,標頭檔案<netinet/in.h> 2、地址轉換函式t

muduo網路學習筆記() 連結器Connector與監聽器Acceptor

本篇繼續為前面封裝的EventLoop新增事件,到現在共給EventLoop添加了兩個fd,Timerfd,EventFd分別用於處理定時任務和通知事件. 今天新增的Acceptor會增加另一個fd,此fd是是一個socket,用於監聽套接字連線.同時封裝非組賽網路程式設計中的connect(2)的

muduo網路原始碼閱讀Step by Step

Posted on: Nov 26 2015 Categories: muduo C++ Tags: muduo 一般寫服務端程式都需要有一個稱手的網路庫來幫我們處理瑣碎的網路通訊細節,比如連線的建立、關閉,讀取資料,傳送資料,接收、傳送緩衝區的管理等,常用的C/C++網路庫有libevent,

Muduo網路原始碼分析(四)EventLoopThread和EventLoopThreadPool的封裝

muduo的併發模型為one loop per thread+ threadpool。為了方便使用,muduo封裝了EventLoop和Thread為EventLoopThread,為了方便使用執行緒

Muduo網路原始碼分析(二) 定時器TimeQueue,Timer,TimerId

首先,我們先要明白為什麼需要設計這樣一個定時器類? 在開發Linux網路程式時,通常需要維護多個定時器,如維護客戶端心跳時間、檢查多個數據包的超時重傳等。如果採用linux的SIGALARM訊號實現,則會帶來較大的系統開銷,且不便於管理。 Muduo 的 Timer

【 專欄 】- muduo網路原始碼分析

muduo網路庫原始碼分析 muduo是基於Reactor模式的C++網路庫,採用Reactor + 執行緒池的方法提高併發性。內部對於事件驅動,執行緒池,定時器,io複用的設計都非常值得學習。設計技巧對C++程式碼風格有很大的幫

Muduo網路原始碼分析(一) EventLoop事件迴圈(Poller和Channel)

從這一篇博文起,我們開始剖析Muduo網路庫的原始碼,主要結合《Linux多執行緒服務端程式設計》和網上的一些學習資料! (一)TCP網路程式設計的本質:三個半事件 1. 連線的建立,包括服務端接受(accept) 新連線和客戶端成功發起(connect) 連線。TCP 連

Muduo 網路原始碼分析 之 關鍵技術點總結

最近又把muduo網路庫仔細研究了一遍,收穫良多。本文將對muduo中的設計思想以及關鍵的技術細節進行總結和分析,當然由於篇幅的原因這裡更多的是對關鍵技術的簡略提及,具體細節還需要讀者自己去查詢學習資料。 muduo/base Date類 日期類的封裝,

muduo網路原始碼學習————執行緒池實現

muduo庫裡面的執行緒池是固定執行緒池,即建立的執行緒池裡面的執行緒個數是一定的,不是動態的。執行緒池裡面一般要包含執行緒佇列還有任務佇列,外部程式將任務存放到執行緒池的任務佇列中,執行緒池中的執行緒佇列執行任務,也是一種生產者和消費者模型。muduo庫中的執

Muduo網路原始碼分析(三)執行緒間使用eventfd通訊和EventLoop::runInLoop系列函式

先說第一點,執行緒(程序)間通訊有很多種方式(pipe,socketpair),為什麼這裡選擇eventfd? eventfd 是一個比 pipe 更高效的執行緒間事件通知機制,一方面它比 pipe

muduo網路學習筆記(三)TimerQueue定時器佇列

目錄 muduo網路庫學習筆記(三)TimerQueue定時器佇列 Linux中的時間函式 timerfd簡單使用介紹 timerfd示例 muduo中對timerfd的封裝 TimerQueue的結構.

muduo網路學習筆記(四) 通過eventfd實現的事件通知機制

目錄 muduo網路庫學習筆記(四) 通過eventfd實現的事件通知機制 eventfd的使用 eventfd系統函式 使用示例 EventLoop對eventfd的封裝 工作時序 runInLoo

muduo網路架構總結

目錄 muduo網路庫架構總結 muduo網路庫服務端的類圖 muduo網路庫模組組成 Recator反應器 EventLoop的兩個元件 TimerQueue定時器 Eventfd Connector和Accepto

muduo網路——詳解muduo多執行緒模型

6.3     非阻塞網路程式設計應該用邊沿觸發(ET)還是電平觸發(LT)?如果是電平觸發,那麼什麼時候關注POLLOUT事件?會不會造成busy-loop?如果是邊沿觸發,如果和防止漏讀造成的飢餓? epoll一定比poll快麼? 6.4        在fi

Retrofit網路請求原始碼解析

1.使用者的retrofit建立 /** * 初始化Retrofit */ public static void init() { okHttpClient = HttpsUtils.getOKHttpClient(); //設定Retrofit

muduo網路——Buffer類的設計與使用

muduo Buffer設計要點: 1.一塊連續的記憶體(char *p, int len)。 2.size()可以自動增長,以適應不同大小的訊息。 3.內部以std::vector<char>來儲存資料,並提供相應的訪問函式。 Buffer像一個que

dubbo原始碼解析() DubboProtocol

DubboProtocol 這個類繼承自AbstractProtocol,實現了Protocol介面,也就是實現了export和refer方法 首先看一下export方法 public <T> Exporter<T> export(Invoker<T> invok

ReactiveSwift原始碼解析() SignalProtocol的observe()、Map、Filter延展實現

上篇部落格我們對Signal的基本實現以及Signal的面向協議擴充套件進行了介紹, 詳細內容請移步於《》。並且聊了Signal的所有的g功能擴充套件都是放在Signal所實現的SignalProtocol協議的擴充套件中的。本篇部落格就沿襲上篇部落格的內容,我們來聊一下SignalProtocol的部分擴充