linux下用C语言实现HTTP客户端-获取网络时间-设置linux系统时间

12 篇文章 1 订阅
8 篇文章 0 订阅

分析

这里是用一些简单的代码实现http客户端。
http是以tcp为基础的,所以跟之前的写的tcp/ip客户端服务器可以说是非常相似。

1.通过调用socket创建一个socket fd

int sockfd = -1;
	sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(-1 == sockfd)
	{
		perror("socket");
		return -1;
	}
	printf("socket\n打开文件描述符成功\n");

2.通过connect去与服务器连接

//第二步 通过connect连接服务器
	cliaddr.sin_family = AF_INET; //设置地址族为ipv4
	cliaddr.sin_port = htons(SERPORT);//设置端口号 大于5000的端口是其他服务器预留的,还要设置字节序
	cliaddr.sin_addr.s_addr = inet_addr(SERADDR);	// 设置IP地址
	ret = connect(sockfd,(const struct sockaddr*)&cliaddr,sizeof(cliaddr));
	if (ret < 0)
	{
		perror("connect");
		return -1;
	}
	printf("与服务器connect成功\n");

重点是这里的SERPORT SERADDR
http默认端口号是80,所以宏定义的时候定义SERPORT为80
SERADDR 是通过ping百度的的网址获得的一个ip地址,不同时间段ping获得的ip地址可能不一样,要自己修改一下(不过我这3天测试过来都能ping通)

3.关键点,HTTP的消息格式

char sendbuf[1024] = {0};//HTTP协议的语法格式
	 sprintf(sendbuf, "GET / HTTP/1.1\r\n"
	 "Host:www.baidu.com\r\n"
	 "User-Agent:whatever\r\n"
	 "Accept-Type:*/*\r\n"
	 "Connection:close\r\n"
	 "X-Power:XXX\r\n"
	 "\r\n"); 				

格式一定不能出错,最后的\r\n一定不能省略,
GET是HTTP的获取方法,随后的’/’表示获取根目录下的默认页面,”HTTP/1.1”标明了协议及版本
Host是指明获取主机,消息格式里面的CRLF就是\r\n,所以不能省略
后面User-Agent和Accept-Type等等这些没有详细去了解。

之前测试的时候就是少了最后一行的\r\n导致一直请求无法通过,服务器识别不了。

4.发送信息

	ret  = send(sockfd,sendbuf,strlen(sendbuf),MSG_NOSIGNAL);
	if (-1 == ret)
	{
		perror("send");
		return -1;
	}

5.接收信息

	num = recv(sockfd, recvBuf, sizeof(recvBuf),0);
	if(-1 == num)
	{
		perror("recv msg fail\n");
		return -1;
	}
	//printf("the msg I recv is \n%s\n",recvBuf);
	printf("接收信息接收成功...\n");

到此为止5步大概就能完成http客户端的构建,大体上跟tcp/ip服务器90%相似的,就是需要自己构建一个发送报文,HTTP除了GET还有POST等方法,想了解更多需要深入学习,现在都是https了,比http更加安全,s代表security
下面是获取到的信息

HTTP/1.1 200 OK
Bdpagetype: 1
Bdqid: 0x840bf5c20006490e
Cache-Control: private
Content-Type: text/html;charset=utf-8
Date: Sun, 24 Jan 2021 12:44:31 GMT
Expires: Sun, 24 Jan 2021 12:44:08 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Server: BWS/1.1
Set-Cookie: BAIDUID=BFC73282CA79EF917ECCB46576FD406E:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BIDUPSID=BFC73282CA79EF917ECCB46576FD406E; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: PSTM=1611492271; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BAIDUID=BFC73282CA79EF91139A6391C6B1E4B4:FG=1; max-age=31536000; expires=Mon, 24-Jan-22 12:44:31 GMT; domain=.baidu.com; path=/; version=1; comment=bd
Set-Cookie: BDSVRTM=0; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=33425_33429_33258_33344_33284_33398_33334_33319; path=/; domain=.baidu.com
Traceid: 161149227106972684909514968851323177230
Vary: Accept-Encoding
Vary: Accept-Encoding
X-Ua-Compatible: IE=Edge,chrome=1
Connection: close
Transfer-Encoding: chunked

b46
<!DOCTYPE html><!--STATUS OK-->


    <html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta content="always" name="re                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

如何获取时间?

之前通过GET获取到的信息里面,有一截有用的信息

Date: Sun, 24 Jan 2021 12:44:31 GMT

