muduo网络库介绍

news2024/11/18 7:24:38

文章目录

    • Muduo
      • Server常见接口
        • TcpServer类
        • EventLoop类
        • TcpConnection类
      • 服务器搭建
      • Client常见接口
        • TcpClient类
      • 客户端搭建

Muduo

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

这是一个基于主从Reactor模型的网络编程库,线程模型是one loop per thread

意思是一个线程只能有一个事件循环(event loop), 用于响应计时器和事件

一个文件描述符只能由一个线程进行读写,也就是一个Tcp连接,必须归属于一个EventLoop管理

基本逻辑是这样的

image.png

所谓的主从Reactor就是,在主线程中有一个主Reactor进行事件触发,而在其他其他线程中就是普通的Reactor进行事件触发

在主线程中主要任务就是监控新连接的到来,保证尽可能高效的获取新建连接,再按照负载均衡的方式分发到普通Reactor的线程中,对对应的IO事件进行监控

主从Reactor必然是一个多执行流的并发模式,也就是one thread one loop

Server常见接口

TcpServer类

这个类用来生成服务器对象

构造函数是这样的

TcpServer(EventLoop *loop,
          const InetAddress &listenAddr,
          const string &nameArg,
          Option option = kNoReusePort);

第一个参数loop对象在下面来介绍

第二个参数是一个地址信息,结构是这样的

class InetAddress : public muduo::copyable
{
public:
    InetAddress(StringArg ip, uint16_t port, bool ipv6 = false);
};

包含了ip和端口两个信息,是服务器需要监听和绑定的地址

第三个参数是字符串的名称

最后一个参数是一个选项,是否启用端口重用的功能

enum Option
{
    kNoReusePort,
    kReusePort,
};

我们直到当请求释放连接时,会有一段time wait状态,这段时间内同一个端口号是无法再次被绑定使用的

打开端口重用就可以解除这个限制,继续使用这个端口号

setThreadNum()

void setThreadNum(int numThreads);

这个成员函数就是用于设置从属Reactor线程的数量的

Start()

void start();

启动事件监听

setConnectionCallback()

这是一个回调函数,需要我们自己来编写

typedef std::function<void(const TcpConnectionPtr &)> ConnectionCallback;
void setConnectionCallback(const ConnectionCallback &cb)
{
    connectionCallback_ = cb;
}

当连接建立成功时,会调用这个回调接口,完成我们的功能

setMessageCallback()

这也是一个回调函数,是用于业务处理的回调函数

typedef std::function<void(const TcpConnectionPtr &,
                           Buffer *,
                           Timestamp)>
    MessageCallback;
void setMessageCallback(const MessageCallback &cb)
{
    messageCallback_ = cb;
}

当收到连接的新的消息的时候,调用的函数

EventLoop类

这个类主要是用于事件监控和业务处理,在构造TcpServer之前,就需要构造这个EventLoop对象,最重要的就是loop成员函数

TcpConnection类

connected()和disconnect()是用于查看连接状态的

send()是用于发送数据的

服务器搭建

#include "muduo/include/muduo/net/TcpServer.h"
#include "muduo/include/muduo/net/EventLoop.h"
#include "muduo/include/muduo/net/TcpConnection.h"
#include "../logs/Xulog.h"
#include "TransLate.hpp"
#include <iostream>
#include <functional>
#include <unordered_map>

class TranslateServer
{
public:
    TranslateServer(int port) : _server(&_baseloop,
                                        muduo::net::InetAddress("0.0.0.0", port),
                                        "TranslateServer",
                                        muduo::net::TcpServer::kReusePort)
    {
        // 参数绑定
        auto func_1 = std::bind(&TranslateServer::onConnection, this, std::placeholders::_1);
        auto func_2 = std::bind(&TranslateServer::onMessage, this, std::placeholders::_1,
                                std::placeholders::_2, std::placeholders::_3);
        // 设置回调函数
        _server.setConnectionCallback(func_1);
        _server.setMessageCallback(func_2);
    }

