Muduo库源码剖析(2) 其余主要类

本文最后更新于:9 个月前

Muduo库源码剖析(2) 其余主要类

写在前面

上一篇分析了Muduo库依托的Reactor模式的三大核心类,今天继续剖析其余的主要类的源码!

正文

1 Acceptor类

1.1 Acceptor类简介

Accetpor封装了服务器监听套接字fd以及相关处理方法。Acceptor类内部其实没有贡献什么核心的处理函数,主要是对其他类的方法调用进行封装。

1.2 Acceptor类私有变量和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private:
// 接受新连接,并且以负载均衡的选择方式选择一个subEventLoop,并把这个新连接分发到这个subEventLoop上。
// 这个方法是要注册到acceptChannel_上的, 同时handleRead()方法内部还调用了成员变量newConnectionCallback_保存的函数。 // 当main EventLoop监听到acceptChannel_上发生了可读事件时(新用户连接事件),就是调用这个handleRead( )方法。
void handleRead();

// 监听套接字的fd由哪个EventLoop负责循环监听以及处理相应事件,其实这个EventLoop就是main EventLoop。
EventLoop* loop_;

// 服务器监听套接字的文件描述符
Socket acceptSocket_;

// 这是个Channel类,把acceptSocket_及其感兴趣事件和事件对应的处理函数都封装进去。
Channel acceptChannel_;

// TcpServer构造函数中将`TcpServer::newConnection( )`函数注册给了这个成员变量。
// 其功能是公平的选择一个subEventLoop,并把已经接受的连接分发给这个subEventLoop。
NewConnectionCallback newConnectionCallback_;

bool listenning_;
int idleFd_;

1.3 Acceptor类公有方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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; }

bool listenning() const { return listenning_; }

// 该函数底层调用了linux的函数listen(),
// 开启对acceptSocket_的监听同时将acceptChannel及其感兴趣事件(可读事件)注册到main EventLoop的事件监听器上。
// 换言之就是让main EventLoop事件监听器去监听acceptSocket_。
void listen();

2 Socket类

2.1 Socket类简介

封装Sockets描述符,负责关闭连接。

2.2 Socket类变量和方法

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
public:
explicit Socket(int sockfd)
: sockfd_(sockfd)
{ }

// Socket(Socket&&) // move constructor in C++11
~Socket();

int fd() const { return sockfd_; }
bool getTcpInfo(struct tcp_info*) const;
bool getTcpInfoString(char* buf, int len) const;

// 调用bind绑定服务器IP端口
void bindAddress(const InetAddress& localaddr);
// 调用listen监听套接字
void listen();
// 调用accept接受新客户连接请求
int accept(InetAddress* peeraddr);
// 调用shutdown关闭服务端写通道
void shutdownWrite();

// 下面四个函数都是调用setsockopt设置socket选项
void setTcpNoDelay(bool on);
void setReuseAddr(bool on);
void setReusePort(bool on);
void setKeepAlive(bool on);

private:
// 服务器监听套接字文件描述符
const int sockfd_;

3 Buffer类

3.1 Buffer类简介

Buffer类其实是封装了一个用户缓冲区,以及向这个缓冲区写数据读数据等一系列控制方法。

3.2 Buffer类成员方法

由于Buffer类代码较长,这里将比较核心的几个方法解释一下。

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
// 将data数据添加到缓冲区中。
void append(const char* /*restrict*/ data, size_t len)
{
ensureWritableBytes(len);
std::copy(data, data+len, beginWrite());
hasWritten(len);
}

// 获取缓冲区中长度为len的数据,并以strnig返回。
string retrieveAsString(size_t len)
{
assert(len <= readableBytes());
string result(peek(), len);
retrieve(len);
return result;
}

// 获取缓冲区所有数据,并以string返回。
string retrieveAllAsString()
{
return retrieveAsString(readableBytes());
}

// 当你打算向缓冲区写入长度为len的数据之前,先调用这个函数,
// 这个函数会检查你的缓冲区可写空间能不能装下长度为len的数据,如果不能,就动态扩容。
void ensureWritableBytes(size_t len)
{
if (writableBytes() < len)
{
makeSpace(len);
}
assert(writableBytes() >= len);
}

4 TcpConnection类

4.1 TcpConnection类简介

这个类主要封装了一个已建立的TCP连接,以及控制该TCP连接的方法(连接建立和关闭和销毁),以及该连接发生的各种事件(读/写/错误/连接)对应的处理函数,以及这个TCP连接的服务端和客户端的套接字地址信息等。

我个人觉得TcpConnection类和Acceptor类是兄弟关系,Acceptor用于main EventLoop中,对服务器监听套接字fd及其相关方法进行封装(监听、接受连接、分发连接给SubEventLoop等),TcpConnection用于SubEventLoop中,对连接套接字fd及其相关方法进行封装(读消息事件、发送消息事件、连接关闭事件、错误事件等)

4.2 TcpConnection类核心成员变量

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
// 该Tcp连接的Channel注册到了哪一个sub EventLoop上。
// 这个loop_就是那一个sub EventLoop。
EventLoop* loop_;

const string name_;

// 标识了当前TCP连接的状态
// Connected/Connecting/Disconnecting/Disconnected
StateE state_;
bool reading_;

// 用于保存已连接套接字文件描述符。
std::unique_ptr<Socket> socket_;

// 封装了上面的socket_及其各类事件的处理函数(读、写、错误、关闭等事件处理函数)。
// 这个Channel中保存的各类事件的处理函数是在TcpConnection对象构造函数中注册的。
std::unique_ptr<Channel> channel_;

const InetAddress localAddr_;
const InetAddress peerAddr_;

// 用户自定义函数
// 分别注册给这些成员变量保存。
ConnectionCallback connectionCallback_;
MessageCallback messageCallback_;
WriteCompleteCallback writeCompleteCallback_;
HighWaterMarkCallback highWaterMarkCallback_;
CloseCallback closeCallback_;

size_t highWaterMark_;

// 该TCP连接对应的用户接收缓冲区。
Buffer inputBuffer_;

// 暂存那些暂时发送不出去的待发送数据。
Buffer outputBuffer_;

boost::any context_;

4.3 TcpConnection类核心成员方法(私有)

1
2
3
4
5
6
7
8
9
10
// 负责处理Tcp连接的可读事件。
// 它会将客户端发送来的数据拷贝到用户缓冲区中(inputBuffer_),然后再调用connectionCallback_保存的连接建立后的处理函数。
void handleRead(Timestamp receiveTime);
// 负责处理Tcp连接的可写事件。
void handleWrite();
// 负责处理Tcp连接关闭的事件。
// 将这个TcpConnection对象中的channel_从事件监听器中移除,然后调用connectionCallback_和closeCallback_保存的回调函数。
void handleClose();
// 负责处理Tcp连接错误的事件。
void handleError();

写在后面

这一篇介绍了其余几个主要类的功能,由于篇幅有限所以没能展开详述,自己目前对于架构梳理还是有些许不理解的地方,还要再仔细研究一下源码。后面打算通过一些应用Muduo的例子入手去学习一下。