每一次访问都会收回一包信息,里面就包含了时间信息。
开发板每次关机都不会保存时间,每次开机都要自己设定时间,如果通过http来获取到时间信息然后通过调用api去设置时间,就可以实现每次开机自动更新时间。(不过其实可以下载ntpclient来自动同步时间的实现嵌入式linux自动同步网络时间—NTP )
但是既然有了这样的想法为何不去尝试一下呢?

1.创建一个文件,用来存储信息

//创建一个文件,用来存储信息
	FILE *fp = NULL;
	fp = fopen(PATHNAME,"w+");
	if(NULL == fp)
	{
		perror("fopen");
		return -1;
	}
	printf("存储信息文件创建成功\n");
	//存储信息
	fwrite(recvBuf,sizeof(recvBuf),1,fp);
	printf("信息存储成功\n");
	//关闭文件
	fclose(fp);

2.重新打开文件,抓取时间Date

为什么要重新打开这个文件呢?
其实之前我是想着直接从保存好的文件里面抓取的,但是发现抓不到信息,都是空白的,所以我在想是不是要fwrite之后fclose关闭了才是真正的把信息保存下来了?
还是说fwrite是缓冲形式的,要fflush之后才行呢?
我尝试了前者,先fclose再重新打开。

	
	//重新打开文件,抓取时间Date
	fp = fopen(PATHNAME,"r");
	if(NULL == fp)
	{
		perror("fopen");
		return -1;
	}
	printf("重新打开文件,抓取时间Date\n");
	
	char file_str[256];
	int line = 0;	
	char target_buf[256] = {0};
	while(fgets(file_str,sizeof(file_str),fp))
	{
		line++;
		
		if(strstr(file_str,"Date:"))
		{
			printf("file_str %s\n",file_str);
			strcpy(target_buf,file_str);
			printf("target_buf %s\n",target_buf);
		}
	}
	printf("strlen of target_buf is %ld\n",strlen(target_buf));

使用fgets的方法是 从网上找的,具体网址忘记了
这里的设计思路是通过fgets一行一行地找,每找到一行就通过使用strstr去找“Date:”这个字符串,如果找到了的话,就把当前的这一段字符串截取下来,存放到target_buf里面,下一步再进行解析。

3.字符串解析

代码没有截全,展示用

/***要解析的字符串Date: Sun, 24 Jan 2021 14:33:55 GMT **/
	//找月份
	char month[12][5] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sept","Oct","Nov","Dec"};
	for(i = 0;i < 12; i++)
	{
		month_ptr = strstr(target_buf,month[i]);
		if(NULL != month_ptr)
		{
			break;
		}
	}
	i_month = i + 1 ;

在目标字符串里面通过一个for循环,还有strstr去遍历一次月份,找到之后就跳出for循环,这时候的月份数字是从0开始的,所以还得+1才是确切的几月

找星期
//星期
	for(j = 0;j < 7; j++)
	{
		week_ptr = strstr(target_buf,week[j]);
		if(NULL != week_ptr)
		{
			break;
		}
	}
	k = 0;
	while(k<3)
	{
		r_week[k] = *week_ptr;
		week_ptr++;
		k++;
	}
	printf("real week is %s\n",r_week);

思路跟找月份是一样的,这里为了保存星期的值,定义了一个指week_ptr和数组r_week[5]
保存星期几的值的思路是
strstr找到之后会返回一个指针,指向被找目标的开头的地址,所以通过一个while循环去每次存放一个地址,然后地址+1移位。
不过其实这样做是有bug的,因为Thur是有4个位的,要移动4次,所以打印是不全面的,刚开始的时候我是想以月份的地址为基准,后面去移动指针获取时间,后面发现这样子不行,所以重新选择基准,找到了最后的GMT作为基准点

//找到"GMT",以GMT为基准计算年、日、时、分、秒
	gmt_ptr = strstr(target_buf,"GMT");
	printf("gmt is %s\n",gmt_ptr);
年月日时分秒

都是以这样的移动指针的方法去获取,然后保存

//日
	k = 0;
	temp = gmt_ptr;
	while(k<2)
	{
		r_day[k] = *(temp - 21);
		temp++;
		k++;
	}
	day = atoi(r_day);
保存时间设置时间

设置linux系统时间的格式为 date -s "xxxx-xx-xx “xx:xx:xx”
通过sprintf里面的%02d,保证了就算是个位时间也会在前面补0
通过strcat去构造一个格式
最终通过system 这个api去执行命令。

