首页 > 编程语言 >C++ 简单使用Json库与muduo网络库

C++ 简单使用Json库与muduo网络库

时间:2024-03-17 09:00:57浏览次数:30  
标签:muduo C++ Json build install tony net include

C++ 简单使用Json库与muduo网络库

C++ 使用Json库

测试代码均在Ubuntu 20上运行
首先下载json.hpp的代码链接
然后和你的测试代码放在同一目录下面

导入方式

#include "json.hpp"
using json = nlohmann::json;

json序列化代码

测试1

void test1()
{
    json js;
  js["id"]={1,2,3};
  js["name"]="zhangsan";

  js["msg"]["zhangsan"]="hello";
  js["msg"]["shaoye"]="world";
// 上面这两行等于这一行
  // js["msg"]={{"zhangsan","hello"},{"shaoye","world"}};

  std::cout<<js<<std::endl;
  //输出
  // {"id":[1,2,3],"msg":{"shaoye":"world","zhangsan":"hello"},"name":"zhangsan"}
 std::string str=js.dump();//转换成为string
  std::cout<<str<<std::endl;

/*
{"id":[1,2,3],"msg":{"shaoye":"world","zhangsan":"hello"},"name":"zhangsan"}
{"id":[1,2,3],"msg":{"shaoye":"world","zhangsan":"hello"},"name":"zhangsan"}
*/
}

例子2

void test2()
{
  json js;
  // 直接序列化vector
  std::vector<int> vec;
  vec.push_back(1);
  vec.push_back(2);
  vec.push_back(5);
  js["list"]=vec;
      // 直接序列化map容器
  std::map<int,std::string> m;
  m.insert({1,"A"});
  m.insert({2,"B"});
  m.insert({3,"C"});
  js["path"]=m;
  std::cout<<js<<std::endl;

  // {"list":[1,2,5],"path":[[1,"A"],[2,"B"],[3,"C"]]}
}

json反序列化代码,把test2的返回string给解析为json

void test3(std::string str)
{
  json js=json::parse(str);
  std::cout<<js["list"]<<std::endl;
  std::cout<<js["path"]<<std::endl;

//   [1,2,5]
// [[1,"A"],[2,"B"],[3,"C"]]

// 将json转换成STL容器
  std::vector<int> vec = js["list"];
   
  std::map<int,std::string> m = js["path"];
}

muduo网络库

在linux上安装muduo库编程

muduo库是基于boost开发的,所以需要先在Linux平台上安装boost库
muduo链接
1.拷贝muduo的源码压缩包muduo-master.zip到Linux系统下
unzip muduo-master.zip
2.解压完成后,进入muduo库的解压目录里面
3.注释这一行

4.看到有一个build.sh源码编译构建程序,运行该程序
./build.sh
5.编译完成后,在输入./build.sh install命令进行muduo库安装
./build.sh install
6.这个./build.sh install实际上把muduo的头文件和lib库文件放到了muduo-master同级目录下的build目录下的release-install-cpp11文件夹下面了
所以上面的install命令并没有把它们拷贝到系统路径下,导致我们每次编译程序都需要指定muduo库的头文件和库文件路径,很麻烦,所以我们选择直接把inlcude(头文件)和lib(库文件)目录下的文件拷贝到系统目录下

root@tony-virtual-machine:/home/tony/package/build/release-install-cpp11# ls
include  lib
root@tony-virtual-machine:/home/tony/package/build/release-install-cpp11# cd include/
root@tony-virtual-machine:/home/tony/package/build/release-install-cpp11/include# ls
muduo
root@tony-virtual-machine:/home/tony/package/build/release-install-cpp11/include# mv muduo/ /usr/include/
root@tony-virtual-machine:/home/tony/package/build/release-install-cpp11/include# cd ..
root@tony-virtual-machine:/home/tony/package/build/release-install-cpp11# ls
include  lib
root@tony-virtual-machine:/home/tony/package/build/release-install-cpp11# cd lib/
root@tony-virtual-machine:/home/tony/package/build/release-install-cpp11/lib# ls
libmuduo_base.a  libmuduo_http.a  libmuduo_inspect.a  libmuduo_net.a
root@tony-virtual-machine:/home/tony/package/build/release-install-cpp11/lib# mv * /usr/local/lib/
root@tony-virtual-machine:/home/tony/package/build/release-install-cpp11/lib# 

7.写测试代码,测试muduo是否能够正常使用

#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();
}

