muduo库的介绍:一个基于reactor反应堆模型的多线程C++网络库。作者是陈硕大神。
muduo库是基于 boost 库开发的,所以需要在 Linux 平台上首先安装 boost 库。
1、boost 库安装
1、编译源码安装
第一种方法是编译源码安装,可以了解一下,不过比较麻烦:
- 1、准备好boost压缩包,我这里是boost_1_65_0.tar.gz
- 2、解压 tar -zxvf boost_1_65_0.tar.gz /usr/local
- 3、进入/usr/local/boost_1_65_0目录,执行./bootstrap.sh
- 4、执行./bjam
- 5、执行./b2
- 6、cp -rf boost /usr/include
- 7、cp -rf stage/lib/* /usr/lib
因为g++会自动从/usr/include和/usr/local/lib路径下寻找所需要的文件。所以把这两部分复制到其中,当然也可以用软连接或者其他方式,使得程序在运行时候找到动态库。
2、操作系统仓库安装
在现在比较新的 Centos 或者 Ubuntu中,可以直接用操作系统仓库中的去安装,以Centos为例
- yum install boost
- yum install boost-devel
- yum install boost-doc
这样就安装好了,然后可以进行测试,以下面代码为例,编译命令为
-
g++ b.cpp -g -o b -lboost_thread
#include <boost/thread/thread.hpp>
#include <iostream>
#include <cstdlib>
using namespace std;
volatile bool isRuning = true;
void func1(){
static int cnt1 = 0;
while(isRuning){
cout << "func1:" << cnt1++ << endl;
sleep(1);
}
}
void func2(){
static int cnt2 = 0;
while(isRuning){
cout << "\tfunc2:" << cnt2++ << endl;
sleep(2);
}
}
int main()
{
boost::thread thread1(&func1);
boost::thread thread2(&func2);
system("read");
isRuning = false;
thread2.join();
thread1.join();
cout << "exit" << endl;
return 0;
}
2、安装muduo库
需要 下载源码自己进行编译,步骤比较简单。
1、下载源代码,解压
root@tony:/home/tony/package# ls
muduo-master.zip
root@tony:/home/tony/package# unzip muduo-master.zip
2、进入解压缩文件,修改CMakeList.txt(可选)
root@tony:/home/tony/package# ls
muduo-master muduo-master.zip
root@:/home/tony/package# cd muduo-master
root@t:/home/tony/package/muduo-master# ls
BUILD.bazel ChangeLog2 contrib muduo WORKSPACE
build.sh CMakeLists.txt examples patches
ChangeLog compile_commands.json License README
此步骤可做可不做,就是修改CMakeLists.txt文件,
muduo库源码编译会编译很多unit_test测试用例代码,
编译耗时长,我们也用不到,
vim编辑上面源码目录里面的CMakeLists.txt文件,如下修改:
7 if(NOT CMAKE_BUILD_TYPE)
8 set(CMAKE_BUILD_TYPE "Release")
9 endif()
10
11 # only build examples if this is the main project
12 if(CMAKE_PROJECT_NAME STREQUAL "muduo")
13 # option(MUDUO_BUILD_EXAMPLES "Build Muduo examples" ON)
14 endif()
15
将13行 option(MUDUO_BUILD_EXAMPLES "Build Muduo examples" ON) 注释掉,保存并退出
3、编译,安装
有一个build.sh源码编译构建程序,运行该程序,muduo是用cmake来构建的,
需要先安装cmake,ubuntu下直接sudo apt install cmake就可以,
redhat或者centos可以从yum仓库直接安装。
进行编译。
root@tony:/home/tony/package/muduo-master# ./build.sh
编译完成后安装
root@tony:/home/tony/package/muduo-master# ./build.sh install
这个 ./build.sh install 实际上把muduo的头文件和lib库文件
放到了muduo-master同级目录下的build目录下
的release-install-cpp11文件夹下面了,可自行查看。
4、设置头文件库文件位置
上面的install命令并没有把它们拷贝到系统路径下,
导致我们每次编译程序都需要指定muduo库的头文件和库文件路径,
所以把inlcude(头文件)和lib(库文件)目录下的文件拷贝到系统目录下或者建立软链接。
root@tony:build/release-install-cpp11/include# mv muduo/ /usr/include/
root@tony:build/release-install-cpp11/include# cd ..
root@tony:build/release-install-cpp11# ls
include lib
root@:build/release-install-cpp11# cd lib/
root@tony:build/release-install-cpp11/lib# ls
libmuduo_base.a libmuduo_http.a libmuduo_inspect.a libmuduo_net.a
root@tony:build/release-install-cpp11/lib# mv * /usr/local/lib/
完成以后使用muduo库编写C++网络程序,不用在指定头文件和lib库文件路径信息了,
因为g++会自动从/usr/include和/usr/local/lib路径下寻找所需要的文件。
在测试之前,补充一个知识点:
运行由链接库生成的可执行文件时,必须确保程序运行时可以找到所有需要的链接库。常用的解决方案有如下几种:
- 将链接库文件移动到标准库目录下(例如 /usr/lib、/usr/lib64、/lib、/lib64),或者软链接
- 在终端输入
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx
,其中xxx
为动态链接库文件的绝对存储路径(此方式仅在当前终端有效,关闭终端后无效); - 修改
~/.bashrc
或~/.bash_profile
文件,即在文件最后一行添加export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx
(xxx
为动态库文件的绝对存储路径)。保存之后,执行source .bashrc
指令(此方式仅对当前登陆用户有效)
测试:
#include <muduo/net/TcpServer.h>
#include <muduo/base/Logging.h>
#include <boost/bind.hpp>
#include <muduo/net/EventLoop.h>
// 使用muduo开发回显服务器
class EchoServer
{
public:
EchoServer(muduo::net::EventLoop* loop,
const muduo::net::InetAddress& listenAddr);
void start();
private:
void onConnection(const muduo::net::TcpConnectionPtr& conn);
void onMessage(const muduo::net::TcpConnectionPtr& conn,
muduo::net::Buffer* buf,
muduo::Timestamp time);
muduo::net::TcpServer server_;
};
EchoServer::EchoServer(muduo::net::EventLoop* loop,
const muduo::net::InetAddress& listenAddr)
: server_(loop, listenAddr, "EchoServer")
{
server_.setConnectionCallback(
boost::bind(&EchoServer::onConnection, this, _1));
server_.setMessageCallback(
boost::bind(&EchoServer::onMessage, this, _1, _2, _3));
}
void EchoServer::start()
{
server_.start();
}
void EchoServer::onConnection(const muduo::net::TcpConnectionPtr& conn)
{
LOG_INFO << "EchoServer - " << conn->peerAddress().toIpPort() << " -> "
<< conn->localAddress().toIpPort() << " is "
<< (conn->connected() ? "UP" : "DOWN");
}
void EchoServer::onMessage(const muduo::net::TcpConnectionPtr& conn,
muduo::net::Buffer* buf,
muduo::Timestamp time)
{
// 接收到所有的消息,然后回显
muduo::string msg(buf->retrieveAllAsString());
LOG_INFO << conn->name() << " echo " << msg.size() << " bytes, "
<< "data received at " << time.toString();
conn->send(msg);
}
int main()
{
LOG_INFO << "pid = " << getpid();
muduo::net::EventLoop loop;
muduo::net::InetAddress listenAddr(8888);
EchoServer server(&loop, listenAddr);
server.start();
loop.loop();
}
使用g++进行编译,注意链接muduo和pthread的库文件,编译命令如下:
g++ main.cpp -lmuduo_net -lmuduo_base -lpthread -std=c++11
编译链接完成,生成a.out可执行程序,上面的echo服务器监听8888端口,运行上面的a.out回显服务器如下:
root@tony:/home/tony/code# ./a.out
20190404 08:00:15.254790Z 42660 INFO pid = 42660 - main.cpp:61
等待客户端连接,可以打开一个新的shell命令行用netcat命令模拟客户端连接echo服务器进行功能测试,命令如下:
tony@tony:~$ echo "hello world" | nc localhost 8888
hello world
客户端数据回显正确,看看服务器接日志信息打印如下:
root@tony:/home/tony/code# ./a.out
20190404 08:00:15.254790Z 42660 INFO pid = 42660 - main.cpp:61
20190404 08:00:59.438626Z 42660 INFO TcpServer::newConnection [EchoServer] - new connection [EchoServer-0.0.0.0:8888#1] from 127.0.0.1:33480 - TcpServer.cc:80
20190404 08:00:59.438707Z 42660 INFO EchoServer - 127.0.0.1:33480 -> 127.0.0.1:8888 is UP - main.cpp:42
20190404 08:00:59.438812Z 42660 INFO EchoServer-0.0.0.0:8888#1 echo 12 bytes, data received at 1554364859.438723 - main.cpp:53
到此,muduo安装成功。