sprintf(time,"%02d-%02d-%02d %02d:%02d:%02d",year,i_month,day,hour,min,sec);//月日时分秒>10
		
	
	printf("time is %s\n",time);
	char cmd[256] = "date -s";
	
	printf("cmd is %s\n",cmd);
	strcat(cmd," \"");
	strcat(cmd,time);
	strcat(cmd,"\"");
	printf("cmd is %s\n",cmd);
	system(cmd);
使用交叉编译工具链编译到我的开发板上测试

在这里插入图片描述

在这里插入图片描述

当然,前提条件是开发板能上网,关于开发板上网可以去看之前的相关帖子。
还有,计算hour的时候记得要+8,因为获取的是GMT时间,不是北京时间。

参考资料

wpa_supplicant移植与使用
用C语言实现一个简单的HTTP客户端(HTTP Client)
Windows下C语言实现HTTP客户端
C语言在文件中查找字符串是否在某行,显示行号和该行内容

源码v1

#include <stdio.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

#define SERPORT		80						//服务器开放的端口号
#define SERADDR		"183.232.231.174"   	//服务器开放的IP地址
#define PATHNAME 	"./msg.txt"
int main(void)
{
	struct sockaddr_in cliaddr = {0};
	int ret = -1;
	//第一步,先socket打开文件描述符
	int sockfd = -1;
	sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(-1 == sockfd)
	{
		perror("socket");
		return -1;
	}
	printf("socket\n打开文件描述符成功\n");
	
	//第二步 通过connect连接服务器
	cliaddr.sin_family = AF_INET; //设置地址族为ipv4
	cliaddr.sin_port = htons(SERPORT);//设置端口号 大于5000的端口是其他服务器预留的,还要设置字节序
	cliaddr.sin_addr.s_addr = inet_addr(SERADDR);	// 设置IP地址
	ret = connect(sockfd,(const struct sockaddr*)&cliaddr,sizeof(cliaddr));
	if (ret < 0)
	{
		perror("connect");
		return -1;
	}
	printf("与服务器connect成功\n");

	char recvBuf[1024 * 2] = {0};
	int num = -1;
	char sendbuf[1024] = {0};//HTTP协议的语法格式
	 sprintf(sendbuf, "GET / HTTP/1.1\r\n"
	 "Host:www.baidu.com\r\n"
	 "User-Agent:whatever\r\n"
	 "Accept-Type:*/*\r\n"
	 "Connection:close\r\n"
	 "X-Power:XXX\r\n"
	 "\r\n");
    
	//printf("sendbuf is : %s\nn",sendbuf);
	
	ret  = send(sockfd,sendbuf,strlen(sendbuf),MSG_NOSIGNAL);
	if (-1 == ret)
	{
		perror("send");
		return -1;
	}

	printf("正在接收信息...\n");
	
	num = recv(sockfd, recvBuf, sizeof(recvBuf),0);
	if(-1 == num)
	{
		perror("recv msg fail\n");
		return -1;
	}
	//printf("the msg I recv is \n%s\n",recvBuf);
	printf("接收信息接收成功...\n");
	
	//创建一个文件,用来存储信息
	FILE *fp = NULL;
	fp = fopen(PATHNAME,"w+");
	if(NULL == fp)
	{
		perror("fopen");
		return -1;
	}
	printf("存储信息文件创建成功\n");
	//存储信息
	fwrite(recvBuf,sizeof(recvBuf),1,fp);
	printf("信息存储成功\n");
	//关闭文件
	fclose(fp);
	
	//重新打开文件,抓取时间Date
	fp = fopen(PATHNAME,"r");
	if(NULL == fp)
	{
		perror("fopen");
		return -1;
	}
	printf("重新打开文件,抓取时间Date\n");
	
	char file_str[256];
	int line = 0;	
	char target_buf[256] = {0};
	while(fgets(file_str,sizeof(file_str),fp))
	{
		line++;
		
		if(strstr(file_str,"Date:"))
		{
			printf("file_str %s\n",file_str);
			strcpy(target_buf,file_str);
			printf("target_buf %s\n",target_buf);
		}
	}
	printf("strlen of target_buf is %ld\n",strlen(target_buf));
	
	char month[12][5] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sept","Oct","Nov","Dec"};
	char week[7][5] = {"Mon","Thu","Wed","Thur","Fri","Sat","Sun"};
	char r_year[5] = {0};
	char r_month[5] = {0};
	char r_week[5] = {0};
	char r_day[3] = {0};
	char r_hour[3] = {0};
	char r_min[3] = {0};
	char r_sec[3] = {0};
	char *temp;
	int i,j,k;
	int sec, min ,hour, year ,day,i_month;
	char *month_ptr = NULL,*week_ptr = NULL,*gmt_ptr = NULL;
	char time[32] = {0};
	/***要解析的字符串Date: Sun, 24 Jan 2021 14:33:55 GMT **/
	//找月份
	for(i = 0;i < 12; i++)
	{
		month_ptr = strstr(target_buf,month[i]);
		if(NULL != month_ptr)
		{
			break;
		}
	}
	i_month = i + 1 ;
	k = 0;
	temp = month_ptr;
	while(k<3)
	{
		r_month[k] = *temp;
		temp++;
		k++;
	}
	//printf("real month is %s\n",r_month);
	//printf("real month is %d\n",i_month);
	//星期
	for(j = 0;j < 7; j++)
	{
		week_ptr = strstr(target_buf,week[j]);
		if(NULL != week_ptr)
		{
			break;
		}
	}
	k = 0;
	while(k<3)
	{
		r_week[k] = *week_ptr;
		week_ptr++;
		k++;
	}
	//printf("real week is %s\n",r_week);
	
	//找到"GMT",以GMT为基准计算年、日、时、分、秒
	gmt_ptr = strstr(target_buf,"GMT");
	printf("gmt is %s\n",gmt_ptr);
	
	//日
	k = 0;
	temp = gmt_ptr;
	while(k<2)
	{
		r_day[k] = *(temp - 21);
		temp++;
		k++;
	}
	day = atoi(r_day);
	//printf("real day is %d\n",day);
	
	//年
	k = 0;
	temp = gmt_ptr;
	temp = temp - 14;
	while(k<4)
	{
		r_year[k] = *temp;
		temp++;
		k++;
	}
	year = atoi(r_year);
	//printf("real year is %d\n",year);
	
	//时
	k = 0;
	temp = gmt_ptr;
	temp = temp - 9;
	while(k<2)
	{
		r_hour[k] = *temp;
		temp++;
		k++;
	}
	hour = atoi(r_hour) + 8; //东八区
	if(hour >= 24)
	{
		hour = hour - 24;
	}
		
	//printf("real hour is %d\n",hour);
	
	//分
	k = 0;
	temp = gmt_ptr;
	temp = temp - 6;
	while(k<2)
	{
		r_min[k] = *temp;
		temp++;
		k++;
	}
	min = atoi(r_min);
	//printf("real min is %d\n",min);
	
	//秒
	k = 0;
	temp = gmt_ptr;
	temp = temp - 3;
	while(k<2)
	{
		r_sec[k] = *temp;
		temp++;
		k++;
	}
	sec = atoi(r_sec);
	//printf("real sec is %d\n",sec);  
	sprintf(time,"%02d-%02d-%02d %02d:%02d:%02d",year,i_month,day,hour,min,sec);//月日时分秒>10
		
	
	printf("time is %s\n",time);
	char cmd[256] = "date -s";
	
	printf("cmd is %s\n",cmd);
	strcat(cmd," \"");
	strcat(cmd,time);
	strcat(cmd,"\"");
	printf("cmd is %s\n",cmd);
	system(cmd);
	return 0;
}