    // 启动服务器
    void start()
    {
        _server.start();  // 开始事件监听
        _baseloop.loop(); // 开始事件监控,死循环阻塞接口
    }

private:
    // 建立连接或关闭之后的回调函数
    void onConnection(const muduo::net::TcpConnectionPtr &conn)
    {
        if (conn->connected())
        {
            INFO("新连接建立成功!");
        }
        else
        {
            INFO("连接关闭!");
        }
    }
    std::string translate(const std::string &str)
    {
        return Translate(str, "en", "zh");
    }
    // 收到请求时的回调函数
    void onMessage(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *buf, muduo::Timestamp)
    {
        // 调用translate接口进行翻译,向客户端返回结果
        std::string str = buf->retrieveAllAsString();
        std::string resp = translate(str);
        conn->send(resp);
    }

private:
    muduo::net::EventLoop _baseloop;
    muduo::net::TcpServer _server;
};

int main()
{
    TranslateServer server(8085);
    server.start();
    return 0;
}

这里我们使用了百度翻译的api,可以将英文翻译成中文

#include <iostream>
#include <string>
#include <curl/curl.h>
#include <cstdlib>
#include <cstring>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <jsoncpp/json/json.h>
#include <sstream>
#include <iomanip>

static size_t WriteCallback(void *contents, size_t size, size_t nmemb, std::string *userp)
{
    size_t total_size = size * nmemb;
    userp->append(static_cast<char *>(contents), total_size);
    return total_size;
}

std::string generateSign(const std::string &appid, const std::string &q, const std::string &salt, const std::string &secret_key)
{
    std::string sign = appid + q + salt + secret_key;
    unsigned char md[EVP_MAX_MD_SIZE];
    unsigned int md_len;

    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
    if (!ctx)
    {
        std::cerr << "Failed to create context for MD5." << std::endl;
        return "";
    }

    if (EVP_DigestInit_ex(ctx, EVP_md5(), nullptr) != 1 ||
        EVP_DigestUpdate(ctx, sign.c_str(), sign.length()) != 1 ||
        EVP_DigestFinal_ex(ctx, md, &md_len) != 1)
    {
        std::cerr << "Error generating MD5 digest." << std::endl;
        EVP_MD_CTX_free(ctx);
        return "";
    }

    EVP_MD_CTX_free(ctx);

    char buf[33] = {0};
    for (unsigned int i = 0; i < md_len; ++i)
    {
        sprintf(buf + i * 2, "%02x", md[i]);
    }
    return std::string(buf);
}

std::string parseJsonResponse(const std::string &response)
{
    Json::CharReaderBuilder reader;
    Json::Value jsonData;
    std::string errs;

    std::istringstream s(response);
    if (Json::parseFromStream(reader, s, &jsonData, &errs))
    {
        std::string from = jsonData["from"].asString();
        std::string to = jsonData["to"].asString();
        std::string translatedText = jsonData["trans_result"][0]["dst"].asString();

        return translatedText;
    }
    else
    {
        std::cerr << "Failed to parse JSON: " << errs << std::endl;
        exit(0);
    }
}

std::string urlEncode(const std::string &value)
{
    std::ostringstream escaped;
    escaped << std::hex << std::setfill('0');
    for (const char c : value)
    {
        if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~')
        {
            escaped << c;
        }
        else
        {
            escaped << '%' << std::setw(2) << static_cast<int>(static_cast<unsigned char>(c));
        }
    }
    return escaped.str();
}

std::string _translate(const std::string &appid, const std::string &secret_key, const std::string &q, const std::string &from, const std::string &to)
{
    char salt[60];
    sprintf(salt, "%d", rand());

    std::string sign = generateSign(appid, q, salt, secret_key);
    std::string q_encoded = urlEncode(q);
    std::string myurl = "http://api.fanyi.baidu.com/api/trans/vip/translate?appid=" + appid + "&q=" + q_encoded +
                        "&from=" + from + "&to=" + to + "&salt=" + salt + "&sign=" + sign;
    CURL *curl = curl_easy_init();
    std::string response_string;

    if (curl)
    {
        curl_easy_setopt(curl, CURLOPT_URL, myurl.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string);
        CURLcode res = curl_easy_perform(curl);
        if (res != CURLE_OK)
        {
            std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
        }
        curl_easy_cleanup(curl);
    }
    return response_string;
}

