通过Socket协议发送JSON数据至服务器(C++)
创始人
2024-09-25 11:51:43
0

声明 : 本代码是在Ubuntu环境下写的。

目   录

1.Socket协议简介:

(1) Socket 的基本概念

(2) Socket 的类型

(3) Socket 编程的基本步骤

(4) Socket 在 C++ 中的应用

2. 客户端完整代码

3. 注意事项


 

1.Socket协议简介:

   Socket 是一种通信机制,它允许不同计算机之间的进程互相通信。在计算机网络中,Socket 提供了一种基于网络的、进程间通信的方式。Socket API(应用程序接口)被设计为跨平台的,这意味着几乎可以在任何操作系统上使用相同的接口来开发网络应用程序。

(1) Socket 的基本概念

  • Socket:
    • 一个 Socket 可以被看作是一个端点,用于网络中的两个进程之间的双向通信。每个 Socket 都有一个唯一的地址,通常包括 IP 地址和端口号。
  • IP 地址:
    • 用来标识网络中的设备。IPv4 地址由四个字节组成,每个字节表示为一个介于 0 到 255 之间的十进制数,并且用点分隔开。
  • 端口号:
    • 用来标识运行在同一台机器上的特定服务或应用程序。端口号是一个 16 位的数字,范围从 0 到 65535。

(2) Socket 的类型

  • 流式套接字 (SOCK_STREAM)
    • 提供面向连接的服务,基于 TCP 协议,保证数据无差错、按顺序到达。
  • 数据报套接字 (SOCK_DGRAM)
    • 提供无连接的服务,基于 UDP 协议,不保证数据的顺序性和可靠性。

(3) Socket 编程的基本步骤

  1. 创建 Socket:根据需要选择合适的 Socket 类型,例如 TCP 或 UDP。
  2. 绑定地址:对于服务器端,需要将 Socket 绑定到一个本地地址和端口。
  3. 监听连接:如果是 TCP 服务器,需要调用 listen() 函数进入监听状态。
  4. 接受连接:服务器端调用 accept() 接受来自客户端的连接请求。
  5. 数据交换:客户端和服务端之间通过 send() 和 recv() 函数发送和接收数据。
  6. 关闭连接:完成数据交换后,双方需要关闭 Socket。

(4) Socket 在 C++ 中的应用

        在 C++ 中,Socket 编程通常涉及到 POSIX 标准库的使用,这些库提供了创建和管理 Socket 的函数。例如,在 Linux 环境下,可以使用  和  头文件来编写 Socket 程序。

2. 客户端完整代码

