客户端相关代码的编写
功能:
1:解析参数,自动识别参数(类似于Linux命令)
2:服务器端的IP地址和端口号以及向服务器端发送数据的时间由开始运行时的参数决定
3:获取树莓派不同序列号下的温度
4:向服务器以字符串的形式发送数据,数据包括温度,时间,序列号
5:与服务器端的连接中,若服务器断开连接,客户端将不断尝试连接,并将获取的数据保存到sqlite3数据库中
6:重新连接后将数据库中的数据发送到服务器并删除相关数据
7:拥有日志系统,将记录程序执行情况以及错误信息等到当前目录下的log文件中
8:日志系统拥有回滚功能,超过一定时间自动删除相关日志数据
学习编写中遇到的问题或难点
1:判断客户端与服务器端的连接情况
2:发送过程数据粘包
3:数据库的安装与后期的编译(我是在无root与sudo权限下安装)
4,makefile的编写
5,日志系统的编写
主程序内容:main.c如下
#include <stdio.h>
#include <errno.h>
#include <getopt.h>
#include <stdlib.h>
#include "fun.h"
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <linux/tcp.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sqlite3.h>
#include "logger.h"
int main(int argc,char **argv)
{
int ch;
int fd=-1;
float temp;
char tempbuf[64];
char Se_nub[128];
struct tm *localTime;
char timebuf[128];
struct Constants constants;
struct tcp_info info;
int len = sizeof(info);
int count=1;
char logtime_name[128];
time_t t=time(NULL);
log_roll();
snprintf(logtime_name,sizeof(logtime_name),"./log/%ld.log",t);
log_init(logtime_name, LOG_DEBUG);
if(argc!=7)
{
printf("sorry,incorrect input format\n");
print_help(argv[0]);
log_message(LOG_CRITICAL, __FILE__,__LINE__,"error:incorrect input format");
return -1;
}
//将main的参数传入到结构体constants里,并分析对应作用
ch=Getdatafrommain(argc,argv,&constants);
if(ch<0)
{
printf("get data from main failed\n");
log_message(LOG_CRITICAL,__FILE__,__LINE__, "error:Get argument failed");
return -1;
}
GET_data((char*)constants.servip,(int)constants.port);
//启动成功
log_message(LOG_INFO,__FILE__,__LINE__, "Program started successfully");
//连接服务器端
fd=MYconnect(constants.servip,constants.port);
if(fd<0)
{
printf("MYconnect is failure and try again now...\n");
while(fd<0)
{
fd=MYconnect(constants.servip,constants.port);
log_message(LOG_ERROR,__FILE__,__LINE__,"Can not connect to server and try [%d] time on 10s",count);
count++;
sleep(10);
}
}
while(1)
{
memset(tempbuf,0,sizeof(tempbuf));
if(Get_temp(&temp,Se_nub)<0)//获取温度和序列号
{
printf("get temp failed\n");
log_message(LOG_ERROR, __FILE__,__LINE__,"Can't get temp");
return -2;
}
localTime=Get_nowtime();//获取当前时间
snprintf(tempbuf,sizeof(tempbuf),"%f",temp);//将float类型的温度转换为字符型
snprintf(timebuf,sizeof(timebuf),"%04d-%02d-%02d %02d:%02d:%02d\n",localTime->tm_year + 1900, localTime->tm_mon + 1, localTime->tm_mday,localTime->tm_hour, localTime->tm_min, localTime->tm_sec);//将时间转换为字符型并保持到timebuf里
//实时监控客户端与服务器端的连接情况
getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *) & len);
if((info.tcpi_state == 1))
{
log_message(LOG_INFO,__FILE__,__LINE__, "has to send data");
printf("Normal connecttion\n");
ch=Query_and_Send(fd);
if(ch==-2)
{
printf("There is no data in sqlite\n");
log_message(LOG_INFO,__FILE__,__LINE__ ,"This time no data in sqlite");
}
Send_data(tempbuf,fd,Se_nub,timebuf);//发送数据,温度,序列号,时间
}
else
{
close(fd);
ch=Save_data(tempbuf,Se_nub,timebuf);
if(!ch)
{
printf("Save data failed\n");
log_message(LOG_ERROR, __FILE__,__LINE__,"Save data failed");
return -1;
}
printf("socket disconnected,and now try to connect......\n");
if((fd=MYconnect(constants.servip,constants.port))<0)
{
printf("connect failed,try.....\n");
log_message(LOG_ERROR, __FILE__,__LINE__,"conecet failed in while (first is successfuly)");
}
}
sleep(constants.time);
}
log_close();
return 0;
}
头文件内容(.h)文件
#ifndef FUN
#define FUN
void print_help(char* progname);
int MYconnect(char *progname,int port);
int Get_temp(float *temp,char* Se_nub);
int Send_data(char *buf,int fd,char *Se_nub,char* timebuf);
struct tm * Get_nowtime();
struct Constants {
int port;
int time;
char *servip;
char *help;
};
int Getdatafrommain(int argc,char* argv[],struct Constants *constants);
int Save_data(char *tempbuf,char* Se_nub,char *timebuf);
int Foundsql(void);
static int callback(void *data, int argc, char **argv, char **azColName) ;
int Query_and_Send();
#endif
相关代码也可以去我的仓库里看看yangjian/atest
后期也会发布修改版