linux muduo 编译安装,muduo记录

article/2025/11/6 18:54:28

1.muduo编译安装

编译muduo遇见的报错可以在github上的issue上面查找。一般都能顺利解决,我遇到的就是没有安装boost-dev.

centos7系统 执行: sudo yum install boost-dev

bVbfss9?w=676&h=589

2.截取流程图

图片截取自《Linux多线程服务端编程:使用muduo C++网络库》

bVbfsuH?w=692&h=427

bVbfswZ?w=710&h=502

bVbfsxs?w=656&h=480

3.源码摘录

摘录一个examples里面的pingpong为例

server.cc 设置回调,开启服务

void onConnection(const TcpConnectionPtr& conn)

{

if (conn->connected())

{

conn->setTcpNoDelay(true);

}

}

void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp)

{

conn->send(buf);

}

int main(int argc, char* argv[])

{

if (argc < 4)

{

fprintf(stderr, "Usage: server

\n");

}

else

{

LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid();

Logger::setLogLevel(Logger::WARN);

const char* ip = argv[1];

uint16_t port = static_cast(atoi(argv[2]));

InetAddress listenAddr(ip, port);

int threadCount = atoi(argv[3]);

EventLoop loop;

TcpServer server(&loop, listenAddr, "PingPong");

server.setConnectionCallback(onConnection);

server.setMessageCallback(onMessage);

if (threadCount > 1)

{

server.setThreadNum(threadCount);

}

server.start();

loop.loop();

}

}

main函数中新建TcpServer 对象,TcpServer构造函数会新建Acceptor对象。Acceptor构造函数中定义了channel对象。channel中包含EventLoop。EventLoop里面根据poller来获取各种事件。

代码可以从main入手,从下往上看。这里便于理清原理,倒叙表达

1.poller 2种模式之epoll

fillActiveChannels(numEvents, activeChannels);

channel->set_revents(events_[i].events);

EPollPoller::EPollPoller(EventLoop* loop)

: Poller(loop),

epollfd_(::epoll_create1(EPOLL_CLOEXEC)),

events_(kInitEventListSize)

{

if (epollfd_ < 0)

{

LOG_SYSFATAL << "EPollPoller::EPollPoller";

}

}

EPollPoller::~EPollPoller()

{

::close(epollfd_);

}

Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels)

{

LOG_TRACE << "fd total count " << channels_.size();

int numEvents = ::epoll_wait(epollfd_,

&*events_.begin(),

static_cast(events_.size()),

timeoutMs);

int savedErrno = errno;

Timestamp now(Timestamp::now());

if (numEvents > 0)

{

LOG_TRACE << numEvents << " events happened";

fillActiveChannels(numEvents, activeChannels);

if (implicit_cast(numEvents) == events_.size())

{

events_.resize(events_.size()*2);

}

}

else if (numEvents == 0)

{

LOG_TRACE << "nothing happened";

}

else

{

// error happens, log uncommon ones

if (savedErrno != EINTR)

{

errno = savedErrno;

LOG_SYSERR << "EPollPoller::poll()";

}

}

return now;

}

Poller* Poller::newDefaultPoller(EventLoop* loop)

{

if (::getenv("MUDUO_USE_POLL"))

{

return new PollPoller(loop);

}

else

{

return new EPollPoller(loop);

}

}

void EPollPoller::fillActiveChannels(int numEvents,

ChannelList* activeChannels) const

{

assert(implicit_cast(numEvents) <= events_.size());

for (int i = 0; i < numEvents; ++i)

{

Channel* channel = static_cast(events_[i].data.ptr);

#ifndef NDEBUG

int fd = channel->fd();

ChannelMap::const_iterator it = channels_.find(fd);

assert(it != channels_.end());

assert(it->second == channel);

#endif

channel->set_revents(events_[i].events);

activeChannels->push_back(channel);

}

}

2.EventLoop 获取各种事件

poller_(Poller::newDefaultPoller(this))

pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);

currentActiveChannel_->handleEvent(pollReturnTime_);

EventLoop::EventLoop()

: looping_(false),

