仿muduo库实现并发服务器
1.Acceptor模块
Acceptor模块的功能是对监听套接字进行管理,里面要封装Socket模块,Channel模块,Eventloop模块。
主要流程:
1.首先要创建一个监听套接字连接
2.启动监听套接字的读事件监控
3.读事件就绪后就去获取新连接套接字
4.获取连接成功之后就调用对连接处理的回调函数。
(对新连接的操作:为新连接创建Connection进行管理…)
注意:acceptor模块它只关心获取连接,不关心获取成功后对新连接如果操作,对新连接如何操作是由服务器决定的。
对于新连接如何处理,是由服务器来管理的,所以服务器模块需要实现一个获取新连接套接字成功之后对新连接进行处理的函数,将这个函数设置给Acceptor模块中的回调函数。
2.成员变量
Acceptor是对监听套接字进行管理的,所以首先需要能够创建一个监听套接字(Socket),然后还需要对这个监听套接字进行读事件监控(EventLoop),读事件一旦就绪还需要执行读事件处理:获取连接套接字(Channel)。成功获取连接套接字之后需要对连接进行处理,所以还需要一个回调函数callback。
所以需要四个变量
private:
Socket _socket;//用于创建监听套接字以及后续获取新连接操作
EventLoop *_loop;//用于监听套接字的读事件监控
Channel _channel;//用于监听套接字的事件管理(读事件就绪做什么)
using NewLinkCallback=std::function<void(int)>;
NewLinkCallback _newlink_callback;//对新连接的后续操作回调函数
3.成员函数
3.1私有成员函数(对内部提供的接口)
①HandleRead()
连接一般在构造时就将channel各种事件回调函数设置进去了,所以我们在这里需要提供监听套接字读就绪之后该怎么处理操作,以便在构造时,设置进去。
监听套接字读就绪要做什么呢?很简单,就是获取新的套接字,然后调用新连接获取成功之后的处理回调函数。
②CreateServer(port)
在创建套接字连接时是一步到位的,只不过需要传入对应的端口号。Socket里面是封装好的。
因为channel初始化时是需要两个参数一个是绑定的eventloop,一个是对应的套接字,而想要获取套接字,就必须要先创建套接字,创建套接字连接只能在函数体中进行,那这样channel就无法初始化了。
所以我们封装一下接口,先在初始化列表中创建处监听套接字,这样channel就能获取到套接字了。
int CreateServer(uint16_t port)
{
//创建监听套接字
bool ret=_socket.CreateServer(port);
assert(ret==true);
return _socket.Fd();
}
3.2公有成员函数(向外提供的接口)
①构造函数
在初始化列表中已经将套接字连接创建出来了,成员变量也初始化了,就差将监听套接字对应的channel的读事件回调函数设置进去了。构造时只要传入要绑定的Eventloop,和要连接的服务器端口号。所以Acceptor对象构建好,就代表着监听套接字连接已经创建成功,并将设置了channel读事件就绪处理回调函数。
public:
Acceptor(EventLoop* loop,uint16_t port):_socket(CreateServer(port)),_loop(loop),_channel(loop,_socket.Fd())
{
//设置监听套接字的读事件就绪回调函数
_channel.SetReadCallback(std::bind(&Acceptor::HandleRead,this));
}
还要注意监听套接字的读事件监听不能放在构造函数中执行,因为会存在刚创建好监听套接字连接,并且启动了读事件监控,同时读事件也就绪了,调用读事件回调函数,获取新连接,但是这个时候服务器对新连接的操作回调函数还没有设置进去,监听套接字的读事件回调函数就只会获取新连接,然后调用空的回调函数,什么都不干。
所以启动监听套接字读事件监控,必须放在服务器设置好获取连接之后回调函数后面。
②设置成功获取连接之后的回调函数
void SetNewlinkCallback(const NewLinkCallback&cb)
{
_newlink_callback=cb;
}
③启动读事件监控
//不能让启动监控操作放入构造函数中,防止构造时就启动后监控,然后立刻读事件就绪了,这个时候服务器的新连接处理函数还没有设置进去
//也就只获取到了新连接,没有对这个新连接进行后续操作,所以启动操作要放在设置回调函数之后
void EnableListen()
{
_channel.EnableRead();
}