C++11重写muduo网络库
文章平均质量分 68
剖析muduo网络库的常用组件,用C++11重写核心组件,实现一套网络库
林林林ZEYU
坚持
展开
-
809-服务器编程(主线程与工作线程的分工)
服务器编程(主线程与工作线程的分工)我们知道,服务器端为了能流畅处理多个客户端链接,一般在某个线程 A 里面 accept 新的客户端连接并生成新连接的 socket fd,然后将这些新连接的socketfd给另外开的数个工作线程 B1、B2、B3、B4,这些工作线程处理这些新连接上的网络 I/O 事件(即收发数据),同时,还处理系统中的另外一些事务。这里我们将线程A称为主线程,B1、B2、B3、B4 等称为工作线程。工作线程的代码框架一般如下:while (!m_bQuit) { e原创 2021-11-15 10:37:34 · 265 阅读 · 0 评论 -
664-Linux高效的wakeupfd进程间通信
eventfdeventfd是Linux 2.6提供的一种系统调用,它可以用来实现事件通知。eventfd包含一个由内核维护的64位无符号整型计数器,创建eventfd时会返回一个文件描述符,进程可以通过对这个文件描述符进行read/write来读取/改变计数器的值,从而实现进程间通信。#include <sys/eventfd.h>int eventfd(unsigned int initval, int flags);flags 可以是以下值的 OR 运算结果,用以改变 event原创 2021-10-03 20:27:51 · 302 阅读 · 0 评论 -
663-Linux高效的writev和readv函数
read()和write()系统调用每次在文件和进程的地址空间之间传送一块连续的数据。但是,应用有时也需要将分散在内存多处地方的数据连续写到文件中,或者反之。在这种情况下,如果要从文件中读一片连续的数据至进程的不同区域,使用read()则要么一次将它们读至一个较大的缓冲区中,然后将它们分成若干部分复制到不同的区域,要么调用read()若干次分批将它们读至不同区域。同样,如果想将程序中不同区域的数据块连续地写至文件,也必须进行类似的处理。readv()和writev()它们只需一次系统调用就可以实现在文原创 2021-10-03 20:19:06 · 1132 阅读 · 0 评论 -
488-手写C++muduo库的扩展
扩展1、TcpClient编写客户端类2、支持定时事件TimerQueue链表/队列 时间轮(libevent) nginx定时器(红黑树)3、DNS、HTTP、RPCDNSHTTPRPC4、丰富的使用示例examples目录提供了很多示例代码,使用姿势5、服务器性能测试 - QPS 涉及linux上进程socketfd的设置相关QPS是多少就是每秒支持多少的查询压力测试工具wrk在linux上,需要单独编译安装 直接创建线程组,发送的时间,压力测试的时间,但是只能测原创 2021-08-27 21:41:50 · 298 阅读 · 0 评论 -
487-手写C++muduo库的梳理总结
Channelfd表示要往poller上注册的文件描述符events就是事先设置的fd所感兴趣的事件(读或者写)revents就是poller最终给我们channel通知的fd上发生的事件,channel根据相应的发生的事件执行相应的回调。对于上层来说,如果有一个fd的话,它就会把fd打包成channel通道,下发到poller上。我们看看poller的头文件poller有一个成员变量channels,是一个map,键就是channel打包的sockfd,值就是包含fd对应的chann..原创 2021-08-27 21:22:19 · 908 阅读 · 0 评论 -
486-手写C++muduo库(测试代码)
testserver.cc#include <mymuduo/TcpServer.h>#include <mymuduo/Logger.h>#include <string>#include <functional>class EchoServer{public: EchoServer(EventLoop *loop, const InetAddress &addr, cons原创 2021-08-27 13:14:55 · 352 阅读 · 0 评论 -
485-手写C++muduo库(TcpConnection)
Buffer封装是一个缓冲区8字节长度(解决粘包问题)+读数据+写数据根据下标进行3个成员变量:数组,数据可读的下标,数据可行的下标Buffer.h#pragma once#include <vector>#include <string>#include <algorithm>//网络库底层的缓冲器类型定义class Buffer{public: static const size_t kCheapPrepend = 8..原创 2021-08-27 11:32:17 · 512 阅读 · 1 评论 -
484-手写C++muduo库(TcpServer)
Callbacks.h#pragma once#include <memory>#include <functional>class Buffer;class TcpConnection;class Timestamp;using TcpConnectionPtr = std::shared_ptr<TcpConnection>;using ConnectionCallback = std::function<void (const TcpC.原创 2021-08-27 10:03:29 · 454 阅读 · 1 评论 -
483-手写C++muduo库(socket封装fd,Acceptor)
我们在之前已经完成了对前面5个模块的剖析和重写。现在我们看AcceptorAcceptor就是处理accept,监听新用户的连接,拿到跟客户端通信的clientfd,打包成channel,根据muduo的轮询算法找一个subloop,把subloop唤醒,把接收的channel给subloop。我们打开TCPServer,处理一下AcceptorAcceptor运行在我们的baseloop(mainreactor)里面封装了socketsocket封装fdSocket.h#pra.原创 2021-08-26 21:42:28 · 387 阅读 · 2 评论 -
482-手写C++muduo库(Thread,EventLoopThread,EventLoopThreadPool)
EventLoopThreadPool:事件循环的线程池,管理事件循环调度我们点进去EventLoopThreadPool,看到打包了一个eventloop和一个线程我们再进去Thread里面就是底层的Thread,我们用C++11精简我们分别实现上面的3个类,从小到大输出Thread线程类Thread.h#pragma once#include "noncopyable.h"#include <functional>#include <thread>原创 2021-08-26 20:25:38 · 409 阅读 · 0 评论 -
481-手写C++muduo库(EventLoop事件循环)
EventLoop相当于reactor模型的reactor反应堆的角色poller和epollpoller相当于是多路分发器的角色,掌控epoll的所有操作最起码得有一个线程来支撑。如果我们设置了setthreadnumber的多线程的反应堆类型,mainreactor就是处理新用户的连接,accept,拿到新用户通信的fd,把fd感兴趣的事件打包成channel,然后唤醒某个工作线程workreactor(subreactor)(轮询的方式),代表eventloop。每个工作线程subreact原创 2021-08-26 18:00:02 · 1994 阅读 · 0 评论 -
480-手写C++muduo库(EPollPoller事件分发器,获取线程tid代码)
EPollPoller事件分发器EPollPoller的主要实现:作为poller的派生类,把基类给派生类保留的这些纯虚函数的接口实现出来。overirde表示在派生类里面,这些方法是覆盖方法。必须由编译器来保证在基类里面一定有这些函数的接口的声明。在派生类要重写他们。给EPollPoller的析构函数写overide,就是让编译器给你检查基类的析构一定是虚函数。底层是vector,放eventlist,可以动态地扩容。成员变量的epollfd要通过epoll_create来创建,映射的就是e原创 2021-08-26 10:52:34 · 433 阅读 · 0 评论 -
479-手写C++muduo库(poller抽象类)
Poller是抽象类为什么muduo库要抽象一层Poller?因为在eventloop里面,在使用I/O复用的时候,并没有直接指定epoll,因为muduo库对外提供I/O复用的能力有2个:1个是poll,1个是epoll,在eventloop里面,不可能直接去使用poll或者epoll。是从抽象层面直接使用抽象类poller,到时候引用不同的派生类对象,调用同名覆盖方法,就可以非常方便地去扩展不同的I/O复用能力,多路分发器。poller监听的就是eventloop保存的那些channelp.原创 2021-08-25 20:48:25 · 399 阅读 · 1 评论 -
478-手写C++muduo库(Channel)
TcpServer相当于是muduo库提供给外部编写服务器程序的入口的一个类,相当于一个大箱子,把muduo库有关服务器的编程相关的东西,包括反应堆,事件分发器,事件回调都打包一块了。我们看看它的成员变量。eventloop事件循环相当于是一个epoll,管理pooller相当于是epoll抽象的概念。事件分发器在这里面最重要的两个东西:poller和channel我们看一下channel是什么revents是具体的发生的事件channel我们理解成通道,相当于就是fd和它所绑定.原创 2021-08-25 19:46:40 · 915 阅读 · 1 评论 -
477-手写C++muduo库(Cmake,nocopyable,logger,Timestamp,InetAddress)
我们创建的项目工程名:mymuduo我们在mymuduo下创建CMakeLists.txtcmake_minimum_required(VERSION 2.5)project(mymuduo)# cmake => makefile make# mymuduo最终编译成so动态库,设置动态库的路径,放在根目录的lib文件夹下面set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)# 设置调试信息 以及 启动C++11语言标准set(CM原创 2021-08-25 11:42:15 · 655 阅读 · 0 评论 -
476-select,poll,epoll对比总结
select和poll的缺点select的缺点:1、单个进程能够监视的文件描述符的数量存在最大限制,通常是1024,当然可以更改数量,但由于select采用轮询的方式扫描文件描述符,文件描述符数量越多,性能越差;(在linux内核头文件中,有这样的定义:#define __FD_SETSIZE 10242、内核 / 用户空间内存拷贝问题,select需要复制大量的句柄数据结构(文件描述符),产生巨大的开销3、select返回的是含有整个句柄的数组,应用程序需要遍历整个数组才能发现哪些句柄发生了事件原创 2021-08-25 09:24:33 · 308 阅读 · 0 评论 -
475-Reactor模型
Reactor模型反应器设计模式是用于处理服务请求的事件处理模式由一个或多个输入并发地交付给服务处理程序。服务处理程序然后将传入的请求解复用,并将它们同步地分发到相关的请求处理程序。重要组件:Event事件、Reactor反应堆、Demultiplex事件分发器、Evanthandler事件处理器在整个的基于Reactor模型的网络服务请在交互的时候,首先,我们把事件注册到反应堆上,也就是说,应用程序对这个事件感兴趣,请求反应堆帮忙来监听它所感兴趣的事件,并且在这个事件发生的时候调用相应的预置的回原创 2021-08-24 21:16:55 · 260 阅读 · 0 评论 -
474-设计良好的网络服务器
设计良好的网络服务器在这个多核时代,服务端网络编程如何选择线程模型呢?赞同libev作者的观点:one loop per thread is usually a good model,这样多线程服务端编程的问题就转换为如何设计一个高效且易于使用的event loop,然后每个线程run一个event loop就行了(当然线程间的同步、互斥少不了,还有其它的耗时事件需要起另外的线程来做)。event loop 是 non-blocking (非阻塞)网络编程的核心,在现实生活中,non-blocking原创 2021-08-24 20:45:50 · 582 阅读 · 0 评论 -
473-Unix/Linux上的五种I/O模型
Unix/Linux上的五种I/O模型I/O模式是操作系统上任何的I/O,内存I/O,磁盘I/O,网络I/O都可以应用。我们主要考虑网络I/O。阻塞 blocking同步的阻塞的I/O模型,效率不高。内核空间就是网络接收到远端发送过来数据的tcp接收缓冲区。应用进程调用read,系统调用,是系统的I/O接口。在应用进程看来,是一直阻塞住,数据是否就绪、数据就绪后的从内核空间向用户空间的拷贝整个过程,应用程序时间都要在read上花费完,一直阻塞住。应用程序调用read这个I/O接口,内核把这一原创 2021-08-24 20:30:18 · 248 阅读 · 0 评论 -
472-I/O阻塞和非阻塞,同步和异步
阻塞、非阻塞、同步、异步典型的一次I/O的两个阶段是什么?数据准备 和 数据读写我们作为服务器,接收客户端的请求,得先监听客户端有没有数据过来,这是一个状态,还有就是数据过来了该怎么去读写,这又是一个状态。实际上,阻塞,非阻塞,同步,异步,分别是这两种状态下的体系。网络I/O阶段1数据准备:根据系统IO操作的就绪状态阻塞 : 让调用I/O的线程进入阻塞状态 ,数据准备好了就唤醒非阻塞: 不会改变线程的状态,通过返回值判断sockfd相当于就是系统的文件描述符,代表1个I/O,创建的时候原创 2021-08-24 18:16:39 · 579 阅读 · 0 评论