当前位置:   article > 正文

C++使用json在Linux中实现TCP通信_c++ tcp json

c++ tcp json

最近在学习使用json格式在Linux中进行tcp通信,以下为学习笔记

我使用的第三方库为nlohomann/json, 仓库地址为

nlohmann/json: JSON for Modern C++ (github.com)

nlohomann/json的所有代码都保存在单个头文件json.hpp中,所以要使用nlohomann/json,需要在实现文件中包含json.hpp

#include "json.hpp"
  • 1
json的发送与接收

要发送json格式的数据时需要先将其转换为二进制数据,我使用以下代码实现转换

    json j;
    char sendData[2048];
    ...
    string s = j.dump();//将json转换为string类型
    strcpy(sendData, s.c_str());//将string类型转为char*后进行拷贝
  • 1
  • 2
  • 3
  • 4
  • 5

在接收到json的二进制数据后,再将其转换为json格式

recv(peerfd, recvdata, 2048, 0);
json j = json::doParse(recvData);
  • 1
  • 2
代码实例

我封装了一个用于json与内置数据类型与STL容器转换的类

#include "json.hpp"
#include <vector>
#include <string>
class ProtocolParser
{
    public:
        void Json2char(json & j, char*  sendData);//json转char数组
        json doParse(char*  recvData);//char数组转json
        json vector2json(vector<string> & s);//vector转json
        void json2vector(json & j, vector<string> & v);//json转vector
};

using std::string;

void ProtocolParser::Json2char(json & j, char*  sendData)
{
    string s = j.dump();
    strcpy(sendData, s.c_str());
}

json ProtocolParser::doParse(char * recvData)
{
    return json::parse(recvData);
}

json ProtocolParser::vector2json(vector<string> & s)
{
    return json(s);
}

void ProtocolParser::json2vector(json & j, vector<string> & v)
{
    v.clear();
    v = j.get<vector<string>>();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

以下为在客户端与服务端中使用ProtocolParse类的示例

服务端

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "json.hpp"

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "ProtocolParser.h"

#include <iostream>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using nlohmann::json;

void test()
{
  //1. 创建监听服务器的套接字
  int listenfd = ::socket(AF_INET, SOCK_STREAM, 0);  

  if(listenfd < 0)
    {
    perror("socket");
    return;
  }

  //网络地址需要采用网络字节序存储(大端模式)
  struct sockaddr_in serveraddr;
  memset(&serveraddr, 0, sizeof(serveraddr));
  serveraddr.sin_family = AF_INET;
  serveraddr.sin_port = htons(8888);
  serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  socklen_t length = sizeof(serveraddr);

#if 1
  //设置网络地址可以重用
  int on = 1;
  if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) < 0) 
    {
    perror("setsockopt");
    close(listenfd);
    return;
  }

  //当端口设置为可以重用时, 就实现了系统级别的负载均衡
  if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int)) < 0) 
    {
    perror("setsockopt");
    close(listenfd);
    return;
  }
#endif

  //2. 绑定服务器的网络地址
  if(::bind(listenfd, (struct sockaddr*)&serveraddr, length) < 0)
    {
    perror("bind");
    //文件描述符是比较稀缺的,所以不用的时候要回收
    close(listenfd);
    return;
  }

  //3. 让服务器开始监听
  if(::listen(listenfd, 10) < 0)
    {
    perror("listen");
    close(listenfd);
    return;
  } 
  printf("server is listening...\n");

  //4. 获取对端的文件描述符,并与对端进行通信
  int peerfd = ::accept(listenfd, nullptr, nullptr);

  //5. 需求:希望服务器可以与客户端通过终端进行聊天
  while(1) 
    {
    char recvdata[2048];
    int ret = recv(peerfd, recvdata, 2048, 0);
    printf("recv msg from client: %s\n", recvdata);
    recvdata[ret] = '\0';
    ProtocolParser parse;
    json j = parse.doParse(recvdata);
    cout << j << endl;

    //从终端获取一行数据
    cout << ">> pls input some message:";
    string line;
    getline(cin, line);
    send(peerfd, line.c_str(),  line.size(), 0);
  }
  
  close(peerfd);// 关闭连接
  close(listenfd);
}
 
int main(void)
{
  test();
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107

客户端

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <vector>
#include "json.hpp"
#include "ProtocolParser.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <iostream>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using nlohmann::json;
using std::vector;

void test()
{
  int clientfd = ::socket(AF_INET, SOCK_STREAM, 0);
  if (clientfd < 0)
  {
    perror("socket");
    return;
  }

  struct sockaddr_in serverAddr;
  memset(&serverAddr, 0, sizeof(serverAddr));
  serverAddr.sin_family = AF_INET;
  serverAddr.sin_port = htons(8888);
  serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  socklen_t length = sizeof(serverAddr);

  if (::connect(clientfd, (struct sockaddr* )&serverAddr, length) < 0)
  {
    perror("connect");
    close(clientfd);
    return;
  }
  printf("conn has connected!...\n");

  while (1)
  {
    // string line;
    // cout << ">> pls input some message:";
    // getline(cin, line);
    // line.append("\n");
    char sendData[2048] = {0};
    
    vector<string> vec={"hello", "world"};
    ProtocolParser parser;
    json j = parser.vector2json(vec);
    parser.Json2char(j, sendData);
    // 1. 客户端先发数据
    send(clientfd, sendData, strlen(sendData), 0);
    /* close(clientfd); */

    char buff[128] = {0};
    recv(clientfd, buff, sizeof(buff), 0);
    printf("recv msg from server: %s\n", buff);
  }

  close(clientfd);
}

int main(void)
{
  test();
  return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

运行结果

服务端进程

在这里插入图片描述

客户端进程

在这里插入图片描述

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

闽ICP备14008679号