muduo网络库介绍

文章目录

    • 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 IDstd::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.xdnf.cn/news/1549868.html

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

相关文章

加法器以及标志位

加法器的结构&#xff1a; OF&#xff08;溢出标志位&#xff09;&#xff0c;SF&#xff08;符号标志位&#xff09;&#xff0c;ZF&#xff08;0标志位&#xff09;&#xff0c;ZF&#xff08;进位/借位标志位&#xff09; 有符号数看标志位&#xff1a;OF&#xff0c;SF 无符…

Stable Diffusion绘画 | 插件-Deforum:动态视频生成

Deforum 与 AnimateDiff 不太一样&#xff0c; AnimateDiff 是生成丝滑变化视频的&#xff0c;而 Deforum 的丝滑程度远远没有 AnimateDiff 好。 它是根据对比前面一帧的画面&#xff0c;然后不断生成新的相似图片&#xff0c;来组合成一个完整的视频。 Deforum 的优点在于可…

AI Agent应用出路到底在哪?

1 Agent/Function Call 的定义 Overview of a LLM-powered autonomous agent system&#xff1a; Agent学会调用外部应用程序接口&#xff0c;以获取模型权重中缺失的额外信息&#xff08;预训练后通常难以更改&#xff09;&#xff0c;包括当前信息、代码执行能力、专有信息源…

【Godot4.3】简单物理模拟之圆粒子碰撞检测

概述 最近开始研究游戏物理的内容&#xff0c;研究运动、速度、加速度之类的内容。也开始模仿一些简单的粒子模拟。这些都是一些基础、简单且古老的算法&#xff0c;但是对于理解游戏内的物理模拟很有帮助。甚至你可以在js、Python或者其他程序语言中实现它们。 图形的碰撞检…

详解JavaScript中属性的特性getOwnPropertyDescriptor()等

属性的特性 可以认为一个属性包含一个名字和4个特性&#xff0c;它的值&#xff0c;可写性&#xff0c;可枚举性&#xff0c;可配置性。 因此&#xff0c;存储器属性的4个特性&#xff0c;读取&#xff0c;写入&#xff0c;可枚举&#xff0c;可配置。 定义了一个“属性描述…

Unity实战案例全解析:RTS游戏的框选和阵型功能(2) 生成选择框

前篇&#xff1a;Unity实战案例全解析&#xff1a;RTS游戏的框选和阵型功能&#xff08;1&#xff09; 基础要素-CSDN博客 本案例来源于unity唐老狮&#xff0c;有兴趣的小伙伴可以去泰克在线观看该课程 【唐老狮】Unity实现 即时战略游戏 阵型功能 - 泰课在线 -- 志存高远&…

C++入门基础知识90(实例)——实例15【求两数的最大公约数】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于求两数的最大公约数的相关内容&#xff…

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 …

完全二叉树的节点个数 C++ 简单问题

完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层&#xff0c;则该层包含 1~ 2h 个节点。 示例 1&#xff…

C语言 | Leetcode C语言题解之第445题两数相加II

题目&#xff1a; 题解&#xff1a; struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){int stack1[100];int stack2[100];int top1 0;int top2 0;int carry 0;int sum 0;struct ListNode* temp NULL;struct ListNode* head NULL;while (l1) {…

Go语言中的深拷贝:概念、实现与局限

前不久&#xff0c;在“Gopher部落”知识星球[1]上回答了一个Gopher关于深拷贝(Deep Copy)的问题&#xff0c;让我感觉是时候探讨一下深拷贝技术了。 在日常开发工作中&#xff0c;深拷贝的使用频率相对较低&#xff0c;可能有80%的时间不需要使用深拷贝&#xff0c;只有在特定…

行为设计模式 -模板方法模式- JAVA

模板方法模式 一 .简介二. 案例2.1 抽象类&#xff08;Abstract Class&#xff09;2.2 具体子类&#xff08;Concrete Class&#xff09;2.3 测试 三. 结论3.1 优缺点3.2 适用场景3.3 要点 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接…

springboot网上商城源码分享

开头&#xff1a;springboot网上商城 题目&#xff1a;springboot网上商城 主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Mysql|大数据|SSM|SpringBoot|Vue|Jsp|MYSQL等)、学习资料、JAVA源码、技术咨询 文末联系获取 感兴趣可以先收藏起来&#xff0c;以防走丢&…

指针变量作为函数参数

int main() {char* LPFileBuffer NULL;//接收堆区的指针变量const char* m_fileName "E:\\c\\windowspad.exe";//一个char*的指针变量if (!ReadExeFile(m_fileName, LPFileBuffer)){return -1;}} //接收两个char*变量 OOL ReadExeFile(__in const char* m_fileName…

【初阶数据结构】排序——选择排序

目录 前言选择排序堆排序 前言 对于常见的排序算法有以下几种&#xff1a; 下面这节我们来看选择排序算法。 选择排序 基本思想&#xff1a;   每一次从待排序的数据元素中遍历选出最大&#xff08;或最小&#xff09;的元素放在序列的起始位置&#xff0c;直到全部待排序…

第三节-类与对象(中)

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

老板最想要的20套模板!基于 VUE 国产开源 IoT 物联网 Web 可视化大屏设计器

如有需求&#xff0c;文末联系小编 Cola-Designer 是一个基于VUE开发&#xff0c;实现拖拽和配置方式生成数据大屏&#xff0c;提供丰富的可视化模板&#xff0c;满足客户业务监控、数据统计、风险预警、地理信息分析等多种业务的展示需求。Cola-Designer 帮助工程师通过图形化…

市场调研利器 网络问卷的优势及面临的挑战

网络问卷作为市场调研工具&#xff0c;高效便捷、成本低廉、数据准确度高且灵活多样。但其低响应率、数据偏差、隐私与安全及技术依赖等挑战也需关注。企业应优化调研方法&#xff0c;应对挑战&#xff0c;以获取全面市场信息。 一、网络问卷的优势 首先&#xff0c;我们来分析…

S32K312 RTD 4.0.0 版本 OCU 例程配置流程说明

一、前言 由于 RTD 4.0.0 版本并没有 S32K312 相关例程&#xff0c;本文基于已有的 S32K344 OCU 例程&#xff0c;新建 S32K312 工程&#xff0c;讲解 OCU 例程的相关配置流程。 二、基本概念 OCU&#xff08;Output Compare Unit – 输出比较单元&#xff09;本质上是一个计…

揭开量子计算和加密未来的秘密

加密保护您的数据 您是否想知道如何保证您的在线数据安全&#xff1f;这就是加密的作用所在。加密是一种使用秘密代码更改数据的过程。这些更改只能由拥有正确密钥的接收者解码和读取。 加密是保护敏感和个人信息安全的重要工具。使用加密的一些示例包括信用卡详细信息、消息…