源码v2

第一次写的代码在一个main函数里面,我觉得看上去是比较好理解的, 但是这样写的代码感觉比较冗余,而且不好维护等等,所以经过了一天的修改获得了第二版源码

#include <stdio.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

#define SERPORT		80						//服务器开放的端口号
#define SERADDR		"183.232.231.174"   	//服务器开放的IP地址
#define PATHNAME 	"./msg.txt"				//文件路径
//debug宏
#define DEBUG 		 
//#undef DEBUG
#ifdef DEBUG  
#define debug(format,...) printf("[debug]""File: "__FILE__", Line: %05d: "format"", __LINE__, ##__VA_ARGS__)  
#else  
#define debug(format,...)  
#endif


//全局变量
int sockfd = -1;
int ret = -1;

typedef struct msg_S
{
	char target_buf[256];
	char time[32];
}msg_S;

	//客户端函数
int client_init(void)
{
	//第一步,先socket打开文件描述符
	struct sockaddr_in cliaddr = {0};
	sockfd = socket(AF_INET,SOCK_STREAM,0);
	if(-1 == sockfd)
	{
		perror("socket");
		return -1;
	}
	debug("打开文件描述符成功\n");
	
	//第二步 通过connect连接服务器
	cliaddr.sin_family = AF_INET; //设置地址族为ipv4
	cliaddr.sin_port = htons(SERPORT);//设置端口号 
	cliaddr.sin_addr.s_addr = inet_addr(SERADDR);	//设置IP地址
	ret = connect(sockfd,(const struct sockaddr*)&cliaddr,sizeof(cliaddr));
	if (ret < 0)
	{
		perror("connect");
		return -1;
	}
	debug("与服务器connect成功\n");
}


