当前位置: 首页 > news >正文

站长工具查询视频网站怎么做360免费优化

站长工具查询视频,网站怎么做360免费优化,wikidot网站怎么做,dede网站单页面怎么做Timestamp时间管理类 ①#xff1a;主要提供now函数显示当前时间#xff1a;自1970年1月1日0点以来经过的秒数#xff0c;使用time函数 ②#xff1a; toString函数将字符串转化成时间字符串#xff0c;使用localtime函数将秒数格式化成日历时间 解析tm_time 并以日历格… Timestamp时间管理类 ①主要提供now函数显示当前时间自1970年1月1日0点以来经过的秒数使用time函数 ② toString函数将字符串转化成时间字符串使用localtime函数将秒数格式化成日历时间 解析tm_time 并以日历格式输出 // 2022/08/26 16:29:10 // 20220826 16:29:10.773804 ③如果想更景区可以显示微秒toFormattedString函数 InetAddress地址管理类 封装了socket地址提供了方便的方法来处理IP地址和端口以及“sockaddr_in”结构转换的功能。 ①接收提供端口号和IP号两个参数的构造函数也接受直接用sockaddr_in结构来初始化这个类。 ②网络地址或端口转化成本地字符串给人阅读 toIp(): 返回IP地址的字符串表示。toPort(): 返回端口号。toIpPort(): 返回IP:端口格式的字符串 inet_ntoa转IP、ntohs转端口 ③设置sockaddr_in结构 getSockAddr(): 获取内部的sockaddr_in结构的指针。setSockAddr(): 设置内部的sockaddr_in结构。 三大核心模块 Muduo库是基于Reactor模型实现的TCP网络编程库。Multi-Reactor模型 Muduo库有三个核心组件支撑一个reactor实现持续监听一组fd并根据每个fd上发生的事件调用相应的处理函数。这三个组件分别是Channel类、Poller/EpollPoller类以及EventLoop类。 三大核心模块一Channel类 Channel类则封装了一个 [fd] 和这个 [fd感兴趣事件] 以及事件监听器监听到 [该fd实际发生的事件]。同时Channel类还提供了设置该fd的感兴趣事件以及将该fd及其感兴趣事件注册到事件监听器或从事件监听器上移除以及保存了该fd的每种事件对应的处理函数。 Channel文件描述的保姆 也就是说Channel里主要就是封装了sockfd感兴趣的事件类型events_事件的回调函数用户设置的传给Channel用 ①Channel类的主要成员变量 int fd_这个Channel对象照看的文件描述符int events_代表fd感兴趣的事件类型kNoneEvent、kReadEvent、kWriteEventint revents_代表事件监听器Poller实际监听到该fd发生的事件类型集合当事件监听器监听到一个fd发生了什么事件通过Channel::set_revents()函数来设置revents值。Poller返回的具体发生的事件类型。EventLoop* loop这个fd属于哪个EventLoop对象。int index表示Channel在Poller中的状态有kNew未添加、kAdded已添加、kDeleted已删除。read_callback_ 、write_callback_、close_callback_、error_callback_这些是std::function类型代表着这个Channel为这个文件描述符保存的各事件类型发生时的处理函数。比如这个fd发生了可读事件需要执行可读事件处理函数这时候Channel类都替你保管好了这些可调用函数真是贴心啊要用执行的时候直接管保姆要就可以了。 ②Channel类重要的成员方法 --向Channel对象注册各类事件的处理函数 这里是用户设置的根据Poller返回的发生事件的具体类型设置的 --将Channel中的文件描述符及其感兴趣事件注册事件监听器上或从事件监听器上移除 外部通过这几个函数来告知Channel你所监管的文件描述符都对哪些事件类型感兴趣并把这个文件描述符及其感兴趣事件注册到事件监听器IO多路复用模块上。update实际上是epoll_ctl。 --index用来标识 channel在poller中的状态 --set_revents Poller监听Channel具体发生了什么事件并返回回去 当事件监听器监听到某个文件描述符发生了什么事件通过这个函数可以将这个文件描述符实际发生的事件封装进这个Channel中。 --void HandlerEvent根据Poller返回给Channel的revents_判断去执行什么回调函数 Pollr中调用了epoll_wait得知那些Channel文件描述符发生了那些事件事件发生后自然就要调用这些Channel对应的处理函数。通过Channel中的revents_变量得知和感兴趣的事件通过Channel中的events_变量得知来选择调用read_callback_和/或write_callback_和/或close_callback_和/或error_callback_。 三大核心模块二Poller类/EpollPoller类 负责监听文件描述符事件是否触发以及返回发生事件的文件描述符以及具体事件的模块就是Poller。所以一个Poller对象对应一个事件监听器这里我不确定要不要把Poller就当作事件监听器。在multi-reactor模型中有多少reactor就有多少Poller。 muduo提供了epoll和poll两种IO多路复用方法来实现事件监听。不过默认是使用epoll来实现也可以通过选项选择poll。该项目自己重构的muduo库只支持epoll。 这个Poller是个抽象虚类由EpollPoller和PollPoller继承实现与监听文件描述符和返回监听结果的具体方法也基本上是在这两个派生类中实现。 EpollPoller就是封装了用epoll方法实现的与事件监听有关的各种方法。 ①EpollPoller的重要成员变量 epollfd_ 就是用epoll_create方法返回的epoll句柄。channels_这个变量是std::unordered_mapint, Channel*类型负责记录文件描述符--Channel的映射也帮忙保管所有注册在Poller上的Channel。ownerLoop_:所属的EventLoop对象 ②EpollPoller给外部提供的最重要的方法 TimeStamp poll(int timeoutMs, ChannelList *activeChannels) Poller的核心底层调用epoll_wait获取监听器上发生事件的fd及其对应发生的事件每个fd都是由一个Channel封装的通过哈希表channels_可以根据fd找到封装fd的Channel。 Poller监听的该fd发生的事件写入Channel中的revents_成员变量。然后通过一个fillActiveChannels函数将该Channel装进activeChannels_它是一个vectorChannel*中表示活跃连接集合。 EventLoop调用玩poll之后就可以拿到监听结果activeChannels_ 三大核心模块三EventLoop类 Poller封装了和事件监听有关的方法和成员epoll_ctl , epoll_wait调用一次Poller::poll方法它就返回事件监听器的监听结果发生事件的fd及其发生的事件。 作为一个网络服务器需要有持续监听、持续获取监听结果、持续处理监听结果对应的事件的能力也就是我们需要循环去调用Poller::poll方法获取实际发生事件的Channel集合然后调用这些Channel里面保管的不同类型事件的处理函数调用Channel::HandlerEvent方法 EventLoop就是负责实现“循环”负责驱动“循环”的重要模块 Channel和Poller其实相当于EventLoop的手下EventLoop封装了二者并向上提供了更方便的接口来使用。 One Loop Per Thread每一个EventLoop都绑定了一个线程一对一绑定这种运行模式是Muduo库的特色充分利用了多核cpu的能力每一个核的线程负责循环监听一组文件描述符的集合。 ①EventLoop中的重要成员变量 atomic_bool looping_ 原子类型bool变量表示EventLoop是否正在运行atomic_bool quit_原子类型bool变量表示EventLoop是否已被要求停止pid_t threadId_ 记录当前loop所在线程tidunique_ptrPoller poller_ 指向Poller对象的指针用于多路复用IO事件分发unique_ptrTimerQueue timerQueue_指向定时器队列指针执行定时任务vectorChannel* activeChannels_ 一个Channel列表存储当前活跃的ChannelsvectorFunctor pendingFunctors_ 存储loop需要执行的所有的回调操作mutex mutex_ 保护pendingFunctors_等可能被多个线程同时访问的成员int wakeupFd_ 由linux内核eventfd创建出来的一个唤醒文件描述符用于在一个线程中唤醒另一个线程的EventLoop每一个线程都有自己的wakeupFd主线程mainLoop想唤醒一个SubLoop可以像SubLoop的wakeupFd写入数据被唤醒的线程会读取自己的wakeupFd清空它并处理唤醒事件 ②EventLoop中重要的成员方法 EventLoop重要方法 EventLoop:loop() 每个EventLoop对象都唯一绑定了一个线程这个线程其实就是在执行这个函数中的while循环这个while循环的大致逻辑比较简单。就是调用Poller::poll方法获取事件监听器上的监听结果结果会存在activeChannels_中。接下来在loop里面就会调用监听结果中每一个Channel的处理函数HandlerEvent()。每一个Channel的处理函数会根据Channel类中封装的实际发生的事件执行Channel类中封装的各事件处理函数。 这里while中还会执行doPendingFunctors()函数执行掉当前Loop事件循环需要处理的回调函数这些函数是放在std::vectorFunctor pendingFunctors_之中。mainLoop只做accept新用户的连接 quit(): 用于停止事件循环 如果loop在自己的线程中调用了quit直接退出 如果在非loop的线程中调用loop需要通过wakeup函数调用wakefd通知唤醒。 ⭐⭐⭐eventfd()跨线程调度任务 eventfd()是Linux内核为用户空间程序提供的轻量级事件通知机制。主要代替更为复杂、重量级的通知方式比如管道等从而为跨线程或进程间通信提供了一个简单、高效的方式。 创建一个eventfd对象时内核会返回一个文件描述符这个文件描述符可以用来进行读写操作。内部是一个计数器写入整数值会被加到计数器上读取时取出计数器当前值重置为0。 muduo中每一个EventLoop创建时都生成一个由eventfd返回的wakeupFd_并封装成wakeupChannel_通过bind函数设置回调函数handleRead交给Poller监听读事件 handleRead()函数 读 wakeup()函数写 runInLoop(const Functor cb): 在事件循环线程中执行给定的回调。如果当前在同一线程中它会立即执行回调否则它会排队等待在事件循环中执行。 queueInLoop(const Functor cb): 将回调放入队列中在事件循环的下一个迭代中执行。 doPendingFunctors()执行回调 在loop中调用的方法 这里又开辟了一个临时空间存放回调方法资源交换把pendingFunctors_释放出来 Poller接口 CurrentThread获取线程tid类 服务器肯定有多个线程一个线程执行一个EventLoop所以我们会有很多个EventLoop每个EventLoop都有很多Channel自己Channel上的事件要在自己的EventLoop线程上去处理为了控制这些逻辑EventLoop在这里涉及到获取当前线程ID。 使用 __thread 线程局部存储 (TLS) 变量每个线程都有自己的变量副本这个变量副本的生命周期和使用它的线程生命周期相同。C11提供 ‘thread_local’关键字 __thread int t_cachedTid 0;   获取Tid的过程是一个系统调用从用户空间切换到内核空间比较浪费时间第一次访问就把Tid存储在定义的线程局部变量中t_cachedTid EventLoop相关的三个线程类 Thread线程类 使用C11的thread类创建一个线程这里是 ①thread成员变量 bool started_;  //启动当前线程bool joined_; // 当前线程等待其他线完了再运行下去std::shared_ptrstd::thread thread_; // 自己掌控线程对象产生的时机这里直接调用thread thread_它会立即创建一个新线程pid_t tid_;ThreadFunc func_;  // 存储线程函数std::string name_; // 调试的时候打印static std::atomic_int numCreated_; // 对线程数量计数 ②thread成员方法 start() 启动当前线程 join() 当前线程等待其他线程完了再运行下去 EventLoopThread事件类 对EventLoop和thread的封装通过bind绑定器将其绑定 这允许在一个单独的线程中执行 I/O 操作不影响主线程的执行。这对于某些应用程序来说是有用的因为它们可能想要在不同的线程中独立地处理 I/O从而提高性能。 ①EventLoopThread成员变量 void threadFunc();//线程函数创建loop    EventLoop *loop_;    bool exiting_;//是否退出循环    Thread thread_;    std::mutex mutex_;    std::condition_variable cond_;    ThreadInitCallback callback_;//初始化操作 ②EventLoopThread成员方法 EventLoopThread::EventLoopThread构造函数 这里重要的点就是通过bind函数将threadFunc函数和thread_绑定起来也就是将线程创建和EventLoop创建绑定起来。 EventLoopThread::startLoop() 开启循环EventLoopThread::threadFunc() start()运行后创建新线程执行绑定的threadFunc函数 ⭐⭐⭐这两个函数要放到一起说         1. 首先在startLoop函数中调用thread_.start()启动新线程去执行在EventLoop构造函数中绑定的threadFunc函数         2. 在startLoop函数中创建一个EventLoop对象loop初始化为nullptr         3. 进入一个作用域unique_lockstd::mutex lock(mutex_)创建互斥锁         4. while循环检查loop_是否为nullptr如果为空调用cond_.wait(lock)挂起等待其他线程通过调用cond.notufy_one()唤醒继续执行         5. 其他线程调用cond.notufy_one()后while循环退出将loop_赋值给loop返回loop也即返回新线程中创建的Eventloop对象         6. 在threadFunc函数中首先创建一个EventLoop对象loop每个线程都用有一个独立的EventLoop         7. 如果存在callback_,则调用callback_(loop)去执行回调函数         8. 进入一个作用域unique_lockstd::mutex lock(mutex_)创建互斥锁并将loop_设置为当前loop即将新线程中创建的EventLoop对象loop赋值给loop_,然后cond.notufy_one()唤醒等待中的线程。         9. 调用loop.loop()进入事件循环执行EventLoop中的loop()函数         10. 事件循环结束后也就是EventLoop中的loop()函数退出后再次获取锁将loop_设置为nullptr表示线程结束。         11. 返回到startLoop函数将loop返回。         该过程实现了创建一个新线程并在新线程中运行一个独立的 EventLoop 对象并通过条件变量等待新线程中的 EventLoop 对象创建完成后返回从而实现了一个 one loop per thread 的设计模式。 EventLoopThreadPool池 EventLoopThreadPool 管理一个线程池每个线程都有自己的 EventLoop。它允许多线程并发处理 I/O 操作。EventLoopThreadPool 对于利用多核 CPU 构建高性能的网络服务器尤其有用因为每个线程可以在单独的 CPU 核心上运行提供真正的并行处理。当新的连接到来时EventLoopThreadPool 可以选择一个现有的 EventLoop运行在某个线程上来处理该连接。 ①EventLoopPoll的成员变量 vectorEventLoop* loops_ 件线程EventLoopThread里面的EventLoop指针EventLoop *baseLoop_ 最基本的loop mainloopbool started_ 表示 EventLoopPool 是否已启动int numThreads_;  线程数量int next_; 做轮询的下标使用的vectorstd::unique_ptrEventLoopThread threads_  所有事件的线程 ②EventLoopPoll的成员函数 start(const ThreadInitCallback cb) 启动EventLoopPoll启动所有的线程和事件循环 由设置的线程数量numThreads_循环构建EventLoopThread并将所有的EventLoopThread放到管理容器threads_中去同时每一个EventLoopThread执行startLoop()开启循环。 EventLoopThreadPool::getNextLoop()通过轮询选择下一个loop EventLoopThreadPool::getAllLoops()返回有所得loop 根据存放所有loop得容器loops_返回 Acceptor类 muduo库在使用得时候需要我们自己顶一个EventLoop这个是mainLoop如果用户在使用时没有通过EventLoopThreadPool提供得setThreadNum()函数设置muduo库得底层线程 得个数得话那么他得IO线程和工作线程实际上是一个线程。这个setThreadNum()设置得实际上是SubReactor得数量。 Acceptor接受新用户连接并分发连接给SubReactorSubEventLoop封装了服务器监听套接字fd以及相关处理方法以及对其他类得方法进行调用。 处理accept监听新用户连接新用户连接响应以后拿到和客户端通信的clientfd打包成Channel然后根据muduo库的轮询算法找一个subloop将Channel给到subloop,扔给subloop之前需要将subloop唤醒一下(wakeupfd : 每loop都有一个wakeupfd 他那个Linux的系统调用eventfd创建的一个带有线程notify即带有通知机制的fd)mainloop可以向subloop随便写 个整数唤醒subloop将打包好的Channel扔给subloop也就是注册到subloop的Poller上! Acceptor运行在我们的baseLoopmainReactor里面。需要从监听队列中监听新用户的连接所以需要有一个listen fdmuduo将这个fd也封装了就是Socket Socket类 封装listenfd包括 listen() 、accept() 都在这里实现。 ①Socket类的成员变量 const int sockfd_ 对listenfd的封装 ②Socket类的成员方法 void bindAddress(const InetAddress localaddr); //调用bind绑定服务器Ip端口 void listen(); //调用listen监听套接字 int accept(InetAddress *peeraddr);  //调用accept接收新客户连接请求 这里使用了accept4() 主要它可以设置成非阻塞的 accept 是阻塞调用会一直等待直到有新的连接到达而 accept4 可以设置为非阻塞模式即使没有新连接到达它也会立即返回。 void shutdownWrite();  //调用shutdown关闭服务端写通道 ①Acceptor成员变量 acceptSocket_这个是服务器监听套接字的文件描述符 创建一个非阻塞的fdacceptChannel_这是个Channel类把acceptSocket_及其感兴趣事件和事件对应的处理函数都封装进去。EventLoop *loop监听套接字的fd由哪个EventLoop负责循环监听以及处理相应事件其实这个EventLoop就是main EventLoop。newConnectionCallback_: TcpServer构造函数中将TcpServer::newConnection( )函数注册给了这个成员变量。这个TcpServer::newConnection函数的功能是公平的选择一个subEventLoop并把已经接受的连接分发给这个subEventLoop。 ②Acceptor成员函数 构造函数Acceptor::Acceptor 封装成acceptChannel_ 并绑定回调函数handleRead 析构函数Acceptor::~Acceptor() listen( )该函数底层调用了linux的函数listen( )开启对acceptSocket_的监听同时将acceptChannel及其感兴趣事件可读事件注册到main EventLoop的事件监听器上。换言之就是让main EventLoop事件监听器去监听acceptSocket_ handleRead( )这是一个私有成员方法这个方法是要注册到acceptChannel_上的 同时handleRead( )方法内部还调用了成员变量newConnectionCallback_保存的函数。当main EventLoop监听到acceptChannel_上发生了可读事件时新用户连接事件就是调用这个handleRead( )方法。 简单说一下这个handleRead( )最终实现的功能是什么接受新连接并且以负载均衡的选择方式选择一个sub EventLoop并把这个新连接分发到这个subEventLoop上通过TcpServer设置的newConnectionCallback_。 TcpServer对外提供类 Acceptor是在mainloop中做事情了做事情的回调函数是由TcpServer给它传递的! ①TcpServer成员变量 有event loop有acceptor跟accept相关的操作全部打包进去事件循环的这个线程池threadPool_有一系列的回调再者它就有一个connection map它维护了所有的连接。 EventLoop *loop_;//baseLoop 主事件循环 用户定义的loop 一个线程一个loop循环const std::string ipPort_;//服务器的IP地址端口号const std::string name_;//服务器的名称 ⭐unique_ptrAcceptor acceptor_ 运行在mainReactor监听新连接事件 shared_ptrEventLoopThreadPool threadPool_ //线程池 ⭐using ConnectionMap std::unordered_mapstd::string, TcpConnectionPtr;     ConnectionMap connections_;//保存所有活动的TcpConnection连接 ②TcpServer成员函数 构造函数、析构函数 TcpServer要传入当前mainLoop 构造函数需要主事件循环、监听地址、服务器名和端口重用选项。 析构函数用于资源清理。 设置回调函数用户设置的 线程与启动 setThreadNum设置线程池中线程的数量。start启动服务器开始监听。启动Loop线程池并且TcpServer开始监听新用户的连接。newConnection 处理新的TCP连接 removeConnection和removeConnectionInLoop移除一个TCP连接。 TcpConnection类 它主要就是用来打包呢成功连接服务器的客户端的这么一条通信链路 TcpServer通过Acceptor得知有一个新用户连接通过accept函数拿到connfd 》通过TcpConnection 设置回调函数然后给Channel然后给Poller判断是什么事件然后再返回给Channel去执行Channel的回调函数 ①TcpServer成员变量 EventLoop *loop_  这里loop一定不是mainloop 因为TcpConnection都是在subLoop里面管理unique_ptrSocket socket_;  unique_ptrChannel channel_;const InetAddress localAddr_;//当前主机IP地址端口号const InetAddress peerAddr_;//对端IP地址端口号ConnectionCallback connectionCallback_;//有新连接时的回调    MessageCallback messageCallback_;//有读写消息时的回调    WriteCompleteCallback writeCompleteCallback_;//消息发送完成以后的回调    HighWaterMarkCallback highWaterMarkCallback_;//水位 控制发送数据的速度    CloseCallback closeCallback_;    size_t highWaterMark_;//水位标志    Buffer inputBuffer_;//接收数据的缓冲区    Buffer outputBuffer_;//发送数据的缓冲区 ②TcpServer成员函数 //发送数据 void send(const std::string buf); void send(Buffer *buf); void shutdown();//关闭连接 void connectEstablished();//连接建立 void connectDestroyed(); //连接销毁 //各个回调函数给Channel设置的 handleRead handleWrite handleClose handleError Buffer类 8字节 包头存放要解析数据长度 |  可读缓冲区  | 可写缓冲区 kCheapPrepend 8          |          kInitialSize 1024 缓冲区对于非阻塞IO非常重要TCP编程中经常会出现粘包问题一般在通讯数据中加一个包头表示读取数据的大小每一次根据数据的长度来截取相应的包的大小。 Buffer类的成员变量     std::vectorchar buffer_     //vector数组 扩容方便    size_t readerIndex_;    //可读数据的下标位置    size_t writerIndex_;        //写数据的下标位置Buffer类的成员函数peek 返回缓冲区中可读数据的起始地址retrieve判断数据有没有一次性读完设置好两个数据位置 retrieveAllAsStringonMessage函数上报的Buffer数据转成string类型的数据返回 makeSpace扩容函数 readFd从fd上读取数据 底层是readv可以从fd上读取数据并可以按照一组散布缓冲区 (iovec 结构数组) 进行存储。 writeFd向fd上写数据 底层是writev可以将散布缓冲区的数据写到指定文件。 Logger异步日志 红黑树定时器 Echo服务器使用 我们需要做的是设置注册回调函数onConnection和onMessage 创建EventLoop loop主事件循环 创建InerAddress addr8000地址类 构建EchoServer类 包含TcpServer对象 server_ 包含EventLoop 文章借鉴 万字长文梳理Muduo库核心代码及优秀编程细节思想剖析 - 知乎 (zhihu.com)
http://www.zqtcl.cn/news/523176/

