木铎库源码剖析—网络分层
InetAddress
这个类主要封装了套接字地址的相关成员变量及方法
class InetAddress : public muduo::copyable
{
public:
/// Constructs an endpoint with given port number.
/// Mostly used in TcpServer listening.
explicit InetAddress(uint16_t port = 0, bool loopbackOnly = false, bool ipv6 = false);
/// Constructs an endpoint with given ip and port.
/// @c ip should be "1.2.3.4"
InetAddress(StringArg ip, uint16_t port, bool ipv6 = false);
/// Constructs an endpoint with given struct @c sockaddr_in
/// Mostly used when accepting new connections
explicit InetAddress(const struct sockaddr_in& addr)
: addr_(addr)
{ }
explicit InetAddress(const struct sockaddr_in6& addr)
: addr6_(addr)
{ }
sa_family_t family() const { return addr_.sin_family; }
string toIp() const;
string toIpPort() const;
uint16_t port() const;
// default copy/assignment are Okay
const struct sockaddr* getSockAddr() const { return sockets::sockaddr_cast(&addr6_); }
void setSockAddrInet6(const struct sockaddr_in6& addr6) { addr6_ = addr6; }
uint32_t ipv4NetEndian() const;
uint16_t portNetEndian() const { return addr_.sin_port; }
// resolve hostname to IP address, not changing port or sin_family
// return true on success.
// thread safe
static bool resolve(StringArg hostname, InetAddress* result);
// static std::vector<InetAddress> resolveAll(const char* hostname, uint16_t port = 0);
// set IPv6 ScopeID
void setScopeId(uint32_t scope_id);
private:
union
{
struct sockaddr_in addr_;
struct sockaddr_in6 addr6_;
};
};
该类封装了IPV4和IPV6两中地址信息,值得注意的是,该类中实现了通过主机名解析主机地址的函数,值得一学
bool InetAddress::resolve(StringArg hostname, InetAddress* out)
{
assert(out != NULL);
struct hostent hent;
struct hostent* he = NULL;
int herrno = 0;
memZero(&hent, sizeof(hent));
//该函数可以通过主机名获取主机地址
int ret = gethostbyname_r(hostname.c_str(), &hent, t_resolveBuffer, sizeof t_resolveBuffer, &he, &herrno);
if (ret == 0 && he != NULL)
{
assert(he->h_addrtype == AF_INET && he->h_length == sizeof(uint32_t));
out->addr_.sin_addr = *reinterpret_cast<struct in_addr*>(he->h_addr);
return true;
}
else
{
if (ret)
{
LOG_SYSERR << "InetAddress::resolve";
}
return false;
}
}
socket
封装了socket套接字的主要常用方法以及各类复用方法的封装
成员变量
const int sockfd_;
成员方法
封装了有关套接字描述符的相关方法;以及bind、listen、accept等方法;还有一些就是关于对象复用的相关方法
class Socket : noncopyable
{
public:
explicit Socket(int sockfd)
: sockfd_(sockfd)
{ }
// Socket(Socket&&) // move constructor in C++11
~Socket();
int fd() const { return sockfd_; }
// return true if success.
bool getTcpInfo(struct tcp_info*) const;
bool getTcpInfoString(char* buf, int len) const;
/// abort if address in use
void bindAddress(const InetAddress& localaddr);
/// abort if address in use
void listen();
/// On success, returns a non-negative integer that is
/// a descriptor for the accepted socket, which has been
/// set to non-blocking and close-on-exec. *peeraddr is assigned.
/// On error, -1 is returned, and *peeraddr is untouched.
int accept(InetAddress* peeraddr);
void shutdownWrite();
///
/// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm).
///
void setTcpNoDelay(bool on);
///
/// Enable/disable SO_REUSEADDR
///
void setReuseAddr(bool on);
///
/// Enable/disable SO_REUSEPORT
///
void setReusePort(bool on);
///
/// Enable/disable SO_KEEPALIVE
///
void setKeepAlive(bool on);
private:
const int sockfd_;
};
Connector
这个类表示一个用于在非阻塞模式下连接服务器的对象,主要功能包括:
- 发起连接: 提供了开始连接、重新连接和停止连接的方法。
- 状态管理: 维护了连接的状态,包括已断开、连接中、已连接。
- 事件处理: 处理连接过程中的各种事件,如写入事件、错误事件等。
- 回调函数: 允许用户设置在连接建立时的回调函数,以处理新连接。
- 重连机制: 提供了简单的重连机制,包括重试延迟的设置。
成员变量
EventLoop* loop_;//指向事件循环对象的指针
InetAddress serverAddr_;//服务器的地址信息
bool connect_; // atomic 是否处于连接状态
States state_; // FIXME: use atomic variable 连接的状态
std::unique_ptr<Channel> channel_; //用于注册和处理事件
NewConnectionCallback newConnectionCallback_;//用户设置的新连接建立时的回调函数
int retryDelayMs_;//重试延迟的时间间隔
成员函数
构造函数,初始化循环事件指针及服务器地址
Connector::Connector(EventLoop* loop, const InetAddress& serverAddr)
: loop_(loop),
serverAddr_(serverAddr),
connect_(false),
state_(kDisconnected),
retryDelayMs_(kInitRetryDelayMs)
{
LOG_DEBUG << "ctor[" << this << "]";
}
开始连接,主要过程放在了事件循环中执行
void Connector::start()
{
connect_ = true;
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::connect()
{
int sockfd = sockets::createNonblockingOrDie(serverAddr_.family());
int ret = sockets::connect(sockfd, serverAddr_.getSockAddr());
int savedErrno = (ret == 0) ? 0 : errno;
switch (savedErrno)
{
case 0:
case EINPROGRESS:
case EINTR:
case EISCONN:
connecting(sockfd);
break;
case 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);
break;
default:
LOG_SYSERR << "Unexpected error in Connector::startInLoop " << savedErrno;
sockets::close(sockfd);
// connectErrorCallback_();
break;
}
}
停止连接,也是在循环体中调用执行
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);
}
}
int Connector::removeAndResetChannel()
{
channel_->disableAll();
channel_->remove();
int sockfd = channel_->fd();
// Can't reset channel_ here, because we are inside Channel::handleEvent
loop_->queueInLoop(std::bind(&Connector::resetChannel, this)); // FIXME: unsafe
return sockfd;
}
void Connector::resetChannel()
{
channel_.reset();
}
//shared_from_this() 用于在对象的生命周期中获取指向自身的std::shared_ptr对象的方法
//这是为了确保在对象还存在的情况下使用共享指针,以防止在对象销毁后仍然引用该对象而导致未定义行为。
void Connector::retry(int sockfd)
{
sockets::close(sockfd);
setState(kDisconnected);
if (connect_)
{
LOG_INFO << "Connector::retry - Retry connecting to " << serverAddr_.toIpPort()
<< " in " << retryDelayMs_ << " milliseconds. ";
loop_->runAfter(retryDelayMs_/1000.0,
std::bind(&Connector::startInLoop, shared_from_this()));
retryDelayMs_ = std::min(retryDelayMs_ * 2, kMaxRetryDelayMs);
}
else
{
LOG_DEBUG << "do not connect";
}
}
connecting用于处理连接中的处理,包括设置连接状态,注册写入事件等
void Connector::connecting(int sockfd)
{
setState(kConnecting);
assert(!channel_);
channel_.reset(new Channel(loop_, sockfd));
channel_->setWriteCallback(
std::bind(&Connector::handleWrite, this)); // FIXME: unsafe
channel_->setErrorCallback(
std::bind(&Connector::handleError, this)); // FIXME: unsafe
// channel_->tie(shared_from_this()); is not working,
// as channel_ is not managed by shared_ptr
channel_->enableWriting();
}
void Connector::handleWrite()
{
LOG_TRACE << "Connector::handleWrite " << state_;
if (state_ == kConnecting)
{
int sockfd = removeAndResetChannel();
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
{
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);
}
}
Acceptor:接受新用户连接并分发给SubReactor(SubEventLoop)
Acceptor封装了服务器监听套接字fd及相关处理办法,Acceptor类内部其实没有贡献什么核心的处理函数,主要是对其他类的方法调用进行封装,
class Acceptor : noncopyable
{
public:
typedef std::function<void (int sockfd, const InetAddress&)> NewConnectionCallback;
Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport);
~Acceptor();
void setNewConnectionCallback(const NewConnectionCallback& cb)
{ newConnectionCallback_ = cb; }
void listen();
bool listening() const { return listening_; }
// Deprecated, use the correct spelling one above.
// Leave the wrong spelling here in case one needs to grep it for error messages.
// bool listenning() const { return listening(); }
private:
void handleRead();
EventLoop* loop_;
//监听套接字的fd由哪个EventLoop负责循环监听以及处理相应事件,其实这个EventLoop就是main EventLoop
Socket acceptSocket_;//服务器监听套接字的文件描述符
Channel acceptChannel_;//把acceptSocket_及其感兴趣事件和事件对应的处理函数都封装进去
NewConnectionCallback newConnectionCallback_;//TcpServer构造函数中将Tcpserver::newConnection()函数注册给了这个成员变量,这个函数的功能就是公平的选择一个SubEventLoop并把已经接受的连接分发给这个subEventLoop
bool listening_;
int idleFd_;
};
构造函数
可以看出都做了些初始化服务器监听套接字文件描述符;注册channel,设置地址及端口的复用,设置发送可读事件的回调函数,并进行bind绑定。可以看出并没有进行可读事件的激活以及listen事件
Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport)
: loop_(loop),
acceptSocket_(sockets::createNonblockingOrDie(listenAddr.family())),
acceptChannel_(loop, acceptSocket_.fd()),
listening_(false),
idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC))
{
assert(idleFd_ >= 0);
acceptSocket_.setReuseAddr(true);
acceptSocket_.setReusePort(reuseport);
acceptSocket_.bindAddress(listenAddr);
acceptChannel_.setReadCallback(
std::bind(&Acceptor::handleRead, this));
}
监听函数
开始监听套接字并使得channel具有可读事件
void Acceptor::listen()
{
loop_->assertInLoopThread();
listening_ = true;
acceptSocket_.listen();
acceptChannel_.enableReading();
}
发生了可读事件意味着开始进行accept
void Acceptor::handleRead()
{
loop_->assertInLoopThread();
InetAddress peerAddr;
//FIXME loop until no more
//此处的accept是非阻塞的
int connfd = acceptSocket_.accept(&peerAddr);
if (connfd >= 0)
{
// string hostport = peerAddr.toIpPort();
// LOG_TRACE << "Accepts of " << hostport;
//此处说明新的连接已经成功了需要执行回调函数 对该事件进行分发
if (newConnectionCallback_)
{
newConnectionCallback_(connfd, peerAddr);
}
else
{
sockets::close(connfd);
}
}
else
{
LOG_SYSERR << "in Acceptor::handleRead";
// Read the section named "The special problem of
// accept()ing when you can't" in libev's doc.
// By Marc Lehmann, author of libev.
if (errno == EMFILE)
{
::close(idleFd_);
idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL);
::close(idleFd_);
idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);
}
}
}

浙公网安备 33010602011771号