muduo库安装及使用

本文介绍了如何在Linux环境下安装和配置Boost库,以及如何使用Muduo库进行网络编程,重点讲解了EventLoop、TcpConnection等关键类的使用和回调函数的设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.muduo库环境

安装muduo库参考了:C++ muduo网络库知识分享01 - Linux平台下muduo网络库源码编译安装_https://blog.csdn.net/qiangweiyuan/article/details_大秦坑王的博客-CSDN博客

1.1 安装boost库

boost安装
官网下载安装包,可以根据需求选择版本,
二、Linux下boost编译安装
1、解压下载好的boost压缩包
tar -zxvf boost_1_73_0.tar.gz
2、进入解压后boost目录
cd boost_1_73_0
3、运行bootstrap.sh生成boost的编译工具b2
./bootstrap.sh --with-libraries=all --with-toolset=gcc
4、编译
./b2 toolset=gcc
5、安装

sudo
./b2 install 

1.2 muduo安装

muduo库源码github仓库地址
1.拷贝muduo的源码压缩包muduo-master.zip到Linux系统并解压
解压完成后,进入muduo库的解压目录里面
在这里插入图片描述
在这里插入图片描述
2.运行build.sh进行编译
./build.sh
3.编译完成后,在输入./build.sh install命令进行muduo库安装
./build.sh install
这个./build.sh install实际上把muduo的头文件和lib库文件放到了muduo-master同级目录下的build目录下的release-install-cpp11文件夹下面了:
在这里插入图片描述
我们每次编译程序都需要指定muduo库的头文件和库文件路径,很麻烦,所以我们选择直接把inlcude(头文件)和lib(库文件)目录下的文件拷贝到系统目录下:

cd ../build
cd include
mv muduo/ /usr/include/
cd ..
cd lib/
mv * /usr/local/lib/

二.Muduo 的使用场景

muduo库的介绍就是:一个基于reactor反应堆模型的多线程C++网络库。
Muduo 的设计目标是用于开发公司内部的分布式程序。 换句话说, 它是用来写专用的 Sudoku server 或者游戏服务器, 不是用来写通用的 httpd 或 ftpd 或 wwwproxy。 前者通常有业务逻辑, 后者更强调高并发与高吞吐。

三.用户如何使用muduo

陈硕大佬认为:Tcp网络编程的本质——基于事件的非阻塞网络编程是编写高性能并发网络服务程序的主流模式,头一次使用这种方式编程通常需要转换思维方式。把原来“主动调用recv来接收数据、主动调用accept来接受新连、主动调用send来发送数据”的思路换成——”注册一个收数据的回调,网络库收到数据会调用我,直接把数据提供给我,供我消费注册一个接受连接的回调,网络库接受了新连接会回调我,直接把新的连接对象传给我,供我使用需要发送数据的时候,只管往连接中写,网络库会负责无阻塞地发送。”这种编程方式有点像Win32的消息循环,消息循环中的代码应该避免阻塞,否则会让整个窗口失去响应,同理,事件处理函数也应该避免阻塞,否则会让网络服务失去响应。
认为,TCP网络编程最本质的是处理三个半事件:

  1. 连接的建立,包括服务端接受( accept)新连接和客户端成功发起( connect )连接。TCP连接一旦建立,客户端和服务端是平等的,可以各自收发数据。
  2. 连接的断开,包括主动断开( close、shutdown )和被动断开(read(2)返回0)。
  3. 消息到达,文件描述符可读。这是最为重要的一个事件,对它的处理方式决定了网络编程的风格(阻塞还是非阻塞,如何处理分包,应用层的缓冲如何设计,等等)。
    3.5 消息发送完毕,这算半个。对于低流量的服务,可以不必关心这个事件;另外,这里的“发送完毕”是指将数据写入操作系统的缓冲区,将由TCP协议栈负责数据的发送与重传,不代表对方已经收到数据。