/*     summary:socket client     author:main     date:2024.08.26 */  // 引入头文件 #include          // 引入标准输入输出库,如 cout 等。 #include           // 引入标准输入输出库,如 printf 等。 #include          // 引入字符串处理库,如 strlen 等。 #include          // 引入 POSIX 标准的 API,如 fork, exec, waitpid 等。 #include          // 引入标准库,如 exit 等。 #include           // 引入网络地址转换库,如 hostent 等。 #include      // 引入 socket API,如 socket, bind, listen, accept 等。 #include       // 引入网络地址转换库,如 inet_addr 等。 #include       // 引入系统类型定义库,如 pid_t 等。 #include            // 引入时间库,如 chrono 等。 #include            // 引入线程库,如 thread 等。 using namespace std;        // 引入标准命名空间,用于简化代码。  const char *ip_address = "255.255.255.255";                    // 服务器IP地址 const char *port = "8080";                                     // 服务器端口号  /*     @brief 延时函数     @param ms 延时时间,单位为毫秒     @return 无 */ void delay(int ms) {     std::this_thread::sleep_for(std::chrono::milliseconds(ms)); }  /*      @brief 创建客户端类     @param ip_address 服务器IP地址     @param port 服务器端口号     @return 无 */ class SOCKET_CLIENT { public:     int sockfd;     int iret;                                                   // 定义返回值      /*--------------------------------------创建套接字-------------------------------------------------*/     int sock_create() {          if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){  // 如果创建失败返回-1             perror("socket");                                   // 输出错误信息             return -1;         }     }      /*--------------------------------------连接服务器-------------------------------------------------*/     int sock_connect() {          struct sockaddr_in servaddr;                            // 初始化服务器地址结构体         memset(&servaddr, 0, sizeof(servaddr));                 // 将结构体清零         servaddr.sin_family = AF_INET;                          // 设置协议族为 IPv4         servaddr.sin_port = htons(atoi(port));                  // 设置端口号         servaddr.sin_addr.s_addr = inet_addr(ip_address);       // 设置 IP 地址         if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)   // 如果连接服务器失败返回-1         {                perror("connect");                                  // 输出错误信息             close(sockfd);                                      // 关闭套接字             return -1;         }     }      /*--------------------------------------发送数据--------------------------------------------------*/     int sock_send(char*msg) {          char buffer[1024];                                      // 创建缓冲区 - 栈         memset(buffer, 0, sizeof(buffer));                      // 清空缓冲区         size_t len = strlen(msg);                               // 获取消息长度          if (len >= sizeof(buffer))         {             perror("消息长度超过缓冲区大小");                     // 输出错误信息             return -1;         }          strncpy(buffer, msg, len);                              // 将消息复制到缓冲区         buffer[strlen(buffer)] = '\0';                          // 添加字符串结束符          if ((iret = send(sockfd, buffer, strlen(buffer), 0)) <= 0)                 // 发送数据         {             printf("数据发送错误,IRET=%d",iret);                  // 输出错误信息             return -1;          }          printf("send data is %s\n",buffer);                      // 打印发送的数据         memset(buffer, 0, sizeof(buffer));                       // 清空缓冲区         }       /*--------------------------------------接收数据--------------------------------------------------*/     int sock_recv() {                   char buffer[1024];                                       // 创建缓冲区         memset(buffer, 0, sizeof(buffer));                       // 清空缓冲区          if ((iret = recv(sockfd, buffer, sizeof(buffer), 0)) <= 0)                  // 接收数据         {             printf("数据接受错误,iret=%d",iret);                  // 打印错误信息             return -1;         }          printf("recv data is %s",buffer);                        // 打印接收到的数据         memset(buffer, 0, sizeof(buffer));                       // 清空缓冲区         return 0;     }      /*--------------------------------------关闭套接字------------------------------------------------*/     void sock_close() {         close(sockfd);                                           // 关闭套接字     } };   class JSON_DATA { public:     string facility_1(char time, char HS, char TEMP, char ATM, char HLux, char LLux){         return "{"             "\'imei\':\'***************\',"                      // 设备IMEI             "\'time\':\'" + to_string(time) + "\',"              // 上报时间             "\'name\':\'WeatherSensors\',"                       // 气象传感器             "\'data\':{"                 "\'HS\':\'" + to_string(HS) + "\',"              // 湿度值                 "\'TEMP\':\'" + to_string(TEMP) + "\',"          // 湿度值                 "\'ATM\':\'" + to_string(ATM) + "\',"            // 气压值                 "\'HLux\':\'" + to_string(HLux) + "\',"          // 光照最高值                 "\'LLux\':\'" + to_string(LLux) + "\'}"          // 光照最低值         "}";     }      string facility_2(char time, char PPM, char TEMP_2, char EC, char PH){         return "{"             "\'imei\':\'***************\',"                      // 设备IMEI             "\'time\':\'" + to_string(time) + "\',"              // 上报时间             "\'name\':\'SoilSensor\',"                           // 土壤传感器             "\'data\':{"                 "\'PPM\':\'" + to_string(PPM) + "\',"            // 水分值                 "\'TEMP\':\'" + to_string(TEMP_2) + "\',"        // 温度值                 "\'EC\':\'" + to_string(EC) + "\',"              // 导电率                 "\'PH\':\'" + to_string(PH) + "\'}"              // PH值         "}";     }      string facility_3(char time, char PRCP){         return "{"             "\'imei\':\'***************\',"                      // 设备IMEI             "\'time\':\'" + to_string(time) + "\',"              // 上报时间             "\'name\':\'RainSensor\',"                           // 雨量传感器             "\'data\':{"                       "\'PRCP\':\'" + to_string(PRCP) + "\'}"          // 雨量值         "}";     } };   int main()         {     SOCKET_CLIENT client1;                                       // 创建客户端对象     JSON_DATA json_socket;                                       // 创建JSON数据对象     string json_data;                                            // JSON数据 字符串      if (client1.sock_create() == -1) return -1;                  // 创建套接字     if (client1.sock_connect() == -1) return -1;                 // 连接服务器      json_data = json_socket.facility_2(time(NULL), 50, 25, 10, 10);                  // 赋值JSON数据            client1.sock_send((char*)json_data.c_str());                 // 发送数据     client1.sock_recv();                                         // 接收数据     client1.sock_close();                                        // 关闭套接字 } 

