当前位置:   article > 正文

C++项目——集群聊天服务器项目(三)muduo网络库

C++项目——集群聊天服务器项目(三)muduo网络库

今天来介绍集群聊天器项目中网络模块代码的核心模块——muduo网络库,一起来看看吧~

环境搭建C++项目——集群聊天服务器项目(一)项目介绍、环境搭建、Boost库安装、Muduo库安装、Linux与vscode配置-CSDN博客

Json第三方库C++项目——集群聊天服务器项目(二)Json第三方库-CSDN博客

一、muduo网络库介绍

muduo由陈硕大佬开发,是一个基于非阻塞IO和事件驱动的C++高并发TCP网络库

网络设计:reactors in threads - one loop per thread

one loop per thread指的是:

(1)一个线程只能有一个事件循环(EventLoop)

(2)一个文件描述符只能由一个线程进行读写,即一个TCP连接必须归属于某个EventLoop管理。

方案的特点是one loop per thread,有一个main reactor负载accept连接,然后把连接分发到某个sub reactor,该连接的所用操作都在那个sub reactor所处的线程中完成。

多个连接可能被分派到多个线程中,以充分利用CPU。

 Reactor poll的大小是固定的,根据CPU的数目确定。

原理:一个Base IO thread负责accept新的连接,接收到新的连接以后,使用轮询的方式在reactor pool中找到合适的sub reactor将这个连接挂载上去,这个连接上的所有任务都在这个sub reactor上完成。

如果有过多的耗费CPU I/O的计算任务,可以提交到创建的ThreadPool线程池中专门处理耗时的计算任务。

将epoll和线程池封装起来,好处是能够把网络的I/O代码与业务代码区分开

二、muduo网络库主要的类

TcpServer:用于编写服务器程序的类

TcpClient:用于编写客户端程序的类

接下来使用muduo网络库开发一个基本的服务器程序

三、基于muduo网络库开发服务器程序

3.1 基本步骤

1.组合TcpServer对象

2.创建EventLoop事件循环对象的指针

3.明确TcpServer构造函数需要什么参数,输出ChatServer的构造函数

4.在当前服务器类的构造函数中,注册处理连接和读写事件的回调函数

5.设置合适的服务端线程数量,muduo会自动划分I/O线程和worker线程

3.2 代码

 头文件

  1. #include <muduo/net/TcpServer.h>
  2. #include <muduo/net/EventLoop.h>
  3. #include <iostream>
  4. #include <functional>
  5. #include <string>
  6. using namespace std;
  7. using namespace muduo;
  8. using namespace muduo::net;
  9. using namespace placeholders;

组合TcpServer对象

创建EventLoop事件循环对象的指针

明确TcpServer构造函数需要什么参数

  1. class ChatServer
  2. {
  3. public:
  4. ChatServer(EventLoop* loop, //事件循环——Reactor反应堆
  5. const InetAddress& listenAddr, //IP和端口
  6. const string& nameArg) //服务器的名字
  7. : _server(loop, listenAddr, nameArg), _loop(loop){}
  8. private:
  9. TcpServer _server;
  10. EventLoop *_loop; //epoll
  11. };

输出ChatServer的构造函数

构造函数负责给服务器注册用户连接与断开回调函数,注册读写事件回调函数,并设置线程数量,muduo网络库会自动分配线程用于主reactor和子reactor

  1. ChatServer(EventLoop* loop, //事件循环——Reactor反应堆
  2. const InetAddress& listenAddr, //IP和端口
  3. const string& nameArg) //服务器的名字
  4. : _server(loop, listenAddr, nameArg), _loop(loop)
  5. {
  6. //给服务器注册用户连接的创建和断开回调
  7. _server.setConnectionCallback(std::bind(&ChatServer::OnConnection,this,_1));
  8. //给服务器注册用户读写事件回调
  9. _server.setMessageCallback(std::bind(&ChatServer::OnMessage,this,_1,_2,_3));
  10. //设置服务器的线程数量 1 I/O线程,3个worker线程
  11. _server.setThreadNum(4);
  12. }

开启时间循环函数

  1. //开启事件循环
  2. void start(){
  3. _server.start();
  4. }

连接与断开回调函数:显示上线和下线

  1. //专门处理用户连接创建和断开 epoll
  2. void OnConnection(const TcpConnectionPtr&conn){
  3. if(conn->connected()){
  4. cout << conn->peerAddress().toIpPort() << "->" << conn->localAddress().toIpPort()
  5. << " state:online" << endl;
  6. }
  7. else{
  8. cout << conn->peerAddress().toIpPort() << "->" << conn->localAddress().toIpPort()
  9. << " state:offline" << endl;
  10. conn->shutdown();
  11. }
  12. }

读写事件回调函数:这里的功能是将客户端发来的信息发回去

  1. //专门处理用户读写事件
  2. void OnMessage(const TcpConnectionPtr&conn , //连接
  3. Buffer*buffer, //缓冲区
  4. Timestamp time) //接受到数据的时间信息
  5. {
  6. string buf = buffer->retrieveAllAsString();
  7. cout << "recv data : " << buf << " time:" << time.toString() << endl;
  8. conn->send(buf);
  9. }