quit_(false),

eventHandling_(false),

callingPendingFunctors_(false),

iteration_(0),

threadId_(CurrentThread::tid()),

poller_(Poller::newDefaultPoller(this)),

timerQueue_(new TimerQueue(this)),

wakeupFd_(createEventfd()),

wakeupChannel_(new Channel(this, wakeupFd_)),

currentActiveChannel_(NULL)

{

LOG_DEBUG << "EventLoop created " << this << " in thread " << threadId_;

if (t_loopInThisThread)

{

LOG_FATAL << "Another EventLoop " << t_loopInThisThread

<< " exists in this thread " << threadId_;

}

else

{

t_loopInThisThread = this;

}

wakeupChannel_->setReadCallback(

boost::bind(&EventLoop::handleRead, this));

// we are always reading the wakeupfd

wakeupChannel_->enableReading();

}

void EventLoop::loop()

{

assert(!looping_);

assertInLoopThread();

looping_ = true;

quit_ = false; // FIXME: what if someone calls quit() before loop() ?

LOG_TRACE << "EventLoop " << this << " start looping";

while (!quit_)

{

activeChannels_.clear();

pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);

++iteration_;

if (Logger::logLevel() <= Logger::TRACE)

{

printActiveChannels();

}

// TODO sort channel by priority

eventHandling_ = true;

for (ChannelList::iterator it = activeChannels_.begin();

it != activeChannels_.end(); ++it)

{

currentActiveChannel_ = *it;

currentActiveChannel_->handleEvent(pollReturnTime_);

}

currentActiveChannel_ = NULL;

eventHandling_ = false;

doPendingFunctors();

}

LOG_TRACE << "EventLoop " << this << " stop looping";

looping_ = false;

}

3.channel 分发事件根据EventLoop

revents_ 在epoll中已经设置

void Channel::handleEvent(Timestamp receiveTime)

{

boost::shared_ptr guard;

if (tied_)

{

guard = tie_.lock();

if (guard)

{

handleEventWithGuard(receiveTime);

}

}

else

{

handleEventWithGuard(receiveTime);

}

}

void Channel::handleEventWithGuard(Timestamp receiveTime)

{

eventHandling_ = true;

LOG_TRACE << reventsToString();

if ((revents_ & POLLHUP) && !(revents_ & POLLIN))

{

if (logHup_)

{

LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP";

}

if (closeCallback_) closeCallback_();

}

if (revents_ & POLLNVAL)

{

LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL";

}

if (revents_ & (POLLERR | POLLNVAL))

{

if (errorCallback_) errorCallback_();

}

if (revents_ & (POLLIN | POLLPRI | POLLRDHUP))

{

if (readCallback_) readCallback_(receiveTime);

}

if (revents_ & POLLOUT)

{

if (writeCallback_) writeCallback_();

}

eventHandling_ = false;

}

4.Acceptor

loop_(loop),

acceptChannel_(loop, acceptSocket_.fd()),

acceptChannel_.setReadCallback(boost::bind(&Acceptor::handleRead, this));

Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport)

: loop_(loop),

acceptSocket_(sockets::createNonblockingOrDie(listenAddr.family())),

acceptChannel_(loop, acceptSocket_.fd()),

listenning_(false),

idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC))

{

assert(idleFd_ >= 0);

acceptSocket_.setReuseAddr(true);

acceptSocket_.setReusePort(reuseport);

acceptSocket_.bindAddress(listenAddr);

acceptChannel_.setReadCallback(

boost::bind(&Acceptor::handleRead, this));

}

void Acceptor::handleRead()

{

loop_->assertInLoopThread();

InetAddress peerAddr;

//FIXME loop until no more

int connfd = acceptSocket_.accept(&peerAddr);

if (connfd >= 0)

{

// string hostport = peerAddr.toIpPort();

// LOG_TRACE << "Accepts of " << hostport;

if (newConnectionCallback_)

{

newConnectionCallback_(connfd, peerAddr);

}

else

{

sockets::close(connfd);

}

}

else

{

LOG_SYSERR << "in Acceptor::handleRead";

// Read the section named "The special problem of

// accept()ing when you can't" in libev's doc.

// By Marc Lehmann, author of libev.

if (errno == EMFILE)

{

::close(idleFd_);

idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL);

::close(idleFd_);

idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);

}

}

}