3. 注意事项

        (1) 0dbe47ce6b39466b969375935b5ed78c.png将如图所示的位置的参数使用时修改为自己的。

        (2)我运行代码时所使用的IP和端口号是对方给我提供的(这里的255.255.255.255,8080是我随意填写的),是正常链接对方的服务端的。

          (3)   我用Python写了一个服务端,用我写的Python版本的客户端是正常连接该服务端的。但使用上述C++写的客户端连接该服务端时总是显示拒绝连接。(由于时间关系就没去排查问题,后续有时间排查了,给大伙奉上结果)。

          (4)      ​​​e00fcf8ab351448b8572e56bfdef3400.png这里的设备IMEI按照自己的实际情况填写。

        (5) 有疑问在评论区提问或者私信即可,看到了第一时间回复。

 

相关内容

热门资讯

安卓系统为什么没网络,探究原因... 手机没网络,这可真是让人头疼的小麻烦!你有没有遇到过这种情况:手机屏幕上显示着“无网络连接”,而你明...
安卓苹果换系统安装教程,安卓与... 亲爱的手机控们,是不是觉得手机用久了,系统卡得像蜗牛爬?别急,今天就来教你怎么给安卓和苹果手机换上全...
魅族安卓系统下载软件,尽享智能... 你有没有发现,最近手机圈里又掀起了一股热潮?没错,就是魅族的新款手机!这款手机不仅外观时尚,性能强大...
平板电脑安卓系统12墨,平板电... 亲爱的读者们,你是否也和我一样,对科技新品的到来充满期待?今天,我要和你聊聊一款让人眼前一亮的新品—...
荣耀畅玩刷安卓系统,解锁更多可... 你有没有想过,你的荣耀畅玩手机,其实可以焕发第二春呢?没错,就是刷上全新的安卓系统!想象你的手机瞬间...
为什么安卓系统老是卡机,性能瓶... 手机卡顿真是让人头疼!尤其是安卓系统,有时候用着用着就突然卡住了,让人忍不住想摔手机。那么,为什么安...
哪款盒子是安卓系统,智能娱乐新... 你有没有想过,在这个智能设备横行的时代,哪款盒子是安卓系统最让人心动呢?安卓系统以其开放性和强大的兼...
安卓Q删除系统文件,安全操作与... 亲爱的安卓用户们,你是否曾在使用安卓手机时,不小心误删了重要的系统文件,心里直发慌?别担心,今天就来...
安卓12系统怎么下载谷歌,安卓... 你有没有听说安卓12系统已经发布了?是不是也想赶紧升级体验一下新系统的魅力呢?不过,别急,升级之前你...
安卓系统怎么清除后台,安卓系统... 手机后台程序太多,是不是感觉手机越来越卡?别急,今天就来教你怎么轻松清除安卓系统的后台程序,让你的手...
ios和安卓重置系统,轻松恢复... 手机用久了是不是感觉卡得要命?别急,今天就来给你揭秘如何给iOS和安卓手机来个彻底的重置,让它焕发新...
华为的手机系统与安卓,融合与创... 亲爱的读者们,你是否曾好奇过,为什么华为的手机系统能在众多安卓手机中独树一帜?今天,就让我们一起揭开...
安卓系统如何加通知声音,安卓系... 你有没有发现,手机上的通知声音有时候就像是个小闹钟,总是不请自来地提醒你各种信息。不过,有时候这个“...
安卓系统怎么锁定主屏,安卓系统... 你是不是也和我一样,手机里藏着不少小秘密,不想让别人轻易窥探呢?别急,今天就来教你怎么给安卓手机的主...
安卓系统激活提示谷歌,谷歌助你... 你刚刚入手了一台全新的安卓手机,是不是兴奋得手舞足蹈?不过,别急着高兴,激活手机之前,可别忘了谷歌的...
缤越导航安卓系统,智能出行新体... 你有没有发现,现在汽车导航系统越来越智能了?这不,缤越导航安卓系统就让我眼前一亮。想象坐在车里,手指...
安卓系统好的阅读软件,精选阅读... 你有没有发现,手机里装了那么多应用,阅读软件可是占据了我们日常使用时间的大头呢!安卓系统上的阅读软件...
统信安卓系统下载,下载与体验新... 你有没有想过,手机系统也能像换衣服一样随心所欲地换?没错,今天就要给你揭秘一个超级实用的秘密——统信...
华为新系统鸿蒙安卓,华为安卓融... 你知道吗?最近科技圈可是炸开了锅,华为的新操作系统鸿蒙系统,竟然和安卓系统来了个亲密接触!这可不是一...
安卓系统拍证件照,轻松搞定 你有没有发现,现在拍照已经成为我们生活中不可或缺的一部分?无论是记录生活点滴,还是办理各种证件,拍照...