Part1 客户端

一、客户端功能要求

1、树莓派上运行socket客户端程序,每隔30秒以字符串“ID/时间/温度”形式上报 采样温度,其中ID为树莓派的编号,便于服务器端区别是哪个树莓派客户端,如“RPI0001/2019-01-05 11:40:30/30.0C”;
2、通过命令行参数指定服务器IP地址和端口以及间隔采样时间;
3、程序放到后台运行,并通过syslog记录程序的运行出错、调试日志;
4、程序能够捕捉kill信号正常退出;

二、功能分析

1、建立socket通信,此处编写一个connect_server()函数,与server进行connect;,使用snprintf()函数进行格式化字符串,以达到指定输出格式;为了获取时间和温度样本,此处分别编写temperper_get()函数和time_get()函数。
2、通过调用getopt_long()函数进行命令行参数解析,并编写打印帮助信息函数print_usage()函数。
3、要是程序后台运行,即须调用守护进程deamon()函数,并与之配合建立log日志系统。
4、捕捉信号,即须安装相关信号,调用signal()函数,并编写相应回调函数sig_stop(),使程序正常退出

三、模块代码

1、连接服务器建立通信模块——connect_server.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>int connect_server(int port, char *ser_ip);int connect_server(int port, char *ser_ip)
{int                      con_fd = -1; struct sockaddr_in       ser_addr; //创建socket_fdcon_fd = socket(AF_INET, SOCK_STREAM, 0); if (con_fd < 0) { printf("Creat socket failure:%s\n",strerror(errno)); return -2; } //设置服务器端IP地址及端口信息memset(&ser_addr, 0, sizeof(ser_addr));    //ser_addr结构体变量占用内存区域清零ser_addr.sin_family = AF_INET;              //设定协议族为AF_INET,即使用ipv4(32位)与端口号(16位)的组合ser_addr.sin_port = htons(port);            //调用htons()函数,将端口号由主机字节序转变成网络字节序inet_aton(ser_ip, &ser_addr.sin_addr);       //将目前字符串形式的IP地址转变成一个32位的网络序列的IP地址//与服务器端建立连接,并判断是否成功连接//ipv4对应sockaddr_in类型,此时应进行强制类型转换为通用套接字sockaddr类型if (connect(con_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr)) < 0) { printf("Connect server failure:%s\n", strerror(errno)); return -3; } //连接成功,打印相关信息printf("Establish the connection with server successfully\n");//返回客户端创建的socket_fdreturn con_fd;
}

2、温度(ds18b20数字温度传感器)采样模块——temperper_get.c

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>int temperper_get(float *temper);int temperper_get(float *temper)
{int              fd = -1;int              found = 0;char             f_name[32];char             cache[512];char             *ptr = NULL;char             path[128]="/sys/bus/w1/devices/";DIR              *dirp = NULL;struct dirent    *direntp = NULL;//打开温度传感器设备文件夹dirp = opendir(path);   if(dirp == NULL) { printf("open folder failure: %s\n", strerror(errno)); return 0;}//查找温度传感器对应文件夹while ((direntp = readdir(dirp)) != NULL) {if (strstr(direntp->d_name, "28-")) {strncpy(f_name, direntp->d_name, sizeof(f_name)); found = 1;      //设置found为1,即代表找到相应文件夹} }closedir(dirp);         //关闭opendir()函数打开的文件夹//found == 0;即表明未检索到目的文件夹if (!found) { printf("Can not find the folder\n"); return 0; } //找到相应文件夹后,切换至该文件夹下以获取温度数据strncat(path, f_name, sizeof(path)-strlen(path));      //将文件夹名连接到path路径后strncat(path, "/w1_slave", sizeof(path)-strlen(path));   //将设备文件夹下存放温度的文件连接在path路径后//打开存放温度数据的文件if ((fd = open(path, O_RDONLY)) < 0) { printf("open file failure: %s\n", strerror(errno)); return 0; } //对定义buffer进行清零操作,并读进文件内容memset(cache, 0, sizeof(cache)); if (read(fd, cache, sizeof(cache)) < 0) {printf("Read data failure: %s\n", strerror(errno)); return 0;} //利用strstr(0函数进行字符串查找,目的是找到相应温度数值ptr = strstr(cache, "t=");if (!ptr) {printf("Can not find \"t=\"!\n");return 0;} //ptr指针后移两个字符单位(“t= ”),其后即为温度数据ptr += 2;*temper = atof(ptr)/1000;    //将以字符串形式存储的温度数据转换成浮点数close(fd);                    //关闭open()打开文件时创建的文件描述符return 0;
}