8.使用g++进行编译,注意链接muduo和pthread的库文件,编译命令如下:

g++ main.cpp -lmuduo_net -lmuduo_base -lpthread -std=c++11

编译链接完成,生成a.out可执行程序,上面的echo服务器监听8888端口,运行上面的a.out回显服务器如下:

root@tony-virtual-machine:/home/tony/code# ./a.out 
20190404 08:00:15.254790Z 42660 INFO  pid = 42660 - main.cpp:61

等待客户端连接,可以打开一个新的shell命令行用netcat命令模拟客户端连接echo服务器进行功能测试,命令如下:

tony@tony-virtual-machine:~$ echo "hello world" | nc localhost 8888
hello world

客户端数据回显正确,看看服务器接日志信息打印如下:

root@tony-virtual-machine:/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安装成功

基于muduo库编程

muduo库的使用需要链接libmuduo_base.so libmuduo_net.so libpthread.so
一般在linux的两个地方,/usr/lib /usr/local/lib
在vscode中配置一下编译
ctrl+shift+B
在tasks.json中修改配置

。。。
"args": [
				"-fdiagnostics-color=always",
				"-g",
				"${file}",
				"-o",
				"${fileDirname}/${fileBasenameNoExtension}",
				"-lmuduo_net",
				"-lmuduo_base",
				"-lpthread" 
			],
。。。

然后按ctrl+shift+B就能编译了

或者在终端中

g++ -o 输出名字 你的CPP名字.cpp -lmuduo_net -lmuduo_base  -lpthread 

muduo库开发服务器端思路

基于muduo网络库开发服务器端流程

  • 1 组合tcpserver对象
  • 2 创建Eventpool事件循环对象的指针
  • 3 明确TcpServer构造函数需要什么参数,输出ChatServer的构造函数
  • 4 在当前服务器类的构造函数当中,注册处理连接的回调函数和处理读写事件的回调函数
  • 5 设置合适的服务端线程数量 ,一般根据内核数量, muduo库会自己划分IO线程和work线程

代码

// muduo网络库给用户提供了两个主要的类
// TcpServer:用于编写服务器程序的
// TcpClient:用于编写客户端程序的
// 模型:
// epoll+线程池
// 好处:能够把网络IO的代码和业务代码区分开
// 用户的连接和断开,用户的可读性事件
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <iostream>
#include <string>

using namespace std;
using namespace muduo;
using namespace muduo::net;
using namespace placeholders;
// 基于muduo网络库开发服务器端流程
// 1组合tcpserver对象
// 2创建Eventpool事件循环对象的指针
// 3明确TcpServer构造函数需要什么参数,输出ChatServer的构造函数
// 4 在当前服务器类的构造函数当中,注册处理连接的回调函数和处理读写事件的回调函数
// 5 设置合适的服务端线程数量 一般根据内核数量,muduo库会自己划分IO线程和work线程

class ChatServer{
  public:
ChatServer(EventLoop* loop,  //事件循环
      const InetAddress &listenAddr,  //ip+port
      const string& nameArg) //服务器名字
      :_server(loop,listenAddr,nameArg),_loop(loop){
          // 给服务器注册用户连接的创建和断开回调 _1代表参数占位符
           _server.setConnectionCallback(std::bind(&ChatServer::onConnection,this,_1));
          // 给服务器注册用户读写事件回调
          _server.setMessageCallback(std::bind(&ChatServer::onMessage,this,_1,_2,_3));

          // 设置服务器端的线程数量  一个IO线程  三个work线程
          _server.setThreadNum(4);
      }
      // 开启事件循环
  void start(){
    _server.start();
  }
  private:
  // 专门处理用户的连接创建和断开 epoll listenfd accept
  void onConnection(const TcpConnectionPtr& conn){
      if(conn->connected()) //true代表连接成功
      {
        cout<<conn->peerAddress().toIpPort()<<"->"
        <<conn->localAddress().toIpPort()<<"state online"<<endl;
      }
      else
      {
        cout<<conn->peerAddress().toIpPort()<<"->"
        <<conn->localAddress().toIpPort()<<"state offline!"<<endl;
        conn->shutdown(); // close(fd)
      }
  }
  // 专门处理用户的读写事件
  void onMessage(const TcpConnectionPtr& conn,//连接
  Buffer* buff,  //缓冲区
  Timestamp time) //接受到数据的时间信息
  {
    string buf =buff->retrieveAllAsString();
    cout<<"recv data:"<<buf<<"time:"<<time.toString()<<endl;
    conn->send(buf); //发送返回
  }
    TcpServer _server;
    EventLoop *_loop; 
};
int main()
{
  EventLoop loop;//epoll
  InetAddress addr("127.0.0.1",8888);
  ChatServer server(&loop,addr,"ChatServer");
  server.start(); //启动服务 listenfd epoll_ctl=>epoll
  loop.loop();
  //最后调用epoll_wait 以阻塞方式等待新用户连接,已连接用户的读写操作等
  return 0;
}