//抓取文件
int msg_parse(msg_S *pMsg)
{
	//发送信息
	msg_S *ptarget_msg = pMsg;
	int num = -1;
	char sendbuf[1024] = {0};//HTTP协议的语法格式
	char recvBuf[1024 * 2] = {0};
	sprintf(sendbuf, "GET / HTTP/1.1\r\n"
	"Host:www.baidu.com\r\n"
	"User-Agent:whatever\r\n"
	"Accept-Type:*/*\r\n"
	"Connection:close\r\n"
	"X-Power:XXX\r\n"
	"\r\n");
    
	ret  = send(sockfd,sendbuf,strlen(sendbuf),MSG_NOSIGNAL);
	if (-1 == ret)
	{
		perror("send");
		return -1;
	}

	debug("正在接收信息...\n");
	//接收信息
	num = recv(sockfd, recvBuf, sizeof(recvBuf),0);
	if(-1 == num)
	{
		perror("recv msg fail\n");
		return -1;
	}
	//debug("the msg I recv is \n%s\n",recvBuf);
	debug("接收信息接收成功...\n");
	
	
	//创建一个文件,用来存储信息
	FILE *fp = NULL;
	fp = fopen(PATHNAME,"w+");
	if(NULL == fp)
	{
		perror("fopen");
		return -1;
	}
	debug("存储信息文件创建成功\n");
	//存储信息
	fwrite(recvBuf,sizeof(recvBuf),1,fp);
	debug("信息存储成功\n");
	//关闭文件
	fclose(fp);
	
	//抓取关键信息
	//重新打开文件
	debug("重新打开文件,抓取时间Date\n");
	char file_str[256];
	//FILE *fp = NULL;
	fp = fopen(PATHNAME,"r");
	if(NULL == fp)
	{
		perror("fopen");
		return -1;
	}
	
	//抓取时间Date
	while(fgets(file_str,sizeof(file_str),fp))
	{
		if(strstr(file_str,"Date:"))
		{
			debug("getmsg:\n%s\n",file_str);
			strcpy(ptarget_msg->target_buf,file_str);
			debug("target_buf:\n%s\n",ptarget_msg->target_buf);
		}
	}
}

	//日、年、时、分、秒解析函数
	/***要解析的字符串Date: Sun, 24 Jan 2021 14:33:55 GMT **/
	/*len:日期值的长度,比如2021-01-23 12:23:45 日 时 分 秒 的长度都是2,年的长度是4
	offset: 偏移量,例如,以GMT的G为基准,往前减3就是秒的起始地址,往前减去6就是分的起始地址
	char src[]: 用来存放年月日时分秒的字符串,最后统一用atoi转换成整型
	msg_S *pMsg:定义的一个结构体,从这里面获取target_msg,解析出GMT的首地址*/
int date_parse(const int len, const int offset , char src[], msg_S *pMsg)
{
	int k = 0;
	char *gmt_ptr = NULL;
	msg_S *ptarget_msg = pMsg;
	//找到"GMT",以GMT为基准计算年、日、时、分、秒
	gmt_ptr = strstr((*ptarget_msg).target_buf,"GMT");
	while(k < len)
	{
		src[k] = *(gmt_ptr - offset);
		gmt_ptr++;
		k++;
	}
	return atoi(src);
}

	//月份解析函数
int month_parse(msg_S *pMsg)
{
	msg_S *ptarget_msg = pMsg;
	char *month_ptr = NULL;
	int month;
	char month_arr[12][5] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sept","Oct","Nov","Dec"};	
	int i = 0;
	//找月份  不能以GMT为基准 因为thur 或者sept都是4个字节的,跟其他的3字节不一样,这样会出错的。
	for(i = 0;i < 12; i++)
	{
		month_ptr = strstr((*ptarget_msg).target_buf,month_arr[i]);
		if(NULL != month_ptr)
		{
			break;
		}
	}
	//debug("month i is %d\n",i);
	//debug("month_ptr is %s\n",month_ptr);
	month = i + 1 ;
	return month;
}