3、时间获取模块——time_get.c

#include <time.h>
#include <stdio.h>void time_get(char *date_time);void time_get(char *date_time)
{time_t            timep;struct tm         *p;      //p为一个指向tm结构体类型的指针time(&timep);             //获得time_t结构的时间,UTC时间(在计算机中看到的UTC时间都是从1970年01月01日 0:00:00开始计算秒数的)p = gmtime(&timep);            //gmtime()函数将时间和日期转换成格林威治(GMT)时间//调用snprintf(),格式化字符串,输出指定时间格式snprintf(date_time, 32, "%d-%d-%d %d:%d:%d", 1900+p->tm_year,1+p->tm_mon, p->tm_mday, (p->tm_hour + 8), p->tm_min, p->tm_sec);return ;
}

4、自定义头文件“header.h”

//“header.h”
void print_usage(char *progname);               //print_usage()函数声明;
void time_get(char *date_time);                 //time_get函数声明;
int temperper_get(float *temper);               //temperper_get函数声明;
int connect_server(int port, char *ser_ip);     //connect_server函数声明;

5、main函数——monitor_tem.c

#include <stdio.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <syslog.h>
#include <time.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <getopt.h>
#include <dirent.h>
#include "header.h"void sig_stop(int signum);             //目的是配合信号使用,将g_stop设置为1,使程序终止int g_stop = 0;int main(int argc, char *argv[])
{int                      rv = -1;int                      daemon_run;int                      opt;int                      idx;int                      S_time;int                      port;int                      log_fd;int                      sock_fd = -1;char                     *ser_ip;char                     buf[512];char                     date_time[32];char                     *id = "Mastema";        //定义设备ID,此处为自己随便设定char                     *hostname;float                    temper;struct hostent           *getname = NULL;/*命令行参数解析:daemon:程序后台运行;time:待设定的上报时间间隔;name:设置待连服务器域名或者IP;port:设置待连服务器端口;help:命令行参数输入错误时,打印帮助信息。*/struct option            opts[] = {{"daemon",no_argument,NULL,'d'},{"time",required_argument,NULL,'t'},{"name",required_argument,NULL,'n'},{"port",required_argument,NULL,'p'},{"help",no_argument,NULL,'h'},{NULL,0,NULL,0}    }; while ((opt = getopt_long(argc,argv,"dt:n:p:h",opts,&idx)) != -1){switch(opt){case 'd':daemon_run = 1;             //daemon_run为1,设定deamon()函数执行break;case 't': S_time = atoi(optarg);       //将命令行参数中的时间(字符串形式)转换成整型break;case 'n':hostname = optarg;            //将命令行参数的域名或IP地址赋值给hostnamebreak;case 'p':port = atoi(optarg);       //将命令行参数中的端口号(字符串形式)转换成整型break;case 'h':print_usage(argv[0]);         //如有“-h”参数,则调用print_usage()函数打印帮助信息return 0;}}if (!port || !hostname)                //判断是否输入端口号或域名(IP地址){print_usage(argv[0]);return 0;}//DNS域名解析,将域名解析成服务器的公网IP地址,并将相关信息保存在getname指向的结构体中getname = gethostbyname(hostname); if (getname == NULL){printf("Get hostname failure : %s\n", strerror(h_errno));return 0;}//将保存在hostent结构体内的服务器IP地址(32位的网络字节序)转换成相应的点分十进制形式IP地址,并返回的char*指针赋值给给ser_ipser_ip = inet_ntoa(*(struct in_addr *)getname->h_addr);if (ser_ip == NULL){printf("Get ser_ip failure : %s\n", strerror(errno));return 0;}printf("ser_ip[%s]\n", ser_ip);//守护进程函数if (daemon_run)         {printf("Program %s is running at the background now\n", argv[0]);//创建日志系统,程序后台运行后,将所有打印信息打印在日志文件中log_fd = open("receive_temper.log",  O_CREAT|O_RDWR, 0666);if (log_fd < 0){printf("Open the logfile failure : %s\n", strerror(errno));return 0;}//标准输出及标准出错重定向,重定向至日志文件dup2(log_fd, STDOUT_FILENO);dup2(log_fd, STDERR_FILENO);//设置deamon()函数两个参数为1//即保持当前目录不变,并且使标准输出及标准出错重定向仍打印输出信息,只不过此时打印信息将会全部打印至日志文件中!if ((daemon(1, 1)) < 0){printf("Deamon failure : %s\n", strerror(errno));return 0;}}//安装信号signal(SIGUSR1, sig_stop);        //捕捉到kill信号后,调用sig_stop(),将g_stop设置为1,程序结束signal(SIGPIPE, SIG_IGN);       //屏蔽SIGPIPE信号,因为当服务器主动断开socket连接后,客户端会接收到SIGPIPE信号,自动退出。为达到服务器主动断开socket连接后,客户端重连服务器端的目的,这里必须屏蔽掉SIGPIPE信号//对buf栈区内存执行清零操作memset(buf, 0, sizeof(buf));while (!g_stop){if ((temperper_get(&temper)) < 0)            //调用temperper_get()函数,获取温度{printf("Get temperature failure!\n");continue;}time_get(date_time);     //调用time_get()函数,获取时间//格式化字符串输出,形式为功能指定形式snprintf(buf, sizeof(buf),"%s/%s/%.1f%c", id, date_time, temper, 'C');//未能连接到服务器if (sock_fd < 0){//调用connect_server()函数,尝试连接服务器if ((sock_fd = connect_server(port, ser_ip)) < 0){printf("Now establish the connection with server again!\n");printf("\n");continue;}}//成功连接服务器,开始传输数据if (sock_fd >= 0) {//向buf中写数据,并通过pipe传输给服务器端rv = write(sock_fd, buf, sizeof(buf));if (rv >= 0){printf("Send messege to server successfully!\n");}else{printf("Send messege to server failure : %s\n", strerror(errno));close(sock_fd); sock_fd = -1;      //上传数据失败,将sock_fd重设为-1,下次循环重新连接服务器}}//程序休眠S_time,达到一定时间间隔后,将数据上报服务器的目的sleep(S_time);}close(sock_fd);//syslog(LOG_NOTICE, "Program stop running\n");//closelog();return 0;
}//打印帮助信息
void print_usage(char *progname)
{printf("-d(--daemon):let program run in the background.\n");printf("-p(--port):enter server port.\n");printf("-h(--help):print this help information.\n");printf("-t(--time):enter the sampling interval time.\n");printf("-i(--ip):enter the server's ipaddr.\n");return ;
}//捕捉到相应信号后,设置g_stop为1
void sig_stop(int signum)
{if (SIGUSR1 == signum){g_stop = 1;        }return ;
}