标签:muduo,C++,Json,build,install,tony,net,include
From: https://www.cnblogs.com/AndreaDO/p/18065610

相关文章

  • UG NX二次开发(C++)-创建样条曲线(二)-UF_MODL_create_spline使用
    系列文章目录第一章、UGNX二次开发(C++)-创建样条曲线(一)-UF_CURVE_create_spline使用第二章、UGNX二次开发(C++)-创建样条曲线(二)-UF_MODL_create_spline使用提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录系列文章目录第一章、[UGN......
  • C++ STL第三篇(搞清楚deque原理和有多少用法)
    dequeVector容器是单向开口的连续内存空间,deque则是一种双向开口的连续线性空间。所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,当然,vector容器也可以在头尾两端插入元素,但是在其头部操作效率奇差,无法被接受。Deque容器和vector容器最大的差异,一在于deque允许......
  • (C++)DP动态规划
    天下苦DP久已。​ DP非常重要,2022年蓝桥杯应该改名为DP杯,至于2023年那个我觉得应该叫做暴力杯。​ DP的核心思想在于,通过前面几个状态来推导下一个数据是什么,也就是走一步是一步。其本质实际上是记忆化搜索,但是有些玄学的事情就是,有时候记忆化会因为玄学递归问题TLE,但DP的那四......
  • c++机试一些提示
    1、优先队列的使用,头文件#include;优先队列定义:priority_queue<int,vector<int>,greater<int>>pq;(整数数据类型,小顶堆)。例题:哈夫曼树#include<iostream>#include<queue>usingnamespacestd;intmain(){intn;cin>>n;priority_queue<i......
  • 华为OD机试 C++ -文件缓存系统
    文件缓存系统前言:本专栏将持续更新互联网大厂机试真题,并进行详细的分析与解答,包含完整的代码实现,希望可以帮助到正在努力的你。关于大厂机试流程、面经、面试指导等,如有任何疑问,欢迎联系我,wechat:steven_moda;email:[email protected];备注:CSDN。题目描述请设计一个文件缓......
  • C++ 枚举
    C++枚举5.4.1普通枚举枚举的定义:,枚举类型是通过enum关键字定义的,比如定义颜色类型enumColor{RED,//默认值为0GREEN,//默认值为1BLUE//默认值为2};ColormyColor=RED;注意:(1)括号内为以逗号分隔,大括号结尾要有分号(2)枚举类型就相当于......
  • 10. C++关键字virtual用法
    1.C++关键字:virtual用法1.1概念virtual是C++OO机制中很重要的一个关键字。主要用在两个方面:虚函数、纯虚函数和虚基类、虚继承。1.2虚函数virtual放在函数的返回值前面,用于表示该类成员函数为虚函数;父类虚函数前的virtual必须写;子类虚函数前的virtual可以省略,因为不......
  • 使用c++容器string相关完成
    //把邮箱地址字符串[email protected],取出其中用户名字符串打印stringgetUsername(string&s){   intpops=s.find('@');   stringusername=s.substr(0,pops);   returnusername;}//大小写转换 使用标准库提供俩函数,单个字符为操作对象stringstr=......
  • 详解MySQL的MVCC(ReadView部分解析C++源码)
    文章目录1.什么是MVCC2.MVCC核心组成(三大件)2.1MVCC为什么需要三大件3.隐藏字段4.undolog4.1模拟版本链数据形成过程5.ReadView5.1m_ids5.2m_creator_trx_id5.3m_low_limit_id5.4m_up_limit_id5.5可见性分析算法6.MVCC流程模拟6.1RC隔离级别6.2RR隔离......
  • C++学习笔记——002
    在一个类里建立一个const时,不能给他初值:classfoo{public:foo():i(100){}private:constinti=100;//错误!!!};//可以通过这样的方式来进行初始化foo::foo():i(100){} classTest{public:Test():a(0){}enum{size1=100,size2=200};......