enum
{
    EnToZh,
    ZhToEn,
    Exit
};

std::string Translate(std::string text_to_translate, std::string from, std::string to)
{
    std::string appid = "";         // 替换为你的 App ID
    std::string secret_key = ""; // 替换为你的密钥
    std::string response = _translate(appid, secret_key, text_to_translate, from, to);
    return parseJsonResponse(response);
}

Client常见接口

TcpClient类

构造函数

TcpClient(EventLoop *loop,
          const InetAddress &serverAddr,
          const string &nameArg);

这里需要传入一个Eventloop,我们的epoll监控就在这里面

第二个参数是要连接的服务器的地址信息

第三个参数是名称

connect()

这个成员函数是用来连接服务器的

disconnect()

停止连接

stop()

停止客户端运行

connection()

TcpConnectionPtr connection() const
{
    MutexLockGuard lock(mutex_);
    return connection_;
}

这个成员函数是用来获取客户端通信连接的Connection对象的接口

这是一个非阻塞接口,调用之后直接返回,连接不一定建立完成,不能直接发送数据

如果需要在连接完成之后再做操作,需要调用内置的CountDownLatch类中的wait()成员函数进行同步控制

setConnectionCallback()

void setConnectionCallback(ConnectionCallback cb)
{
    connectionCallback_ = std::move(cb);
}

这是连接服务器成功时的回调函数

setMessageCallback()

void setMessageCallback(MessageCallback cb)
{
    messageCallback_ = std::move(cb);
}

这是收到服务器发送的消息时的回调函数

客户端搭建

#include "muduo/include/muduo/net/TcpClient.h"
#include "muduo/include/muduo/net/EventLoopThread.h"
#include "muduo/include/muduo/net/TcpConnection.h"
#include "muduo/include/muduo/base/CountDownLatch.h"
#include "../logs/Xulog.h"
#include <iostream>
#include <functional>

class TranslateClient
{
public:
    TranslateClient(const std::string &sip, int sport) : _lanch(1), // 设置阻塞
                                                         _client(_loopthread.startLoop(), muduo::net::InetAddress(sip, sport), "TranslateClient")

    {
        auto func_1 = std::bind(&TranslateClient::onConnection, this, std::placeholders::_1);
        auto func_2 = std::bind(&TranslateClient::onMessage, this, std::placeholders::_1,
                                std::placeholders::_2, std::placeholders::_3);
        _client.setConnectionCallback(func_1);
        _client.setMessageCallback(func_2);
    }
    // 连接服务器 阻塞等待连接建立成功
    void connect()
    {
        _client.connect();
        _lanch.wait(); // 阻塞等待,直到连接建立成功
    }
    bool send(const std::string &msg)
    {
        if (_conn->connected())
        {
            _conn->send(msg);
            return true;
        }
        return false;
    }

private:
    // 建立连接或关闭之后的回调函数 唤醒阻塞
    void onConnection(const muduo::net::TcpConnectionPtr &conn)
    {
        if (conn->connected())
        {
            _lanch.countDown(); // 唤醒主线程阻塞
            _conn = conn;
            std::cout << "连接建立成功!" << std::endl;
        }
        else
        {
            _conn.reset();
            std::cout << "连接已经断开!" << std::endl;
        }
    }

    // 收到消息时的回调函数
    void onMessage(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *buf, muduo::Timestamp)
    {
        std::cout << "翻译完成啦,结果是: " << buf->retrieveAllAsString() << std::endl;
    }

private:
    muduo::CountDownLatch _lanch;
    muduo::net::EventLoopThread _loopthread;
    muduo::net::TcpClient _client;
    muduo::net::TcpConnectionPtr _conn;
};

