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 代码

 头文件

#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <iostream>
#include <functional>
#include <string>
using namespace std;
using namespace muduo;
using namespace muduo::net;
using namespace placeholders;

组合TcpServer对象

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

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

class ChatServer
{
public:
    ChatServer(EventLoop* loop,                 //事件循环——Reactor反应堆
            const InetAddress& listenAddr,      //IP和端口
            const string& nameArg)              //服务器的名字
              : _server(loop, listenAddr, nameArg), _loop(loop){}
private:
    TcpServer _server;
    EventLoop *_loop;       //epoll
};

输出ChatServer的构造函数

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

 ChatServer(EventLoop* loop,                 //事件循环——Reactor反应堆
            const InetAddress& listenAddr,      //IP和端口
            const string& nameArg)              //服务器的名字
               : _server(loop, listenAddr, nameArg), _loop(loop)
    {
        //给服务器注册用户连接的创建和断开回调
        _server.setConnectionCallback(std::bind(&ChatServer::OnConnection,this,_1));

        //给服务器注册用户读写事件回调
        _server.setMessageCallback(std::bind(&ChatServer::OnMessage,this,_1,_2,_3));

        //设置服务器的线程数量  1 I/O线程,3个worker线程
        _server.setThreadNum(4);
    }

开启时间循环函数

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

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

    //专门处理用户连接创建和断开    epoll
    void OnConnection(const TcpConnectionPtr&conn){
        if(conn->connected()){
            cout << conn->peerAddress().toIpPort() << "->"  << conn->localAddress().toIpPort() 
            <<  " state:online" << endl;
            }
        else{
            cout << conn->peerAddress().toIpPort() << "->"  << conn->localAddress().toIpPort() 
            <<  " state:offline" << endl;
            conn->shutdown();
        }
    }

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

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

main函数

int main(){

    EventLoop loop; //epoll
    InetAddress addr("127.0.0.1",6000);
    ChatServer server(&loop,addr,"ChatServer");
    server.start();         
    loop.loop();        //epoll_wait以阻塞方式等待新用户连接或读写事件等
    return 0;

}

全部代码:

/*muduo网络库给用户提供了两个主要的类
TcpServer:用于编写服务器程序的类
TcpClient:用于编写客户端程序的类

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

#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <iostream>
#include <functional>
#include <string>
using namespace std;
using namespace muduo;
using namespace muduo::net;
using namespace placeholders;


/*基于muduo网络库开发服务器程序
1.组合TcpServer对象
2.创建EventLoop事件循环对象的指针
3.明确TcpServer构造函数需要什么参数,输出ChatServer的构造函数
4.在当前服务器类的构造函数中,注册处理连接和读写事件的回调函数
5.设置合适的服务端线程数量,muduo会自动划分I/O线程和worker线程
*/
class ChatServer
{
public:
    ChatServer(EventLoop* loop,                 //事件循环——Reactor反应堆
            const InetAddress& listenAddr,      //IP和端口
            const string& nameArg)              //服务器的名字
               : _server(loop, listenAddr, nameArg), _loop(loop)
    {
        //给服务器注册用户连接的创建和断开回调
        _server.setConnectionCallback(std::bind(&ChatServer::OnConnection,this,_1));

        //给服务器注册用户读写事件回调
        _server.setMessageCallback(std::bind(&ChatServer::OnMessage,this,_1,_2,_3));

        //设置服务器的线程数量  1 I/O线程,3个worker线程
        _server.setThreadNum(4);
    }
    //开启事件循环
    void start(){
        _server.start();
    }


private:
    //专门处理用户连接创建和断开    epoll
    void OnConnection(const TcpConnectionPtr&conn){
        if(conn->connected()){
            cout << conn->peerAddress().toIpPort() << "->"  << conn->localAddress().toIpPort() 
            <<  " state:online" << endl;
            }
        else{
            cout << conn->peerAddress().toIpPort() << "->"  << conn->localAddress().toIpPort() 
            <<  " state:offline" << endl;
            conn->shutdown();
        }
    }
    //专门处理用户读写事件    
    void OnMessage(const TcpConnectionPtr&conn ,    //连接
                            Buffer*buffer,            //缓冲区
                            Timestamp time)          //接受到数据的时间信息
    {         
        string buf = buffer->retrieveAllAsString();
        cout << "recv data : " << buf << " time:" << time.toString() << endl;
        conn->send(buf);
    }

    TcpServer _server;
    EventLoop *_loop;       //epoll
};


int main(){

    EventLoop loop; //epoll
    InetAddress addr("127.0.0.1",6000);
    ChatServer server(&loop,addr,"ChatServer");
    server.start();         
    loop.loop();        //epoll_wait以阻塞方式等待新用户连接或读写事件等
    return 0;

}

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文件,分别写出编译选项、需要编译的源文件列表、可执行文件存储的路径、生成可执行文件、以及链接的库文件

cmake_minimum_required(VERSION 3.0)
project(main)

# 配置编译选项
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -g)  # 可调试可执行文件