//把时间整合成一个字符串
int catenate_time(msg_S *pst_time)
{
	int sec, min ,hour, year ,day, month;
	char r_year[5] = {0};
	char r_month[5] = {0};
	char r_day[3] = {0};
	char r_hour[3] = {0};
	char r_min[3] = {0};
	char r_sec[3] = {0};
	
	msg_S *p = pst_time;
	
	/***要解析的字符串Date: Sun, 24 Jan 2021 14:33:55 GMT **/
	month = month_parse(p);				//月
	day = date_parse(2, 21, r_day, p);		//日
	year = date_parse(4, 14, r_year, p);	//年
	min = date_parse(2, 6, r_min, p);		//分
	sec = date_parse(2, 3, r_sec, p);		//秒
	hour = date_parse(2, 9, r_hour, p);	//时
	hour = hour + 8;					//时+8 北京时间
	if(hour >= 24)
		hour = hour - 24;
	sprintf(p->time,"%02d-%02d-%02d %02d:%02d:%02d",year,month,day,hour,min,sec);//格式化月日时分秒
}
//整合出设置时间的命令,然后执行命令
void func_settime(msg_S * const pst_time)
{
	msg_S *p = pst_time;
	
	debug("time is %s\n",p->time);
	char cmd[256] = "date -s";
	strcat(cmd," \"");
	strcat(cmd,p->time);
	strcat(cmd,"\"");
	debug("cmd is %s\n",cmd);
	system(cmd);
}

int main(void)
{
	msg_S st_time;
	memset(&st_time, 0, sizeof(msg_S));
	client_init();				//http 客户端
	msg_parse(&st_time);		//保存并获取信息
	catenate_time(&st_time);	//整合时间
	func_settime(&st_time);		//调用system命令去执行
	return 0;
}

总结

刚开始把v1代码修改的时候,虽然我封装了不少函数,但是弄了很多全局变量在外面,其实这样的做法是很不好的。
后面仔细推敲,根据每部分代码的作用,重新规划函数的封装,把大部分的全局变量都放在函数体里面,成为局部变量,但是还是有2个数组在外面,这时候我想起了之前看过的海思的源码,发现别人的代码很多时候传参都是通过结构体参数传参,所以我也学习模仿他们的写法:
1.定义一个结构体,里面包含我的数组
2.在main函数里面定义一个结构体变量,供给函数使用
3.当某些函数需要往结构体里面写入或者读出的时候,就调用这个结构体变量的地址,这样每次传参就只是传地址了。
4.每个调用这个地址的函数体里面,再自己定义一个结构体变量,然后把main函数里面的结构体变量的地址赋值给它,相当于进行了一个绑定,(有点类似C++的引用?)
当这个函数操作完之后自己挂掉就会释放这部分内存,不用像全局变量一样一直在占用静态存储空间。

最后,如果有写的不准确的地方欢迎指正。

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要在Linux系统下使用C语言实现MQTT客户端程序,可以按照以下步骤进行: 1. 首先,需要安装用于MQTT通信的C语言库。常见的MQTT库有Paho MQTT C库和Mosquitto MQTT C库,你可以选择其中一个进行安装。 2. 安装完成后,创建一个新的C文件,用于编写MQTT客户端程序的代码。 3. 在程序中包含MQTT库的头文件,并进行必要的初始化。例如,使用Paho MQTT C库,可以包含`"MQTTClient.h"`头文件,并通过`"MQTTClient_create()"`函数创建一个MQTT客户端实例。 4. 设置MQTT客户端连接的服务器地址和端口号。这可以通过使用`"MQTTClient_setOptions()"`函数来完成。 5. 定义一个回调函数,用于处理从MQTT服务器接收到的消息。例如,使用Paho MQTT C库,可以使用`"MessageArrived()"`函数来处理接收到的消息,并将其打印出来。 6. 使用`"MQTTClient_connect()"`函数连接到MQTT服务器。 7. 使用`"MQTTClient_subscribe()"`函数订阅你感兴趣的主题。 8. 实现发送MQTT消息的功能。可以使用`"MQTTClient_publish()"`函数发送消息到MQTT服务器。 9. 最后,使用`"MQTTClient_disconnect()"`函数断开与MQTT服务器的连接,并进行必要的资源清理。 10. 编译并运行你的程序。 总之,要在Linux系统下使用C语言实现MQTT客户端程序,你需要选择并安装一个MQTT库,创建一个新的C文件并编写相关代码,包括初始化、连接服务器、订阅主题、发送和接收消息等功能。最后,编译并运行你的程序。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值