muduo之Connector
生活随笔
收集整理的這篇文章主要介紹了
muduo之Connector
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ? ? ? ??Connector負責主動發起連接,不負責創建socket,只負責連接的建立,外部調用Connector::start就可以發起連接,Connector具有重連的功能和停止連接的功能,連接成功建立后返回到TcpClient。
Connector.h
// Copyright 2010, Shuo Chen. All rights reserved. // http://code.google.com/p/muduo/ // // Use of this source code is governed by a BSD-style license // that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com) // // This is an internal header file, you should not include this.#ifndef MUDUO_NET_CONNECTOR_H #define MUDUO_NET_CONNECTOR_H#include "muduo/base/noncopyable.h" #include "muduo/net/InetAddress.h"#include <functional> #include <memory>namespace muduo { namespace net {class Channel; class EventLoop;//負責主動發起連接,不負責創建socket,只負責連接的建立 class Connector : noncopyable,public std::enable_shared_from_this<Connector> {public:typedef std::function<void (int sockfd)> NewConnectionCallback;Connector(EventLoop* loop, const InetAddress& serverAddr);~Connector();void setNewConnectionCallback(const NewConnectionCallback& cb){ newConnectionCallback_ = cb; }void start(); // can be called in any threadvoid restart(); // must be called in loop threadvoid stop(); // can be called in any threadconst InetAddress& serverAddress() const { return serverAddr_; }private:enum States { kDisconnected, kConnecting, kConnected };static const int kMaxRetryDelayMs = 30*1000;static const int kInitRetryDelayMs = 500;void setState(States s) { state_ = s; }void startInLoop();void stopInLoop();void connect();void connecting(int sockfd);void handleWrite();void handleError();void retry(int sockfd);int removeAndResetChannel();void resetChannel();EventLoop* loop_; //所屬的EventLoopInetAddress serverAddr_; //要連接的server地址bool connect_; // atomicStates state_; // FIXME: use atomic variablestd::unique_ptr<Channel> channel_; //對應的channelNewConnectionCallback newConnectionCallback_; //連接成功時的回調函數int retryDelayMs_; //重連間隔時間 };} // namespace net } // namespace muduo#endif // MUDUO_NET_CONNECTOR_HConnector.cc
// Copyright 2010, Shuo Chen. All rights reserved. // http://code.google.com/p/muduo/ // // Use of this source code is governed by a BSD-style license // that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com) //#include "muduo/net/Connector.h"#include "muduo/base/Logging.h" #include "muduo/net/Channel.h" #include "muduo/net/EventLoop.h" #include "muduo/net/SocketsOps.h"#include <errno.h>using namespace muduo; using namespace muduo::net;const int Connector::kMaxRetryDelayMs;Connector::Connector(EventLoop* loop, const InetAddress& serverAddr): loop_(loop),serverAddr_(serverAddr),connect_(false),state_(kDisconnected),retryDelayMs_(kInitRetryDelayMs) {LOG_DEBUG << "ctor[" << this << "]"; }Connector::~Connector() {LOG_DEBUG << "dtor[" << this << "]";assert(!channel_); }void Connector::start() {connect_ = true;//在所屬IO線程Lloop中調用該函數loop_->runInLoop(std::bind(&Connector::startInLoop, this)); // FIXME: unsafe }void Connector::startInLoop() {loop_->assertInLoopThread();assert(state_ == kDisconnected);if (connect_){connect(); //請求連接}else{LOG_DEBUG << "do not connect";} }void Connector::stop() {connect_ = false;loop_->queueInLoop(std::bind(&Connector::stopInLoop, this)); // FIXME: unsafe// FIXME: cancel timer }void Connector::stopInLoop() {loop_->assertInLoopThread();if (state_ == kConnecting){setState(kDisconnected);int sockfd = removeAndResetChannel();retry(sockfd);} }void Connector::connect() {int sockfd = sockets::createNonblockingOrDie(serverAddr_.family());//創建非阻塞socketint ret = sockets::connect(sockfd, serverAddr_.getSockAddr());// 請求連接int savedErrno = (ret == 0) ? 0 : errno;switch (savedErrno){case 0:case EINPROGRESS: //socket是非阻塞,返回這個錯誤碼表示正在連接case EINTR:case EISCONN: //連接成功connecting(sockfd);break;case EAGAIN: //connect返回EAGAIN是真的錯誤了case EADDRINUSE:case EADDRNOTAVAIL:case ECONNREFUSED:case ENETUNREACH:retry(sockfd); //重連break;case EACCES:case EPERM:case EAFNOSUPPORT:case EALREADY:case EBADF:case EFAULT:case ENOTSOCK:LOG_SYSERR << "connect error in Connector::startInLoop " << savedErrno;sockets::close(sockfd); //關閉socketbreak;default:LOG_SYSERR << "Unexpected error in Connector::startInLoop " << savedErrno;sockets::close(sockfd);// connectErrorCallback_();break;} }void Connector::restart() {loop_->assertInLoopThread();setState(kDisconnected);retryDelayMs_ = kInitRetryDelayMs;connect_ = true;startInLoop(); }void Connector::connecting(int sockfd) {setState(kConnecting); //設置狀態為正在進行連接assert(!channel_);//channel對應于一個文件描述符,所以在有了socket后才能創建channelchannel_.reset(new Channel(loop_, sockfd));//設置回調函數channel_->setWriteCallback(std::bind(&Connector::handleWrite, this)); // FIXME: unsafechannel_->setErrorCallback(std::bind(&Connector::handleError, this)); // FIXME: unsafe// channel_->tie(shared_from_this()); is not working,// as channel_ is not managed by shared_ptrchannel_->enableWriting(); //注冊可寫事件 }int Connector::removeAndResetChannel() {channel_->disableAll();channel_->remove();int sockfd = channel_->fd();// Can't reset channel_ here, because we are inside Channel::handleEventloop_->queueInLoop(std::bind(&Connector::resetChannel, this)); // FIXME: unsafereturn sockfd; }void Connector::resetChannel() {channel_.reset(); }void Connector::handleWrite() //可寫事件的回調函數 {LOG_TRACE << "Connector::handleWrite " << state_;if (state_ == kConnecting){//移除channel(Connector的channel只管理建立連接的階段),成功建立連接后//交給TcpClient的TcpConnection來管理int sockfd = removeAndResetChannel();//可寫并不一定連接建立成功//如果連接發生錯誤,socket會是可讀可寫的//所以還需要調用getsockopt檢查是否出錯int err = sockets::getSocketError(sockfd);if (err){LOG_WARN << "Connector::handleWrite - SO_ERROR = "<< err << " " << strerror_tl(err);retry(sockfd); //出錯重連}else if (sockets::isSelfConnect(sockfd)) //是否是自連接{LOG_WARN << "Connector::handleWrite - Self connect";retry(sockfd); }else{//連接成功建立,更改狀態//調用TcpClient設置的回調函數,創建TcpConnection對象 setState(kConnected);if (connect_){newConnectionCallback_(sockfd);}else{sockets::close(sockfd);}}}else{// what happened?assert(state_ == kDisconnected);} }void Connector::handleError() {LOG_ERROR << "Connector::handleError state=" << state_;if (state_ == kConnecting){int sockfd = removeAndResetChannel();int err = sockets::getSocketError(sockfd);LOG_TRACE << "SO_ERROR = " << err << " " << strerror_tl(err);retry(sockfd);} }void Connector::retry(int sockfd) {//socket是一次性的,失敗后需要關閉重新創建sockets::close(sockfd);setState(kDisconnected);if (connect_){LOG_INFO << "Connector::retry - Retry connecting to " << serverAddr_.toIpPort()<< " in " << retryDelayMs_ << " milliseconds. ";//隔一段時間后重連,重新執行startInLooploop_->runAfter(retryDelayMs_/1000.0,std::bind(&Connector::startInLoop, shared_from_this()));//間隔時間翻倍retryDelayMs_ = std::min(retryDelayMs_ * 2, kMaxRetryDelayMs);}else{LOG_DEBUG << "do not connect";} }?
總結
以上是生活随笔為你收集整理的muduo之Connector的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: muduo之TcpClient
- 下一篇: muduo之Socket和Sockets