相关文章:

  • 郑州seo网站排名优化公司建站行业发展
  • 彭山住房和城乡建设局网站儒枫网网站建设
  • wap asp网站模板下载中企动力骗子公司
  • 中文电商网站模板洛阳网络公司排名
  • 国外毕业设计网站青岛seo服务
  • 自己做的网站怎么发布视频教程廊坊网站排名优化公司哪家好
  • 域名服务器都有了怎么做网站网站开发获取用户微信号登录
  • 淮南建设公司网站企业系统工程
  • 仓山福州网站建设佛山网站制作专业公司
  • 男男做的视频网站扬中网站建设案例
  • 做钓鱼网站用哪种编程语言代理网站备案
  • 广汉有没有做网站建设公司wordpress 301插件
  • 龙岗菠菜网站建设chatgpt网页
  • 如何查看网站ftp地址四川公共资源交易网招标网
  • 家居企业网站建设机构沈阳工程信息
  • 上海好的网站设计公司wordpress 上传文件路径
  • 用微信微博网站来做睡眠经济亚马逊跨境电商开店流程及费用
  • 网络公司做的网站根目录在哪网站建设必备条件
  • 网站建设外包服务管理情况公众号 链接wordpress
  • 深圳网站建设黄浦网络 技术差做网站的怎么跑业务
  • 青岛崂山区网站建设广东企业网站建设多少钱
  • 男女做那个的小视频网站韩国儿童才艺网站建设模板
  • 餐饮品牌网站建设淮北论坛最新招聘
  • 给客户做网站网站自动适应屏幕
  • 人力资源培训与开发什么是网站优化
  • 制作 网站 盈利农村自建房设计图一层平房
  • 佛山住房和城乡建设厅网站wordpress图片外链转内链
  • 海东高端网站建设价格wordpress侧边栏淘宝客
  • 网站功能建设中页面wordpress让投稿
  • 学校网站 asp网站结构方面主要做哪些优化