5.TcpServer

acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)),

ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn));

tcpserver 在得到⌈ 新连接newConnection以后,会新建一个 TcpConnection ⌋来处理后续协议报文的发送接收

TcpServer::TcpServer(EventLoop* loop,

const InetAddress& listenAddr,

const string& nameArg,

Option option)

: loop_(CHECK_NOTNULL(loop)),

ipPort_(listenAddr.toIpPort()),

name_(nameArg),

acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)),

threadPool_(new EventLoopThreadPool(loop, name_)),

connectionCallback_(defaultConnectionCallback),

messageCallback_(defaultMessageCallback),

nextConnId_(1)

{

acceptor_->setNewConnectionCallback(

boost::bind(&TcpServer::newConnection, this, _1, _2));

}

void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)

{

loop_->assertInLoopThread();

EventLoop* ioLoop = threadPool_->getNextLoop();

char buf[64];

snprintf(buf, sizeof buf, "-%s#%d", ipPort_.c_str(), nextConnId_);

++nextConnId_;

string connName = name_ + buf;

LOG_INFO << "TcpServer::newConnection [" << name_

<< "] - new connection [" << connName

<< "] from " << peerAddr.toIpPort();

InetAddress localAddr(sockets::getLocalAddr(sockfd));

// FIXME poll with zero timeout to double confirm the new connection

// FIXME use make_shared if necessary

TcpConnectionPtr conn(new TcpConnection(ioLoop,

connName,

sockfd,

localAddr,

peerAddr));

connections_[connName] = conn;

conn->setConnectionCallback(connectionCallback_);

conn->setMessageCallback(messageCallback_);

conn->setWriteCompleteCallback(writeCompleteCallback_);

conn->setCloseCallback(

boost::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe

ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn));

}

void TcpServer::start()

{

if (started_.getAndSet(1) == 0)

{

threadPool_->start(threadInitCallback_);

assert(!acceptor_->listenning());

loop_->runInLoop(

boost::bind(&Acceptor::listen, get_pointer(acceptor_)));

}

}

6.TcpConnection

注册各种IO事件

TcpConnection::TcpConnection(EventLoop* loop,

const string& nameArg,

int sockfd,

const InetAddress& localAddr,

const InetAddress& peerAddr)

: loop_(CHECK_NOTNULL(loop)),

name_(nameArg),

state_(kConnecting),

reading_(true),

socket_(new Socket(sockfd)),

channel_(new Channel(loop, sockfd)),

localAddr_(localAddr),

peerAddr_(peerAddr),

highWaterMark_(64*1024*1024)

{

channel_->setReadCallback(

boost::bind(&TcpConnection::handleRead, this, _1));

channel_->setWriteCallback(

boost::bind(&TcpConnection::handleWrite, this));

channel_->setCloseCallback(

boost::bind(&TcpConnection::handleClose, this));

channel_->setErrorCallback(

boost::bind(&TcpConnection::handleError, this));

LOG_DEBUG << "TcpConnection::ctor[" << name_ << "] at " << this

<< " fd=" << sockfd;

socket_->setKeepAlive(true);

}

7.main使用

EventLoop loop;

TcpServer server(&loop, listenAddr, "PingPong");

server.start();

loop.loop();

void onConnection(const TcpConnectionPtr& conn)

{

if (conn->connected())

{

conn->setTcpNoDelay(true);

}

}

void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp)

{

conn->send(buf);

}

int main(int argc, char* argv[])