总结:用户只从简单使用角度出发可以只关注Tcpserver、EventLoop、TcpConnection、Buffer这几个类,使用时自己需要创建好一个主线程的EventLoop、TcpServer、指定开启的子线程数量
设置TcpServer回调函数的接口(对应了三个半事件后的回调):

  /// Set connection callback.
  /// Not thread safe.
void setConnectionCallback(const ConnectionCallback& cb)
  { connectionCallback_ = cb; }
  /// Set message callback.
  /// Not thread safe.
void setMessageCallback(const MessageCallback& cb)
  { messageCallback_ = cb; }
  /// Set write complete callback.
  /// Not thread safe.
void setWriteCompleteCallback(const WriteCompleteCallback& cb)
  { writeCompleteCallback_ = cb; }

使用在场景中的一个demo

  EventLoop loop;
  InetAddress listenAddr(2000, false, ipv6);
  TcpServer server(loop,listenAddr, "DemoServer");
    //设置子线程数
  server->setThreadNum(5);
    //自定义新连接、可读事件、发送完成的回调函数(三个半事件)
  server->setConnectionCallback(std::bind(.....));
  server->setMessageCallback(std::bind(.....));
  server->setWriteCompleteCallback(std::bind(.....));

且传入的回调函数的参数、返回值需参考如下设定

  typedef std::function<void (const TcpConnectionPtr&)> ConnectionCallback;
  typedef std::function<void (const TcpConnectionPtr&)> WriteCompleteCallback;    
  typedef std::function<void (const TcpConnectionPtr&,Buffer*,Timestamp)> MessageCallback;                                   

参数TcpConnectionPtr参数是收到数据的那个TCP连接;
在 MessageCallback()函数中,Buffer是已经收到的数据,Buffer的数据会累积,直到用户从中取走( retrieve)数据。注意Buffer是指针,表明用户代码可以修改(消费)Buffer; Timestamp是收到数据的确切时间,即epoll_wait(2)返回的时间,注意这个时间通常比read(2)发生的时间略早,可以用于正确测量程序的消息处理延迟。另外,Timestamp对象采用pass-by-value,而不是pass-by-(const)reference,这是有意的,因为在x86-64上可以直接通过寄存器传参。
样例回显服务器代码:

#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/base/Logging.h>
#include <string>
#include <functional>
#include <iostream>
using namespace std;
using namespace muduo;
using namespace muduo::net;
class EchoServer
{
public:
    EchoServer(EventLoop* loop,
            const InetAddress &addr, 
            const std::string &name)
        :server_(loop,addr,name)
        ,loop_(loop)
    {
        //注册回调
        server_.setConnectionCallback(std::bind(&EchoServer::OnConnect, this,std::placeholders::_1));
        server_.setMessageCallback(std::bind(&EchoServer::OnMessage, this,
        std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
    }
    void start()
    {
        server_.start();
    }
private:
    void OnMessage(const TcpConnectionPtr& conn,Buffer* buff ,Timestamp time)                   
    {
        std::string str=buff->retrieveAllAsString();
        conn->send(str);
        conn->shutdown(); // 写端   EPOLLHUP =》 closeCallback_
    }
    void OnConnect(const TcpConnectionPtr& conn)
    {
        if(conn->connected())
        {
            std::cout << conn->peerAddress().toIpPort() << " -> " << conn->localAddress().toIpPort() << "state:online" << endl;
        }
        else 
        {
            std::cout << conn->peerAddress().toIpPort() << " -> " << conn->localAddress().toIpPort() << "state:offline" << endl;
            conn->shutdown(); //连接断开将socket资源释放
            //或者调用_loop->quit()退出epoll;
        }
    }
    EventLoop *loop_;
    TcpServer server_;

};
int main()
{
    EventLoop loop;
    InetAddress addr("127.0.0.1", 8080);
    EchoServer server(&loop,addr,"EchoServer");
    server.start();
    loop.loop();
    return 0;
}

编译:g++ -o test test.cpp -lmuduo_net -lmuduo_base -lpthread
开一个新连接进行测试
telnet 127.0.0.1 8080
服务器显示
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值