muduo網路庫學習之EventLoop(七):TcpClient、Connector
Connector 主要用於發起連線,並帶有自動重連的功能,成員主要有一個channel_,
C++ Code
1
|
boost::scoped_ptr<Channel> channel_; // Connector所對應的Channel
|
與Acceptor 相比少了一個acceptSocket_ 成員,因為Connector 是建立一個新的sockfd 並connect 它,如下:Connector::start()-->Connector::startInLoop()-->void Connector::connect()
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void Connector::connect()
{ int sockfd = sockets::createNonblockingOrDie(); // 建立非阻塞套接字 int ret = sockets::connect(sockfd, serverAddr_.getSockAddrInet()); int savedErrno = (ret == 0) ? 0 : errno; switch (savedErrno) { case 0: case EINPROGRESS: // 非阻塞套接字,未連線成功返回碼是EINPROGRESS表示正在連線 case EINTR: case EISCONN: // 連線成功 connecting(sockfd); break; .... } } |
-->Connector::connecting()
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void Connector::connecting(int sockfd)
{ setState(kConnecting); assert(!channel_); // Channel與sockfd關聯 channel_.reset(new Channel(loop_, sockfd)); // 設定可寫回撥函式,這時候如果socket沒有錯誤,sockfd就處於可寫狀態 channel_->setWriteCallback( boost::bind(&Connector::handleWrite, this)); // FIXME: unsafe // 設定錯誤回撥函式 channel_->setErrorCallback( boost::bind(&Connector::handleError, this)); // FIXME: unsafe channel_->enableWriting(); // 讓Poller關注可寫事件 } |
現在connnect(sockfd) 沒有出錯,sockfd 就處於可寫狀態(核心緩衝區不為滿),而且poller 關注了可寫事件,觸發呼叫Connector::handleWrite()
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
void Connector::handleWrite()
{ LOG_TRACE << "Connector::handleWrite " << state_; if (state_ == kConnecting) { int sockfd = removeAndResetChannel(); // 從poller中移除關注,並將channel置空 // socket可寫並不意味著連線一定建立成功 // 還需要用getsockopt(sockfd, SOL_SOCKET, SO_ERROR, ...)再次確認一下。 int err = sockets::getSocketError(sockfd); ...... else // 連線成功 { setState(kConnected); if (connect_) { newConnectionCallback_(sockfd); // 回撥 } } } } |
注意:在handleWrite()裡面需要removeAndResetChannel(),因此此時連線建立,故不用再關注channel的可寫事件,最終會執行 channel_.reset(); 即把channel析構了。此外函式需要返回sockfd, 讓TcpConnection來接管。
連線成功後呼叫newConnectionCallback_(sockfd); 通過下面函式設定:
C++ Code
1
2 3 4 |
void setNewConnectionCallback(const NewConnectionCallback &cb)
{ newConnectionCallback_ = cb; } |
實際上 Connector 一般也不單獨使用,作為TcpClient 的成員:
C++ Code
1
2 |
typedef boost::shared_ptr<Connector> ConnectorPtr;
ConnectorPtr connector_; // 用於主動發起連線 |
但TcpClient 與 TcpServer 不同的是隻有一個TcpConnection 成員:
C++ Code
1
|
TcpConnectionPtr connection_; // Connector連線成功以後,得到一個TcpConnection
|
即一個TcpClient 對應一個TcpConnection 和一個 Connector;而一個TcpServer 對應一個TcpConnection 列表 和 一個 Acceptor。
在TcpClient 建構函式中:
C++ Code
1
2 3 |
// 設定連線成功回撥函式
connector_->setNewConnectionCallback( boost::bind(&TcpClient::newConnection, this, _1)); |
也就是說現在會執行TcpClient::newConnectionn()
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
void TcpClient::newConnection(int sockfd)
{ ........... TcpConnectionPtr conn(new TcpConnection(loop_, connName, sockfd, localAddr, peerAddr)); conn->setConnectionCallback(connectionCallback_); conn->setMessageCallback(messageCallback_); conn->setWriteCompleteCallback(writeCompleteCallback_); conn->setCloseCallback( boost::bind(&TcpClient::removeConnection, this, _1)); // FIXME: unsafe { MutexLockGuard lock(mutex_); connection_ = conn; // 儲存TcpConnection } conn->connectEstablished(); // 這裡回撥connectionCallback_ } |
此外與TcpServer 還有一點不同的是,TcpServer 可以有多個Reactor,即mainReactor+ThreadPool(subReactors),但TcpClient 只能有一個Reactor,即一個事件迴圈EventLoop,由它來處理這個TcpConnection 的事件(可讀事件(包括接收資料,連線關閉),可寫事件(核心傳送緩衝區不為滿),錯誤事件)。當然我們可以開多個TcpClient繫結在同個EventLoop上,這樣一個EventLoop
就管理多個TcpClient, 也就是多個TcpConnection,事件發生的處理流程與TcpServer 類似,可以參考以前筆記。
還需要說明一點是,使用者呼叫TcpServer/TcpClient 的setXXXCallback() 系列公有介面函式設定回撥函式,實際上最終設定的是TcpConnection 的XXXCallback_ 成員,這些回撥函式會在事件發生時被呼叫,比如連線建立,訊息到來等。
測試程式碼:
先開啟回射伺服器端如 ./reactor_test11
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h> #include <muduo/net/InetAddress.h> #include <boost/bind.hpp> #include <stdio.h> using namespace muduo; using namespace muduo::net; class TestServer { public: TestServer(EventLoop *loop, const InetAddress &listenAddr) : loop_(loop), server_(loop, listenAddr, "TestServer") { server_.setConnectionCallback( boost::bind(&TestServer::onConnection, this, _1)); server_.setMessageCallback( boost::bind(&TestServer::onMessage, this, _1, _2, _3)); } void start() { server_.start(); } private: void onConnection(const TcpConnectionPtr &conn) { if (conn->connected()) { printf("onConnection(): new connection [%s] from %s\n", conn->name().c_str(), conn->peerAddress().toIpPort().c_str()); } else { printf("onConnection(): connection [%s] is down\n", conn->name().c_str()); } } void onMessage(const TcpConnectionPtr &conn, Buffer *buf, Timestamp receiveTime) { string msg(buf->retrieveAllAsString()); printf("onMessage(): received %zd bytes from connection [%s] at %s\n", msg.size(), conn->name().c_str(), receiveTime.toFormattedString().c_str()); conn->send(msg); } EventLoop *loop_; TcpServer server_; }; int main() { printf("main(): pid = %d\n", getpid()); InetAddress listenAddr(8888); EventLoop loop; TestServer server(&loop, listenAddr); server.start(); loop.loop(); } |
接著執行./tcpclient_test
分別輸入
aaaaaaaaaaa
XXXXXXXXXXXXXXXX
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
#include <muduo/net/Channel.h>
#include <muduo/net/TcpClient.h> #include <muduo/base/Logging.h> #include <muduo/net/EventLoop.h> #include <muduo/net/InetAddress.h> #include <boost/bind.hpp> #include <stdio.h> using namespace muduo; using namespace muduo::net; class TestClient { public: TestClient(EventLoop *loop, const InetAddress &listenAddr) : loop_(loop), client_(loop, listenAddr, "TestClient"), stdinChannel_(loop, 0) { client_.setConnectionCallback( boost::bind(&TestClient::onConnection, this, _1)); client_.setMessageCallback( boost::bind(&TestClient::onMessage, this, _1, _2, _3)); //client_.enableRetry(); // 標準輸入緩衝區中有資料的時候,回撥TestClient::handleRead stdinChannel_.setReadCallback(boost::bind(&TestClient::handleRead, this)); stdinChannel_.enableReading(); // 關注可讀事件 } void connect() { client_.connect(); } private: void onConnection(const TcpConnectionPtr &conn) { if (conn->connected()) { printf("onConnection(): new connection [%s] from %s\n", conn->name().c_str(), conn->peerAddress().toIpPort().c_str()); } else { printf("onConnection(): connection [%s] is down\n", conn->name().c_str()); } } void onMessage(const TcpConnectionPtr &conn, Buffer *buf, Timestamp time) { string msg(buf->retrieveAllAsString()); printf("onMessage(): recv a message [%s]\n", msg.c_str()); LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toFormattedString(); } // 標準輸入緩衝區中有資料的時候,回撥該函式 void handleRead() { char buf[1024] = {0}; fgets(buf, 1024, stdin); buf[strlen(buf) - 1] = '\0'; // 去除\n client_.connection()->send(buf); } EventLoop *loop_; TcpClient client_; Channel stdinChannel_; // 標準輸入Channel }; int main(int argc, char *argv[]) { LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); EventLoop loop; InetAddress serverAddr("127.0.0.1", 8888); TestClient client(&loop, serverAddr); client.connect(); loop.loop(); } |
伺服器端輸出如下:
simba@ubuntu:~/Documents/build/debug/bin$ ./reactor_test11
20131110 07:57:14.970756Z 3400 TRACE IgnoreSigPipe Ignore SIGPIPE - EventLoop.cc:51
main(): pid = 3400
20131110 07:57:14.986047Z 3400 TRACE updateChannel fd = 4 events = 3 - EPollPoller.cc:104
20131110 07:57:14.986501Z 3400 TRACE EventLoop EventLoop created 0xBFADD094 in thread 3400 - EventLoop.cc:76
20131110 07:57:14.986822Z 3400 TRACE updateChannel fd = 5 events = 3 - EPollPoller.cc:104
20131110 07:57:14.987696Z 3400 TRACE updateChannel fd = 6 events = 3 - EPollPoller.cc:104
20131110 07:57:14.988252Z 3400 TRACE loop EventLoop 0xBFADD094 start looping - EventLoop.cc:108
20131110 07:57:17.022285Z 3400 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:17.022988Z 3400 TRACE printActiveChannels {6: IN } - EventLoop.cc:271
20131110 07:57:17.023190Z 3400 INFO TcpServer::newConnection [TestServer] - new connection [TestServer:0.0.0.0:8888#1] from 127.0.0.1:54917 - TcpServer.cc:93
20131110 07:57:17.023348Z 3400 DEBUG TcpConnection TcpConnection::ctor[TestServer:0.0.0.0:8888#1] at 0x84417E0 fd=8 - TcpConnection.cc:65
20131110 07:57:17.023359Z 3400 TRACE newConnection [1] usecount=1 - TcpServer.cc:111
20131110 07:57:17.023387Z 3400 TRACE newConnection [2] usecount=2 - TcpServer.cc:113
20131110 07:57:17.023417Z 3400 TRACE connectEstablished [3] usecount=6 - TcpConnection.cc:238
20131110 07:57:17.023424Z 3400 TRACE updateChannel fd = 8 events = 3 - EPollPoller.cc:104
onConnection(): new connection [TestServer:0.0.0.0:8888#1] from 127.0.0.1:54917
20131110 07:57:17.023464Z 3400 TRACE connectEstablished [4] usecount=6 - TcpConnection.cc:243
20131110 07:57:17.023469Z 3400 TRACE newConnection [5] usecount=2 - TcpServer.cc:123
20131110 07:57:19.704918Z 3400 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:19.704958Z 3400 TRACE printActiveChannels {8: IN } - EventLoop.cc:271
20131110 07:57:19.704969Z 3400 TRACE handleEvent [6] usecount=2 - Channel.cc:67
onMessage(): received 11 bytes from connection [TestServer:0.0.0.0:8888#1] at 20131110 07:57:19.704916
20131110 07:57:19.705084Z 3400 TRACE handleEvent [12] usecount=2 - Channel.cc:69
20131110 07:57:22.728687Z 3400 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:22.728725Z 3400 TRACE printActiveChannels {8: IN} - EventLoop.cc:271
20131110 07:57:22.728735Z 3400 TRACE handleEvent [6] usecount=2 - Channel.cc:67
onMessage(): received 16 bytes from connection [TestServer:0.0.0.0:8888#1]at 20131110 07:57:22.728685
20131110 07:57:22.728786Z 3400 TRACE handleEvent [12] usecount=2 - Channel.cc:69
20131110 07:57:32.739020Z 3400 TRACE poll nothing happended - EPollPoller.cc:74
^C
20131110 07:57:14.970756Z 3400 TRACE IgnoreSigPipe Ignore SIGPIPE - EventLoop.cc:51
main(): pid = 3400
20131110 07:57:14.986047Z 3400 TRACE updateChannel fd = 4 events = 3 - EPollPoller.cc:104
20131110 07:57:14.986501Z 3400 TRACE EventLoop EventLoop created 0xBFADD094 in thread 3400 - EventLoop.cc:76
20131110 07:57:14.986822Z 3400 TRACE updateChannel fd = 5 events = 3 - EPollPoller.cc:104
20131110 07:57:14.987696Z 3400 TRACE updateChannel fd = 6 events = 3 - EPollPoller.cc:104
20131110 07:57:14.988252Z 3400 TRACE loop EventLoop 0xBFADD094 start looping - EventLoop.cc:108
20131110 07:57:17.022285Z 3400 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:17.022988Z 3400 TRACE printActiveChannels {6: IN } - EventLoop.cc:271
20131110 07:57:17.023190Z 3400 INFO TcpServer::newConnection [TestServer] - new connection [TestServer:0.0.0.0:8888#1] from 127.0.0.1:54917 - TcpServer.cc:93
20131110 07:57:17.023348Z 3400 DEBUG TcpConnection TcpConnection::ctor[TestServer:0.0.0.0:8888#1] at 0x84417E0 fd=8 - TcpConnection.cc:65
20131110 07:57:17.023359Z 3400 TRACE newConnection [1] usecount=1 - TcpServer.cc:111
20131110 07:57:17.023387Z 3400 TRACE newConnection [2] usecount=2 - TcpServer.cc:113
20131110 07:57:17.023417Z 3400 TRACE connectEstablished [3] usecount=6 - TcpConnection.cc:238
20131110 07:57:17.023424Z 3400 TRACE updateChannel fd = 8 events = 3 - EPollPoller.cc:104
onConnection(): new connection [TestServer:0.0.0.0:8888#1] from 127.0.0.1:54917
20131110 07:57:17.023464Z 3400 TRACE connectEstablished [4] usecount=6 - TcpConnection.cc:243
20131110 07:57:17.023469Z 3400 TRACE newConnection [5] usecount=2 - TcpServer.cc:123
20131110 07:57:19.704918Z 3400 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:19.704958Z 3400 TRACE printActiveChannels {8: IN } - EventLoop.cc:271
20131110 07:57:19.704969Z 3400 TRACE handleEvent [6] usecount=2 - Channel.cc:67
onMessage(): received 11 bytes from connection [TestServer:0.0.0.0:8888#1] at 20131110 07:57:19.704916
20131110 07:57:19.705084Z 3400 TRACE handleEvent [12] usecount=2 - Channel.cc:69
20131110 07:57:22.728687Z 3400 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:22.728725Z 3400 TRACE printActiveChannels {8: IN} - EventLoop.cc:271
20131110 07:57:22.728735Z 3400 TRACE handleEvent [6] usecount=2 - Channel.cc:67
onMessage(): received 16 bytes from connection [TestServer:0.0.0.0:8888#1]at 20131110 07:57:22.728685
20131110 07:57:22.728786Z 3400 TRACE handleEvent [12] usecount=2 - Channel.cc:69
20131110 07:57:32.739020Z 3400 TRACE poll nothing happended - EPollPoller.cc:74
^C
輸出中fd = 6是監聽套接字,fd=8是返回的已連線套接字,連線建立呼叫OnConnection(),因為客戶端輸入兩串資料,fd=8產生兩次可讀事件,呼叫兩次onMessage().
客戶端輸出如下:
simba@ubuntu:~/Documents/build/debug/bin$ ./tcpclient_test
20131110 07:57:16.999262Z 3401 TRACE IgnoreSigPipe Ignore SIGPIPE - EventLoop.cc:51
20131110 07:57:17.001679Z 3401 INFO pid = 3401, tid = 3401 - TcpClient_test.cc:77
20131110 07:57:17.002535Z 3401 TRACE updateChannel fd = 4 events = 3 - EPollPoller.cc:104
20131110 07:57:17.003035Z 3401 TRACE EventLoop EventLoop created 0xBFE52018 in thread 3401 - EventLoop.cc:76
20131110 07:57:17.003367Z 3401 TRACE updateChannel fd = 5 events = 3 - EPollPoller.cc:104
20131110 07:57:17.003846Z 3401 DEBUG Connector ctor[0x9A946D0] - Connector.cc:33
20131110 07:57:17.004215Z 3401 INFO TcpClient::TcpClient[TestClient] - connector 0x9A946D0 - TcpClient.cc:72
20131110 07:57:17.004569Z 3401 TRACE updateChannel fd = 0 events = 3 - EPollPoller.cc:104
20131110 07:57:17.005017Z 3401 INFO TcpClient::connect[TestClient] - connecting to 127.0.0.1:8888 - TcpClient.cc:106
20131110 07:57:17.024071Z 3401 TRACE updateChannel fd = 6 events = 4 - EPollPoller.cc:104
20131110 07:57:17.024375Z 3401 TRACE loop EventLoop 0xBFE52018 start looping - EventLoop.cc:108
20131110 07:57:17.024561Z 3401 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:17.024980Z 3401 TRACE printActiveChannels {6: OUT} - EventLoop.cc:271
20131110 07:57:17.025181Z 3401 TRACE handleWrite Connector::handleWrite 1 - Connector.cc:169
20131110 07:57:17.025326Z 3401 TRACE updateChannel fd = 6 events = 0 - EPollPoller.cc:104
20131110 07:57:17.025509Z 3401 TRACE removeChannel fd = 6- EPollPoller.cc:147
20131110 07:57:17.025804Z 3401 DEBUG TcpConnection TcpConnection::ctor[TestClient:127.0.0.1:8888#1] at 0x9A94808 fd=6 - TcpConnection.cc:65
20131110 07:57:17.026012Z 3401 TRACE connectEstablished [3] usecount=3 - TcpConnection.cc:238
20131110 07:57:17.026183Z 3401 TRACE updateChannel fd = 6 events = 3 - EPollPoller.cc:104
onConnection(): new connection [TestClient:127.0.0.1:8888#1] from 127.0.0.1:8888
20131110 07:57:17.026506Z 3401 TRACE connectEstablished [4] usecount=3 - TcpConnection.cc:243
aaaaaaaaaaa
20131110 07:57:19.704702Z 3401 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:19.704765Z 3401 TRACE printActiveChannels {0: IN } - EventLoop.cc:271
20131110 07:57:19.705370Z 3401 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:19.705408Z 3401 TRACE printActiveChannels {6: IN } - EventLoop.cc:271
20131110 07:57:19.705427Z 3401 TRACE handleEvent [6] usecount=2 - Channel.cc:67
onMessage(): recv a message [aaaaaaaaaaa]
20131110 07:57:19.705520Z 3401 TRACE onMessage TestClient:127.0.0.1:8888#1 recv 11 bytes at 20131110 07:57:19.705368 - TcpClient_test.cc:58
20131110 07:57:19.705538Z 3401 TRACE handleEvent [12] usecount=2 - Channel.cc:69
XXXXXXXXXXXXXXXX
20131110 07:57:22.728548Z 3401 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:22.728616Z 3401 TRACE printActiveChannels {0: IN} - EventLoop.cc:271
20131110 07:57:22.729010Z 3401 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:22.729035Z 3401 TRACE printActiveChannels {6: IN } - EventLoop.cc:271
20131110 07:57:22.729045Z 3401 TRACE handleEvent [6] usecount=2 - Channel.cc:67
onMessage(): recv a message [XXXXXXXXXXXXXXXX]
20131110 07:57:22.729070Z 3401 TRACE onMessage TestClient:127.0.0.1:8888#1 recv 16 bytes at 20131110 07:57:22.729009 - TcpClient_test.cc:58
20131110 07:57:22.729093Z 3401 TRACE handleEvent [12] usecount=2 - Channel.cc:69
20131110 07:57:32.739100Z 3401 TRACE poll nothing happended - EPollPoller.cc:74
20131110 07:57:36.887794Z 3401 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:36.887848Z 3401 TRACE printActiveChannels {6: IN } - EventLoop.cc:271
20131110 07:57:36.887860Z 3401 TRACE handleEvent [6] usecount=2 - Channel.cc:67
20131110 07:57:36.887882Z 3401 TRACE handleClose fd = 6 state = 2 - TcpConnection.cc:369
20131110 07:57:36.887892Z 3401 TRACE updateChannel fd = 6 events = 0 - EPollPoller.cc:104
onConnection(): connection [TestClient:127.0.0.1:8888#1] is down
20131110 07:57:36.887948Z 3401 TRACE handleClose [7] usecount=3 - TcpConnection.cc:377
20131110 07:57:36.887966Z 3401 TRACE handleClose [11] usecount=3 - TcpConnection.cc:380
20131110 07:57:36.887984Z 3401 TRACE handleEvent [12] usecount=2 - Channel.cc:69
20131110 07:57:36.887994Z 3401 TRACE removeChannel fd = 6- EPollPoller.cc:147
20131110 07:57:36.888005Z 3401 DEBUG ~TcpConnection TcpConnection::dtor[TestClient:127.0.0.1:8888#1] at 0x9A94808 fd=6 - TcpConnection.cc:72
20131110 07:57:46.894605Z 3401 TRACE poll nothing happended - EPollPoller.cc:74
20131110 07:57:16.999262Z 3401 TRACE IgnoreSigPipe Ignore SIGPIPE - EventLoop.cc:51
20131110 07:57:17.001679Z 3401 INFO pid = 3401, tid = 3401 - TcpClient_test.cc:77
20131110 07:57:17.002535Z 3401 TRACE updateChannel fd = 4 events = 3 - EPollPoller.cc:104
20131110 07:57:17.003035Z 3401 TRACE EventLoop EventLoop created 0xBFE52018 in thread 3401 - EventLoop.cc:76
20131110 07:57:17.003367Z 3401 TRACE updateChannel fd = 5 events = 3 - EPollPoller.cc:104
20131110 07:57:17.003846Z 3401 DEBUG Connector ctor[0x9A946D0] - Connector.cc:33
20131110 07:57:17.004215Z 3401 INFO TcpClient::TcpClient[TestClient] - connector 0x9A946D0 - TcpClient.cc:72
20131110 07:57:17.004569Z 3401 TRACE updateChannel fd = 0 events = 3 - EPollPoller.cc:104
20131110 07:57:17.005017Z 3401 INFO TcpClient::connect[TestClient] - connecting to 127.0.0.1:8888 - TcpClient.cc:106
20131110 07:57:17.024071Z 3401 TRACE updateChannel fd = 6 events = 4 - EPollPoller.cc:104
20131110 07:57:17.024375Z 3401 TRACE loop EventLoop 0xBFE52018 start looping - EventLoop.cc:108
20131110 07:57:17.024561Z 3401 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:17.024980Z 3401 TRACE printActiveChannels {6: OUT} - EventLoop.cc:271
20131110 07:57:17.025181Z 3401 TRACE handleWrite Connector::handleWrite 1 - Connector.cc:169
20131110 07:57:17.025326Z 3401 TRACE updateChannel fd = 6 events = 0 - EPollPoller.cc:104
20131110 07:57:17.025509Z 3401 TRACE removeChannel fd = 6- EPollPoller.cc:147
20131110 07:57:17.025804Z 3401 DEBUG TcpConnection TcpConnection::ctor[TestClient:127.0.0.1:8888#1] at 0x9A94808 fd=6 - TcpConnection.cc:65
20131110 07:57:17.026012Z 3401 TRACE connectEstablished [3] usecount=3 - TcpConnection.cc:238
20131110 07:57:17.026183Z 3401 TRACE updateChannel fd = 6 events = 3 - EPollPoller.cc:104
onConnection(): new connection [TestClient:127.0.0.1:8888#1] from 127.0.0.1:8888
20131110 07:57:17.026506Z 3401 TRACE connectEstablished [4] usecount=3 - TcpConnection.cc:243
aaaaaaaaaaa
20131110 07:57:19.704702Z 3401 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:19.704765Z 3401 TRACE printActiveChannels {0: IN } - EventLoop.cc:271
20131110 07:57:19.705370Z 3401 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:19.705408Z 3401 TRACE printActiveChannels {6: IN } - EventLoop.cc:271
20131110 07:57:19.705427Z 3401 TRACE handleEvent [6] usecount=2 - Channel.cc:67
onMessage(): recv a message [aaaaaaaaaaa]
20131110 07:57:19.705520Z 3401 TRACE onMessage TestClient:127.0.0.1:8888#1 recv 11 bytes at 20131110 07:57:19.705368 - TcpClient_test.cc:58
20131110 07:57:19.705538Z 3401 TRACE handleEvent [12] usecount=2 - Channel.cc:69
XXXXXXXXXXXXXXXX
20131110 07:57:22.728548Z 3401 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:22.728616Z 3401 TRACE printActiveChannels {0: IN} - EventLoop.cc:271
20131110 07:57:22.729010Z 3401 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:22.729035Z 3401 TRACE printActiveChannels {6: IN } - EventLoop.cc:271
20131110 07:57:22.729045Z 3401 TRACE handleEvent [6] usecount=2 - Channel.cc:67
onMessage(): recv a message [XXXXXXXXXXXXXXXX]
20131110 07:57:22.729070Z 3401 TRACE onMessage TestClient:127.0.0.1:8888#1 recv 16 bytes at 20131110 07:57:22.729009 - TcpClient_test.cc:58
20131110 07:57:22.729093Z 3401 TRACE handleEvent [12] usecount=2 - Channel.cc:69
20131110 07:57:32.739100Z 3401 TRACE poll nothing happended - EPollPoller.cc:74
20131110 07:57:36.887794Z 3401 TRACE poll 1 events happended - EPollPoller.cc:65
20131110 07:57:36.887848Z 3401 TRACE printActiveChannels {6: IN } - EventLoop.cc:271
20131110 07:57:36.887860Z 3401 TRACE handleEvent [6] usecount=2 - Channel.cc:67
20131110 07:57:36.887882Z 3401 TRACE handleClose fd = 6 state = 2 - TcpConnection.cc:369
20131110 07:57:36.887892Z 3401 TRACE updateChannel fd = 6 events = 0 - EPollPoller.cc:104
onConnection(): connection [TestClient:127.0.0.1:8888#1] is down
20131110 07:57:36.887948Z 3401 TRACE handleClose [7] usecount=3 - TcpConnection.cc:377
20131110 07:57:36.887966Z 3401 TRACE handleClose [11] usecount=3 - TcpConnection.cc:380
20131110 07:57:36.887984Z 3401 TRACE handleEvent [12] usecount=2 - Channel.cc:69
20131110 07:57:36.887994Z 3401 TRACE removeChannel fd = 6- EPollPoller.cc:147
20131110 07:57:36.888005Z 3401 DEBUG ~TcpConnection TcpConnection::dtor[TestClient:127.0.0.1:8888#1] at 0x9A94808 fd=6 - TcpConnection.cc:72
20131110 07:57:46.894605Z 3401 TRACE poll nothing happended - EPollPoller.cc:74
fd=0是標準輸入,fd=6是客戶端連線的套接字,剛開始連線成功,fd=6可寫事件發生,但馬上把connector的channel移除關注並析構,並構造TcpConnection。在命令列輸入一串資料,標準輸入可讀事件發生,等伺服器回射回來,fd=6可讀事件發生,呼叫OnMessage(),重複兩次。我們首先ctrl+c 掉伺服器,客戶端發現此連線已經down掉,就會析構TcpConnection,順便關閉套接字,當然事件迴圈還在繼續,因為如前面所說,有可能EventLoop繫結了多個TcpClient。
可以稍微舉個例子,比如可以讓EventLoopThreadPool開兩個IO執行緒,每個IO執行緒管理4個TcpClient,如下程式中RecvFileClient 是一個封裝了TcpClient類的類。
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
int main(int argc, char* argv[])
{ LOG_INFO << "pid = " << getpid(); EventLoop loop; g_loop = &loop; // 用兩個IO執行緒來發起多個連線 EventLoopThreadPool loopPool(&loop); loopPool.setThreadNum(2); loopPool.start(); boost::ptr_vector<RecvFileClient> clients(8); InetAddress serverAddr("127.0.0.1", 2021); for (int i = 0; i < 8; ++i) { char buf[32]; snprintf(buf, sizeof buf, "%d", i+1); clients.push_back(new RecvFileClient(loopPool.getNextLoop(), serverAddr, buf)); clients[i].connect(); usleep(200); } loop.loop(); usleep(20000); } |
參考:
《UNP》
muduo manual.pdf
《linux 多執行緒伺服器程式設計:使用muduo c++網路庫》
相關文章
- muduo網路庫學習之EventLoop(四):EventLoopThread 類、EventLoopThreadPool 類OOPthread
- muduo網路庫學習之EventLoop(二):程式(執行緒)wait/notify 和 EventLoop::runInLoopOOP執行緒AI
- muduo網路庫學習之EventLoop(六):TcpConnection::send()、shutdown()、handleRead()、handleWrite()OOPTCP
- muduo網路庫學習之EventLoop(一):事件迴圈類圖簡介和muduo 定時器TimeQueueOOP事件定時器
- muduo網路庫學習之EventLoop(五):TcpConnection生存期管理(連線關閉)OOPTCP
- muduo網路庫學習之muduo_http 庫涉及到的類HTTP
- muduo網路庫學習之EventLoop(三):Socket、Acceptor、TcpServer、TcpConnection(連線建立,接收訊息)OOPTCPServer
- muduo網路庫學習之muduo_inspect 庫涉及到的類
- muduo網路庫學習筆記(1):Timestamp類筆記
- muduo網路庫學習筆記(2):原子性操作筆記
- muduo網路庫學習筆記(3):Thread類筆記thread
- muduo網路庫學習筆記(14):chargen服務示例筆記
- muduo網路庫學習筆記(11):有用的runInLoop()函式筆記OOP函式
- muduo網路庫學習之ThreadLocal 類、ThreadLocalSingleton類封裝知識點thread封裝
- muduo網路庫學習筆記(12):TcpServer和TcpConnection類筆記TCPServer
- muduo網路庫學習筆記(13):TcpConnection生命期的管理筆記TCP
- muduo網路庫學習筆記(10):定時器的實現筆記定時器
- muduo網路庫學習筆記(7):執行緒特定資料筆記執行緒
- muduo網路庫Timestamp類
- muduo網路庫使用心得
- muduo網路庫學習之Timestamp類、AtomicIntegerT 類封裝中的知識點封裝
- muduo網路庫學習筆記(9):Reactor模式的關鍵結構筆記React模式
- muduo網路庫學習筆記(8):高效日誌類的封裝筆記封裝
- muduo網路庫學習筆記(4):互斥量和條件變數筆記變數
- muduo網路庫學習筆記(5):執行緒池的實現筆記執行緒
- muduo網路庫Exception異常類Exception
- muduo網路庫編譯安裝編譯
- muduo網路庫學習筆記(6):單例類(執行緒安全的)筆記單例執行緒
- muduo網路庫學習之BlockinngQueue類、ThreadPool 類、Singleton類封裝中的知識點BloCthread封裝
- muduo網路庫學習之MutexLock類、MutexLockGuard類、Condition類、CountDownLatch類封裝中的知識點MutexCountDownLatch封裝
- muduo網路庫學習之Logger類、LogStream類、LogFile類封裝中的知識點封裝
- muduo網路庫AtomicIntegerT原子整數類
- muduo網路庫學習筆記(15):關於使用stdio和iostream的討論筆記iOS
- Mudo C++網路庫第七章學習筆記C++筆記
- muduo網路庫學習之Exception類、Thread 類封裝中的知識點(重點講pthread_atfork())Exceptionthread封裝
- 深度學習(五)之原型網路深度學習原型
- 深度學習之Transformer網路深度學習ORM
- 深度學習之殘差網路深度學習