main函数

  1. int main(){
  2. EventLoop loop; //epoll
  3. InetAddress addr("127.0.0.1",6000);
  4. ChatServer server(&loop,addr,"ChatServer");
  5. server.start();
  6. loop.loop(); //epoll_wait以阻塞方式等待新用户连接或读写事件等
  7. return 0;
  8. }

全部代码:

  1. /*muduo网络库给用户提供了两个主要的类
  2. TcpServer:用于编写服务器程序的类
  3. TcpClient:用于编写客户端程序的类
  4. 将epoll和线程池封装起来,好处是能够把网络的I/O代码与业务代码区分开
  5. */
  6. #include <muduo/net/TcpServer.h>
  7. #include <muduo/net/EventLoop.h>
  8. #include <iostream>
  9. #include <functional>
  10. #include <string>
  11. using namespace std;
  12. using namespace muduo;
  13. using namespace muduo::net;
  14. using namespace placeholders;
  15. /*基于muduo网络库开发服务器程序
  16. 1.组合TcpServer对象
  17. 2.创建EventLoop事件循环对象的指针
  18. 3.明确TcpServer构造函数需要什么参数,输出ChatServer的构造函数
  19. 4.在当前服务器类的构造函数中,注册处理连接和读写事件的回调函数
  20. 5.设置合适的服务端线程数量,muduo会自动划分I/O线程和worker线程
  21. */
  22. class ChatServer
  23. {
  24. public:
  25. ChatServer(EventLoop* loop, //事件循环——Reactor反应堆
  26. const InetAddress& listenAddr, //IP和端口
  27. const string& nameArg) //服务器的名字
  28. : _server(loop, listenAddr, nameArg), _loop(loop)
  29. {
  30. //给服务器注册用户连接的创建和断开回调
  31. _server.setConnectionCallback(std::bind(&ChatServer::OnConnection,this,_1));
  32. //给服务器注册用户读写事件回调
  33. _server.setMessageCallback(std::bind(&ChatServer::OnMessage,this,_1,_2,_3));
  34. //设置服务器的线程数量 1 I/O线程,3个worker线程
  35. _server.setThreadNum(4);
  36. }
  37. //开启事件循环
  38. void start(){
  39. _server.start();
  40. }
  41. private:
  42. //专门处理用户连接创建和断开 epoll
  43. void OnConnection(const TcpConnectionPtr&conn){
  44. if(conn->connected()){
  45. cout << conn->peerAddress().toIpPort() << "->" << conn->localAddress().toIpPort()
  46. << " state:online" << endl;
  47. }
  48. else{
  49. cout << conn->peerAddress().toIpPort() << "->" << conn->localAddress().toIpPort()
  50. << " state:offline" << endl;
  51. conn->shutdown();
  52. }
  53. }
  54. //专门处理用户读写事件
  55. void OnMessage(const TcpConnectionPtr&conn , //连接
  56. Buffer*buffer, //缓冲区
  57. Timestamp time) //接受到数据的时间信息
  58. {
  59. string buf = buffer->retrieveAllAsString();
  60. cout << "recv data : " << buf << " time:" << time.toString() << endl;
  61. conn->send(buf);
  62. }
  63. TcpServer _server;
  64. EventLoop *_loop; //epoll
  65. };
  66. int main(){
  67. EventLoop loop; //epoll
  68. InetAddress addr("127.0.0.1",6000);
  69. ChatServer server(&loop,addr,"ChatServer");
  70. server.start();
  71. loop.loop(); //epoll_wait以阻塞方式等待新用户连接或读写事件等
  72. return 0;
  73. }

3.3 服务器程序执行

3.3.1 g++编译

g++ -o server muduo_server.cpp -lmuduo_net -lmuduo_base -lpthread

终端输入上述语句,其中,g++ -I头文件搜索路径 -L库文件搜素路径 -l库名称,执行server文件,结果如下:

可以看到客户端登录成功后,信息成功回显!

telnet 127.0.0.1 6000

3.3.2 CMake编译

可以查看Linux环境下是否有CMake,有muduo库其实就已经有CMake了,通过下面的命令查看版本号

cmake -version

在3.2文件的同级目录下,创建CMakeLists.txt文件,分别写出编译选项、需要编译的源文件列表、可执行文件存储的路径、生成可执行文件、以及链接的库文件

  1. cmake_minimum_required(VERSION 3.0)
  2. project(main)
  3. # 配置编译选项
  4. set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -g) # 可调试可执行文件
  5. #配置头文件搜索路径
  6. # include_directories()
  7. #配置库文件搜索路径
  8. # link_directories()
  9. # 设置需要编译的源文件列表
  10. set(SRC_LIST ./muduo_server.cpp)
  11. # 设置可执行文件存储的路径
  12. set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
  13. # 把.指定路径下的所有源文件放入SRC_LIST变量名中
  14. # aux_source_directory(.SRC_LIST)
  15. # 表示生成可执行文件server,由SRC_LIST变量定义的源文件而来
  16. add_executable(server ${SRC_LIST}) # 生成可执行文件
  17. #表示server这个目标程序,需要链接muduo_net muduo_base pthread库文件
  18. target_link_libraries(server muduo_net muduo_base pthread)

可以看到,这里将可执行文件放在了项目文件的bin文件夹下,执行server文件同样回显相同的结果

至此,muduo网络库的示例代码与实验完毕,期待后续项目的更新把~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/332624
推荐阅读
相关标签
  

闽ICP备14008679号