{

if (argc < 4)

{

fprintf(stderr, "Usage: server

\n");

}

else

{

LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid();

Logger::setLogLevel(Logger::WARN);

const char* ip = argv[1];

uint16_t port = static_cast(atoi(argv[2]));

InetAddress listenAddr(ip, port);

int threadCount = atoi(argv[3]);

EventLoop loop;

TcpServer server(&loop, listenAddr, "PingPong");

server.setConnectionCallback(onConnection);

server.setMessageCallback(onMessage);

if (threadCount > 1)

{

server.setThreadNum(threadCount);

}

server.start();

loop.loop();

}

}


http://chatgpt.dhexx.cn/article/5G7UYlkZ.shtml

相关文章

muduo源码分析之TcpServer模块

这次我们开始muduo源代码的实际编写&#xff0c;首先我们知道muduo是LT模式&#xff0c;Reactor模式&#xff0c;下图为Reactor模式的流程图[来源1] 然后我们来看下muduo的整体架构[来源1] 首先muduo有一个主反应堆mainReactor以及几个子反应堆subReactor&#xff0c;其中子反应…

muduo网络库学习(1)

muduo网络库学习&#xff08;1&#xff09; 文章目录 muduo网络库学习&#xff08;1&#xff09;前言一、muduo是什么&#xff1f;二、代码结构1.base库2.net库3.附属库 二、网络库结构总结 前言 本章节主要介绍muduo网络库的整体架构&#xff01;一、muduo是什么&#xff1f;…

muduo

muduo 概述 muduo是基于Reactor模式的网络库&#xff0c;用于响应计时器和IO事件。 muduo采用基于对象而非面向对象的设计风格&#xff0c;其事件回调采用functionbind&#xff0c;用户在使用muduo的时候不需要继承其中的class 架构 Multiple Reactor Reactor模式&#xff1a…

muduo日志库原理以及源码分析

muduo日志库特点 日志批量写入批量唤醒写线程写日志用notifywait_timeout 方式触发日志的写入锁的粒度&#xff0c;双缓冲&#xff0c;双队列buffer默认 4M 缓冲区&#xff0c; buffers 是 buffer 队列&#xff0c; push 、 pop 时使用 move 语义 减少内存拷贝 muduo的这些特点…

muduo网络库与服务模型介绍

目录 一、muduo网络库简介 1、特点 2、代码结构 &#xff08;1&#xff09;公共接口 &#xff08;2&#xff09;内部实现 二、muduo线程模型 1、单线程Reactor 2、Reactor线程池 3、one loop per thread 4、one loop per thread 线程池 muduo是陈硕个人使用C开发的一…

muduo 架构解析

muduo是一个基于Reactor模式的C网络库。它采用非阻塞I/O模型&#xff0c;基于事件驱动和回调。我们不仅可以通过muduo来学习linux服务端多线程编程&#xff0c;还可以通过它来学习C11。     Reactor是网络编程的一般范式。我们这里从reactor模式为出发点&#xff0c;根据R…

muduo库介绍

muduo库是一个多线程服务器开发库 muduo 作者陈硕&#xff0c;现在在美国加州硅谷某互联网大公司工作&#xff0c;从事大规模分布式的可靠系统工程。这个库是作者多年工作的总结&#xff0c;可以说大家学通了这个库&#xff0c;找一份Linux服务器开发的工作是没问题的&#xf…

C++ muduo网络库知识分享01 - Linux平台下muduo网络库源码编译安装

Muduo is a multithreaded C network library based on the reactor pattern. muduo库的介绍就是&#xff1a;一个基于reactor反应堆模型的多线程C网络库。 muduo网络库是C语言开发的一个非常优秀的网络库&#xff0c;作者陈硕&#xff0c;muduo网络库在多线程环境下性能非常高…

遗传算法示例

遗传的概念&#xff1a; 遗传算法是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型&#xff0c;是一种通过模拟自然进化过程搜索最优解的方法。 遗传算法的特点&#xff1a; 对于搜索算法的共同特征有 首先组成一组候选解。依据某些使用性条件测算这些…

10分钟搞懂遗传算法

大自然有种神奇的力量&#xff0c;它能够将优良的基因保留下来&#xff0c;从而进化出更加强大、更加适合生存的基因。遗传算法便基于达尔文的进化论&#xff0c;模拟了自然选择&#xff0c;物竞天择、适者生存&#xff0c;通过N代的遗传、变异、交叉、复制&#xff0c;进化出问…

遗传算法简单实例

遗传算法的手工模拟计算示例 为更好地理解遗传算法的运算过程&#xff0c;下面用手工计算来简单地模拟遗传算法的各 个主要执行步骤。 例&#xff1a;求下述二元函数的最大值&#xff1a; (1) 个体编码 遗传算法的运算对象是表示个体的符号串&#xff0…

遗传算法(基础知识)

遗传算法&#xff08;基础知识&#xff09; 遗传算法简称GA&#xff08;Genetic Algorithms&#xff09;模拟自然界生物遗传学&#xff08;孟德尔&#xff09;和生物进化论&#xff08;达尔文&#xff09;通过人工方式所构造的一类 并行随机搜索最优化方法&#xff0c;是对生物…

遗传算法概念、步骤、应用解析(案例直白--黄含驰)

遗传算法 ①  在几十亿年的演化过程中&#xff0c;自然界中的生物体已经 形成了一种优化自身结构的内在机制&#xff0c;它们能够不 断地从环境中学习&#xff0c;以适应不断变化的环境  对于大多数生物体&#xff0c;这个过程是通过自然选择和有性生殖来完成的。自然选择…

遗传算法超详细图解

遗传算法&#xff08;Genetic Algorithm&#xff09;顾名思义&#xff0c;是一种基于自然选择原理和自然遗传机制的启发式搜索算法。该算法通过模拟自然界中生物遗传进化的自然机制&#xff08;选择、交叉和变异操作&#xff09;&#xff0c;将好的遗传基因&#xff08;最优目标…

遗传算法及其应用

一、遗传算法的定义 遗传算法的基本思想是参考生物学中物种“物竞天择&#xff0c;适者生存”的思想。在计算机中&#xff0c;通过给定约束条件&#xff0c;使初始参数不断迭代&#xff0c;从而接近最优解。 遗传算法可描述为&#xff1a; Initialize population process-chr…

详解遗传算法(含MATLAB代码)

目录 一、遗传算法概述 二、遗传算法的特点和应用 三、遗传算法的基本流程及实现技术 3.1 遗传算法的基本流程 3.2 遗传算法的实现技术 1.编码 2.适应度函数 3.选择算子 4.交叉算子 5.变异算子 6.运行参数 四、遗传算法的基本原理 4.1 模式定理 4.2 积木块假设 …

遗传算法步骤

遗传算法是一种模拟生物自然进化的一种算法&#xff0c;通话对生物进化的模拟&#xff0c;实现对数值函数的模拟计算。它主要分为四个步骤&#xff1a;初始化、杂交、变异和选择。相关实现可参考https://github.com/ShaquallLee/evolutionary-programming/tree/master/aEP 1、…

遗传算法原理+程序案例详解

注明&#xff1a;这篇遗传算法程序我在网上看到多次&#xff0c;很多人在转载时&#xff0c;都称已经修改了错误的地方&#xff0c;程序在matlab上能够运行。 当我在学习这段程序时&#xff0c;发现结果仍存在很大问题(不稳定、不准确)。我一行一行看时&#xff0c;发现不仅有少…

遗传算法、遗传算法库函数ga和gamultiobj、遗传算法工具箱GOT实例介绍

目录 前言 适应度函数和目标函数的关系 1. 常规遗传算法 2.结合非线性规划fmincon函数的遗传算法 2.1 fmincon非线性规划函数使用 2.2 结合非线性规划fmincon函数的遗传算法使用及示例 2.2.1 编码 2.2.2 选择 2.2.3交叉 2.2.4变异 2.2.5非线性规划fmincon函数 2.2.…

遗传算法原理与应用详解

遗传算法 ( GA , Genetic Algorithm ) &#xff0c;也称进化算法 。 遗传算法是受达尔文的进化论的启发&#xff0c;借鉴生物进化过程而提出的一种启发式搜索算法。因此在介绍遗传算法前有必要简单的介绍生物进化知识。 一.进化论知识 作为遗传算法生物背景的介绍&#xff0…