int main()
{
    TranslateClient client("127.0.0.1", 8085);
    client.connect();
    while (true)
    {
        std::string buffer;
        std::cin >> buffer;
        client.send(buffer);
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2176171.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

K-means聚类分析对比

K-means聚类分析&#xff0c;不同K值聚类对比&#xff0c;该内容是关于K-means聚类分析的&#xff0c;主要探讨了不同K值对聚类结果的影响。K-means聚类是一种常见的数据分析方法&#xff0c;用于将数据集划分为K个不同的类别。在这个过程中&#xff0c;选择合适的K值是非常关键…

VSCode 中配置 C/C++ 环境的步骤

VSCode 中配置 C/C 环境的步骤 1. 安装 VSCode 1、下载位置 https://code.visualstudio.com/Download2、安装 正常操作步骤&#xff0c;同意协议&#xff0c;下一步&#xff0c;点击完成即可 2. 安装 C/C 扩展 打开 VSCode。 点击左侧的扩展图标&#xff08;或使用快捷键…

Linux网络:网络编程套接字

socket 套接字 socket常见API 创建套接字&#xff1a;&#xff08;TCP/UDP&#xff0c;客户端服务器&#xff09; int socket(int domain, int type, int protocol);绑定端口号&#xff1a;&#xff08;TCP/UDP&#xff0c;服务器&#xff09; int listen(int sockfd, int …

Python 算法交易实验89 QTV200日常推进-模式思考

说明 过去几天大A的表现还是比较戏剧化的。 让我想到了&#xff1a; 1 价稳量缩模式。之前很长一段时间都是这种状态&#xff0c;最终还是大爆发了&#xff0c;这个可取。2 周期模式。假设价格是一个周期为T(T可变)的正弦波&#xff0c;所以最终还是回到了几个月前的位置&…

Java 常用运算符简单总结

目录 1. 运算符​编辑 1.1 算术运算符​编辑 1.1.1 除法运算符​编辑 1.1.2 取模&#xff08;取余&#xff09;运算符​编辑 1.1.3 自增/减运算符​编辑​编辑 1.2 关系运算符 1.3 逻辑运算符 1.3.1 逻辑/短路与 1.3.2 逻辑/短路或 1.4 取反操作 1.5 逻辑异或 1.4 …

第三节-类与对象(中)

1.类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类&#xff08;空类大小为1&#xff09;。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 默认成员函数&#xff1a;…

828华为云征文|华为云弹性云服务器FlexusX实例下的Nginx性能测试

本文写的是华为云弹性云服务器FlexusX实例下的Nginx性能测试 目录 一、华为云弹性云服务器FlexusX实例简介二、测试环境三、测试工具四、测试方法五、测试结果 下面是华为云弹性云服务器FlexusX实例下的Nginx性能测试。 一、华为云弹性云服务器FlexusX实例简介 华为云弹性云服…

Woocommerce怎么分类显示产品?如何将Shopify的产品导入到Woocommerce?

WooCommerce作为WordPress的一个电子商务插件&#xff0c;功能强大、使用简洁&#xff0c;能够轻松集成到WordPress网站中&#xff0c;为用户提供了一个完整的在线商店解决方案&#xff0c;在国外还是挺受欢迎的。 Woocommerce怎么分类显示产品&#xff1f; 在Woocommerce中&a…

数据资产新范式,URP城市焕新平台东博会首发!

城市数据资产蕴藏着巨大的宝藏。今年1月&#xff0c;国家数据局印发《“数据要素”三年行动计划&#xff08;2024—2026年&#xff09;》&#xff0c;将“数据要素智慧城市”上升为“数据要素”计划的重要部分&#xff0c;加速释放城市数据资产价值。 高质量发展以数据要素驱动…

聚星文社最新风格图库角色

聚星文社最新风格图库角色涵盖了各种不同的风格和类型。以下是一些可能的角色风格&#xff1a; Docs聚星文社https://iimenvrieak.feishu.cn/docx/ZhRNdEWT6oGdCwxdhOPcdds7nof 现代都市风格角色&#xff1a;这种角色通常穿着时尚的衣服&#xff0c;有时尚的发型和化妆。他们可…

【Python】Jet Bridge:快速构建内部工具和管理面板的高效解决方案

Jet Bridge 是一个开源的后台管理工具构建框架&#xff0c;专门用于帮助开发者快速创建内部工具、管理面板和仪表板。它允许用户通过现有的数据库结构快速生成强大的 CRUD&#xff08;创建、读取、更新、删除&#xff09;接口&#xff0c;并提供了直观的可视化界面。Jet Bridge…

反思式思维链大模型 o1 有啥用?

&#xff08;注&#xff1a;本文为小报童精选文章。已订阅小报童或加入知识星球「玉树芝兰」用户请勿重复付费&#xff09; 失望 OpenAI o1 刚出来的时候&#xff0c;我其实对这种 reflection 模型有点儿免疫了。因为刚刚被 reflection 70B 模型诳过一回。 第一时间&#xff0c…

漏洞挖掘 | 某系统中少见的前端登录校验

0 前言 我也是第一次碰到前端登录校验的站点&#xff0c;那所谓前端校验&#xff0c;就是不走后端&#xff0c;这种情况大概率会在前端存着登录的账号和密码&#xff0c;除此之外&#xff0c;一些验证码也可能会在前端校验。 1 测试 如下图&#xff0c;点普通的功能点均显示…

Deep Learning for Video Anomaly Detection: A Review 深度学习视频异常检测综述阅读

Deep Learning for Video Anomaly Detection: A Review 深度学习视频异常检测综述阅读 AbstractI. INTRODUCTIONII. BACKGROUNDA. Notation and TaxonomyB. Datasets and Metrics III. SEMI-SUPERVISED VIDEO ANOMALY DETECTIONA. Model InputB. MethodologyC. Network Archite…

栏目一:使用echarts绘制简单图形

栏目一&#xff1a;使用echarts绘制简单图形 前言1. 在线编辑图形1.1 折线图1.2 柱状图1.3 扇形图 2. 本地绘制图表2.1 下载echarts.min.js2.2 创建一个简单的图形 前言 Echarts是一款基于JavaScript的可视化图表库。它提供了丰富的图表类型和交互功能&#xff0c;可以用于在网…

Golang | Leetcode Golang题解之第445题两数相加II

题目&#xff1a; 题解&#xff1a; func reverseList(head *ListNode) *ListNode {if head nil || head.Next nil {return head}newHead : reverseList(head.Next)head.Next.Next head // 把下一个节点指向自己head.Next nil // 断开指向下一个节点的连接&#xff0c;保证…

Study-Oracle-10-ORALCE19C-RAC集群搭建(一)

一、硬件信息及配套软件 1、硬件设置 RAC集群虚拟机:CPU:2C、内存:10G、操作系统:50G Openfile数据存储:200G (10G*2) 2、网络设置 主机名公有地址私有地址VIP共享存储(SAN)rac1192.168.49.13110.10.10.20192.168.49.141192.168.49.130rac2192.168.49.13210.10.10.3…

使用dockerfile来构建一个包含Jdk17的centos7镜像(构建镜像:centos7-jdk17)

文章目录 1、dockerfile简介2、入门案例2.1、创建目录 /opt/dockerfilejdk172.2、上传 jdk-17_linux-x64_bin.tar.gz 到 /opt/dockerfilejdk172.3、在/opt/dockerfilejdk17目录下创建dockerfile文件2.4、执行命令构建镜像 centos7-jdk17 : 不要忘了后面的那个 .2.5、查看镜像是…

Mixture-of-Experts (MoE): 条件计算的诞生与崛起【上篇】

大型语言模型&#xff08;LLM&#xff09;的现代进步主要是缩放定律的产物[6]。 假设模型是在足够大的数据集上训练出来的&#xff0c;那么随着底层模型规模的增加&#xff0c;我们会看到性能的平滑提升。 这种扩展规律最终促使我们创建了 GPT-3 以及随后的其他&#xff08;更强…

力扣高频 SQL 50 题(基础版)|分析、题解

注意一些语法 1、group by出现在having前面&#xff0c;但是having中所使用的聚合必须是select中的 2、date类型之间的比较&#xff1a;datediff&#xff08;&#xff09; 差的绝对值 or 用字符框起来比较边界 3、算日期长度需要相减之后加一 4、round(, n)n默认是0&#x…