📌本文采用wolai制作, link
1 回顾socket接口·
在分析muduo源码前,简单回顾下linux下的网络编程接口,这里用下csapp的slide:
这里解释下一些关键接口的含义:
- socket: 用于创建一个socket descriptor(就像open返回一个fd一样)
- bind: 将ip地址绑定到socket
1
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
- listen: 将一个socket从
active socket
转换为listening socket
默认情况下,创建的socket叫做1
2int listen(int socket, int backlog);
active socket
,这种socket只能用在client端。 通过listen
调用,将其转换为listening socket
,这种socket可以接收来自client的请求,用于server端。 - accept: server端用于等待client端的连接函数,连接信息放在
address
中。1
2
3int accept(int socket, struct sockaddr * address,
socklen_t * address_len); - connect: client端发起连接
1
int connect(int socket, const struct sockaddr *address, socklen_t address_len);
2 Acceptor源码·
Acceptor 用于处理新连接,正如官方注释写的:
1 | /// |
对外提供的接口有:
1 | Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport); |
包含一个处理链接的回调,和一个listen
监听接口。
主要成员包括:
1 | EventLoop* loop_; |
先看构造函数:
1 | Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport) |
acceptSocket_ 是muduo关于socket的封装。 关于socket的细节下文再说。本节重点关于Acceptor的逻辑即可。
channel已经在muduo源码分析1-事件循环(上)中分析过。
额外关注的是 acceptor
开启了ReusePort.
打开看acceptSocket_
的Reuse相关实现:
1 | void Socket::setReuseAddr(bool on) |
重点参数是两个flag:
SO_REUSEADDR
选项允许在TCP连接中,立即重用处于TIME_WAIT
状态的端口。这在服务器程序需要频繁重启时特别有用,因为它避免了必须等待旧连接完全关闭才能重新绑定端口的问题。SO_REUSEPORT
选项允许多个套接字绑定到同一个IP地址和端口。这对于实现负载均衡非常有用,因为可以创建多个监听套接字,每个监听套接字可以在不同的线程或进程中处理请求,从而提高并发处理能力。
这里提到了
TIME_WAIT
, 所以再说下TCP的四次回收断开连接过程。如下图:可以看到每个主动发起close的一端,在最后总会进入
TIME_WAIT
状态,等待2MSL时间才能真正断开,在此期间,原链接的ip+port 组是不能被复用的,对于高并发多连接的场景,是不可接受的,所以SO_REUSEADDR
的作用就是对于处于这个状态的连接,可以重用。
回到Acceptor
。 Acceptor
还提供了listen函数
, 其caller
为
1 | void TcpServer::start() |
再看 handleRead
1 | void Acceptor::handleRead() |
newConnectionCallback_
哪来的?在TcpServer
构造函数中注册进来的:
1 | TcpServer::TcpServer(EventLoop* loop, |
newConnection
函数已经在muduo源码分析1-事件循环(上)和muduo源码分析2-事件循环(下)都提到了, 这里再提一下:
1 | void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) |
拿到sockfd后,创建TcpConnection
对象,内部生成channel
,后面关于这个连接的读写,都通过channel
来监听,一旦出现读写事件,又会回调这里的 messageCallback_
和 writeCompleteCallback_
回调。 同时,当出现新建连接时,还会进入 connectEstablished
:
1 | void TcpConnection::connectEstablished() |
这里的connectionCallback_
就是最外层应用层逐层传递下来的,以HtppServer
为例:
1 | HttpServer::HttpServer(EventLoop* loop, |
2.1 一图串起来·
现在我们完全了解了 **创建一个新连接 **是怎么玩的了,画个图来总结。
3 Socket·
这个类是对底层socket
接口的wrap, 其实没什么好说的,贴下源码吧。
1 | /// |