温度上报实时监控项目——客户端相关推荐

  1. 温度上报实时监控项目——服务器端

    Part2 服务器 一.服务器端功能要求 1, 服务器程序运行在PC端服务器(需要开端口)或同一个树莓派上(不需要开端口): 2, 通过命令行指定监听的端口: 3, 程序放到后台运行,并通过syslo ...

  2. android 与后台实时视频,Android实时监控项目第四篇:后台线程发送预览帧视频数据...

    还记得上篇提到的setPreviewCallback(Camera.PreviewCallback cb)函数吗?我们在开始预览帧视频之前,调用的它,这里要注意其内部的Camera.PreviewCa ...

  3. RTSP服务器综合项目:rtsp实时监控

    点击 RTSP实时监控项目:项目索引,回到目录. 目标:添加摄像头采集编码和码流队列管理,完成实时监控功能. protocol.h添加采集相关设置 // RTSP服务器测试 #define RTSP_ ...

  4. Sentinel(十二)之实时监控

    转载自  实时监控 Sentinel 提供对所有资源的实时监控.如果需要实时监控,客户端需引入以下依赖(以 Maven 为例): <dependency><groupId>co ...

  5. 利用爬虫实现全国疫情实时监控(手机版)

    文中分为六个部分,介绍如何用python等工具实现定时爬虫,完成全国疫情实时监控项目.主要用到工具:PyCharm (代码编写),python(版本为3.7.6,后台代码结构设计),Hbuilder ...

  6. 快速学习-sentinel实时监控

    9.实时监控 Sentinel 提供对所有资源的实时监控.如果需要实时监控,客户端需引入以下依赖(以Maven 为例): <dependency><groupId>com.al ...

  7. 温度实时监控上报(客户端)

    温度实时监控上报 客户端功能 1.树莓派上运行socket客户端程序,每隔30秒以字符串"ID/时间/温度"形式上报 采样温度,其中ID为树莓派的编号,便于服务器端区别是哪个树莓派 ...

  8. CAT 实时监控与项目集成

    一. CAT概要 1.CAT是什么? CAT(Central Application Tracking)是大众点评开源的一套基于Java开发的实时应用监控平台,提供了全面的监控服务和业务决策支持.主要 ...

  9. 大数据实战项目------中国移动运营分析实时监控平台 || 项目需求实现(文章最后有数据文件)

    1.业务概况(显示总订单量.订单成功量.总金额.花费时间) 2.业务详细概述(每小时的充值订单量.每小时的充值成功订单量) 3.业务质量(每个省份的充值成功订单量) 4.实时统计每分钟的充值金额和订单 ...

