77.Linux撒花

lesson52

listenner会有个hander指针,每遇到新链接,就把这个指针注册进去,相当于一个中间人,

拼模块

main中注册lsitenner回调,listenner自己不用,在获得连接后,注册给每一个connection,channel内回调方法就会回调到protocol的。

此时匿名对象怎么写

回调函数中的参数channel可以调用到输入缓冲区, 参数用的都是引用。内部就是对inbuffer进行处理的,

如果没读到完整报文就直接结束回调 ,channnel内 recv就结束,就会在epoll中继续执行新数据,添加到inbuff后面,

不管缓冲区满没满,只要设置一次out关心,就触发一次写事件就绪,如果是满的,仍然放在epoll内(循环写,错误码ewouldblock或者eagan就是写满了,不能写了)

读到outbuffer有数据就直接发,如果没发完,开启些时间关心,未来reactor当底层有空间,主动wait获得时间,主动sender主动发完

main函数中,一旦读事件就绪,回调之后对报文解析,上层返回,发送是由epoll完成,刚开始是由我自己发一次,之后就不用管了。

out不为空可以不发,开启对写事件的关心,下一次epoll自动写事件就绪,

看课件改多线程

数据发多次,可能交给不同线程,两个线程竞争一个fd,可能向一个socket写的顺序不一样了

reactor是模块,可以设计,

master 获得一个新链接,识别到listener套接字就绪,不获取连接负载均衡的分配写给管道,每个slave的reactor把管道读端封装成connection,添加到自己reactor,所以一旦master向管道里写,就通知slave,slave的ractor读时间就绪,唤醒哪个进程,哪个进程就调用listener模块,获取连接添加到自己reactor,就实现一个进程一个reactor。实现了多进程。

多线程:可以把管道当成套接字,master和每个slaver都建立连接,都用127连接本地服务就可以了,主线程还是多线程共享文件描述符表,

master获取上来listen套接字之后,往指定管道写,套接字读端封装成connection添加到自己reactor一旦事件就绪,就从管道读上来按四字节读文件描述符,多线程也能把文件描述符拿到添加到自己reactor里,多线程当中,共享文件描述符表,master把文件描述符拿上来,同过管道添加到slaver,对端拿到数字添加到自己reator里。

下面代码说明fd平替管道

最终方案:listen套接字添加到自己所对应的reactor里,有新链接到来这个reactor就会就绪,然后accept获取文件描述符,上面用队列和互斥锁,维护socketfd池,然后在master创建好几个eventfd(得到文件描述符),slaver把这个添加到自己reactor,这个线程就可以从sockfd池把文件描述符拿到自己reactor,全部由自己reactor管理,这就是基于eventfd的多线程通知另外线程的做法。

eventfd,不设置EFD 可以当成只有一个字节的管道

内核里就是一个整数,以文件形式管理,你写,别人能读,计数器变化了可以通知你,

添加EFD 以信号量方式工作,以文件描述符方式让我们两个进程一个通过read 一个write 类似操作信号量。

我们用:我给对方写,对方epoll就会就绪,这就是做个时间通知,不像管道还要从内核到用户,用户到内核。

所以创建多个fd,把多个fd维护到master的reactor,同时添加到slave的ractor里,一旦事件就绪,从应用层加锁维护的文件描述符集获取文件描述符,不用从管道拿,不用发生拷贝

master把listener封装,但是listrern就绪不要调用accept,listener模块里不要包含listener套接字而是包含所有管道写端,一旦listen就绪向指定管道写1,唤醒后端指定进程,因为子进程或新线程能读到文件描述符,唤醒就能获取到新的文件描述符

最佳实践:listen套接字添加到自己所对应的reactor里,再构建一个文件描述符集里面放vector和锁,文件描述符就绪就把链接添加到这个集,同时向eventfd写唤醒然后从这个集写。

课堂板书/20250607_结课.png · whb-helloworld/113 - 码云 - 开源中国