#配置头文件搜索路径
# include_directories()

#配置库文件搜索路径
# link_directories()

# 设置需要编译的源文件列表
set(SRC_LIST ./muduo_server.cpp)
# 设置可执行文件存储的路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)


# 把.指定路径下的所有源文件放入SRC_LIST变量名中
# aux_source_directory(.SRC_LIST)

# 表示生成可执行文件server,由SRC_LIST变量定义的源文件而来
add_executable(server ${SRC_LIST})  # 生成可执行文件

#表示server这个目标程序,需要链接muduo_net muduo_base pthread库文件
target_link_libraries(server muduo_net muduo_base pthread)

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

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

  • 26
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于muduo开发集群聊天服务器c++源码+数据+使用说明.zip 基于muduo开发集群聊天服务器c++源码+数据+使用说明.zip 基于muduo开发集群聊天服务器c++源码+数据+使用说明.zip 【资源说明】 该项目是个人毕设项目源码,评审分达到95分,调试运行正常,确保可以运行!放心下载使用。 该项目资源主要针对计算机、自动化等相关专业的学生或从业者下载使用,也可作为期末课程设计、课程大作业、毕业设计等。 具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现类似其他功能。 在 Linux 环境下基于 muduo 开发集群聊天服务器实现新用户注册、用户登录、添加好友、添加群组、好友通信、群组聊天、保持离线消息等功能。 ## 项目特点 - 基于 muduo 网络开发网络核心模块,实现高效通信 - 使用第方 JSON 实现通信数据的序列化和反序列化 - 使用 Nginx 的 TCP 负载均衡功能,将客户端请求分派到多个服务器上,以提高并发处理能力 - 基于发布-订阅的服务器中间件redis消息队列,解决跨服务器通信难题 - 封装 MySQL 接口,将用户数据储存到磁盘中,实现数据持久化 - 基于 CMake 构建项目 ## 必要环境 - 安装`boost` - 安装`muduo` - 安装`Nginx` - 安装`redis` ## 构建项目 创建数据 ```shell # 连接MySQL mysql -u root -p your passward # 创建数据 create database chat; # 执行数据脚本创建表 source chat.sql ``` 执行脚本构建项目 ```shell bash build.sh ``` ## 执行生成文件 ```shell # 启动务端 cd ./bin ./ChatServer 6000 ``` ```shell # 启动客户端 ./ChatClient 127.0.0.1 8000 ``` ## 业务模块设计 ### 注册模块 我们从网络模块接收数据,根据 `MSGID` 定位到注册模块。从传递过来的 `json` 对象中获取用户 ID 和用户密码。并以此生成 `User` 对象,调用 model 层方法将新生成的 `User` 插入到数据中。 ### 登录模块 从 `json` 对象中获取用户ID和密码,并在数据中查询获取用户信息是否匹配。如果用户已经登录过,即 `state == "online"`,则返回错误信息。登录成功后需要在改务端的用户表中记录登录用户,并显示该用户的好友列表和收到的离线消息。 ### 客户端异常退出模块 如果客户端异常退出了,我们会从务端记录用户连接的表中找到该用户,如果它断连了就从此表中删除,并设置其状态为 `offline`。 ### 务端异常退出模块 如果务端异常退出,它会将所有在线的客户的状态都设置为 `offline`。即,让所有用户都下线。异常退出一般是 `CTRL + C` 时,我们需要捕捉信号。这里使用了 Linux 的信号处理函数,我们向信号注册回调函数,然后在函数内将所有用户置为下线状态。 ### 点对点聊天模块 通过传递的 `json` 查找对话用户 ID: - 用户处于登录状态:直接向该用户发送信息 - 用户处于离线状态:需存储离线消息 ### 添加好友模块 从 `json` 对象中获取添加登录用户 ID 和其想添加的好友的 ID,调用 model 层代码在 friend 表中插入好友信息。 ### 群组模块 创建群组需要描述群组名称,群组的描述,然后调用 model 层方法在数据中记录新群组信息。 加入群组需要给出用户 ID 和想要加入群组的 ID,其中会显示该用户是群组的普通成员还是创建者。 群组聊天给出群组 ID 和聊天信息,群内成员在线会直接接收到。 ## 使用Nginx负载均衡模块 ### 负载均衡是什么 假设一台机器支持两万的并发量,现在我们需要保证八万的并发量。首先想到的是升级服务器的配置,比如提高 CPU 执行频率,加大内存等提高机器的物理性能来解决此问题。但是单台机器的性能毕竟是有限的,而且也有着摩尔定律也日已失效。 这个时候我们就可以增加服务器的数量,将用户请求分发到不同的服务器上分担压力,这就是负载均衡。那我们就需要有一个第方组件充当负载均衡器,由它负责将不同的请求分发到不同的服务器上。而本项目,我们选择 `Nginx` 的负载均衡功能。
基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL 基于nginx tcp负载均衡 + redis的集群聊天服务器网络层使用muduo搭建,数据使用MySQL

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值