最新文章

  1. JAVA I/O系统。
  2. linux 命令详解 十一
  3. 沟通管理计划3个过程及重点
  4. 标准库类型string的基本功能和使用
  5. 如何编写高性能的C#代码(一)
  6. eigen 列向量转矩阵_快速入门矩阵运算——开源库Eigen
  7. js过渡效果_干货 | Vue事件、过渡和制作index页面
  8. CSS类选择器选择多个类用逗号隔开
  9. 华容道(java版)
  10. 浏览器渲染机制面试_面试 09-01.浏览器渲染机制
  11. 漫画:什么是基数排序?
  12. paip.ecshop邮件模板修改一个密码找回 一个留言回复
  13. 沪深股票历史数据下载,股票历史交易数据下载
  14. 那些年关于JavaWeb的点点滴滴,你想看的这里全都有噢~
  15. 【产品】 产品设计:工业设计(ID设计)系列软件介绍:平面设计、建模和3D渲染
  16. Win11的文件资源管理器如何显示预览窗格?
  17. diadem2017注册机 ni_NI DIAdem2017下载
  18. PS制作透明图片png格式
  19. 论文笔记7 --(ReID)Video-based Person Re-identification via Self Paced Weighting
  20. PC端页面适应不同的分辨率的方法

热门文章

  1. 2016银行卡BIN
  2. sqlsever2000和mysql_数据库迁移 SQLServer2000到MYsql
  3. thor修改html,f4thor修改工具[thor规则解包打包] | 贝贝吧
  4. 个人微信ipad二次开发
  5. 【定位原理揭秘第二期】GPS定位实现原理解析
  6. matlab 旋转向量和旋转矩阵互转
  7. [COI2007] Sabor
  8. STM32F103C8T6核心板控制器下,通过电路搭建实现LED灯轮流闪烁的实验操作
  9. 亲身经历3家1000人互联网公司,分享 25 条潜规则!
  10. ad20如何画出pcb板大小_资深大咖SMT硬件工程师手把手教你分清多层板及PCB各层中的含义,给力!...