一,首先是客户端需要实现的功能:
1, 树莓派上运行socket客户端程序,每隔30秒以字符串“ID/时间/温度”形式上报采样温度,其中ID为树莓派的编号,便于服 务器端区别是哪个树莓派客户端,如“RPI0001/2019-01-05 11:40:30/30.0C”;
2, 通过命令行参数指定服务器IP地址和端口以及间隔采样时间;
3, 程序放到后台运行,并通过syslog记录程序的运行出错、调试日志;
4, 程序能够捕捉kill信号正常退出;
二,客户端实现的流程图:
三 代码:
1,通过域名解析,将树莓派的域名解析成IP地址:
void print_usage(char *order)
{
printf("%s usages:\n",order);
printf("-I(IP):server IP\n");
intf("-p(port):server port\n");
printf("-h(help):help information\n");
exit(0);
}
int main(int argc,char **argv)
{
char *serv_IP = NULL;
int serv_port = 0;
int opt;
struct sockaddr_in serv_addr;
char buf[100];
char buf1[100];
char chip[20];
int sockfd;
int rv = -1;
int on = 1;
float temp;
int line;
struct timespec tout;
struct tm *tmp;
struct hostent *hptr;
struct option long_options[]=
{
{"IP",1,NULL,'i'},
{"port",1,NULL,'p'},
{"help",0,NULL,'h'},
{0,0,0,0}
};
mylog(argv[0],__LINE__,DEBUG,"This is debug info");
hptr = gethostbyname(argv[1]);
if(hptr != NULL)
{
printf("domian name visit.\n");
// printf("IP address1:%s\n",inet_ntoa(*(struct in_addr *)hptr->h_addr_list[1]));
serv_IP = hptr->h_addr_list[1];
printf("IP address2:%s\n",inet_ntoa(*(struct in_addr *)serv_IP));
}
else if(hptr == NULL)
{
switch(opt)
{
case 'i':
serv_IP = optarg;
break;
case 'p':
serv_port = atoi(optarg);
break;
case 'h':
print_usage(argv[0]);
break;
default:
break;
}
}
if((!serv_IP)|(!serv_port))
{
print_usage(argv[0]);
}
}
2socket函数初始化
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
{
printf("socket failed: %s\n",strerror(errno));
}
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(serv_port);
inet_aton(serv_IP,&serv_addr.sin_addr);
memset(buf,0,sizeof(buf));
printf("client is connecting serve...\n");
if(connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
{
printf("connect failed: %s\n",strerror(errno));
}
else
{
printf("Connect successfully...\n");
}
3while循环
while(1)
{
DS_get_tem(&temp,chip);
tmp = localtime(&tout.tv_sec);
strftime(buf1,sizeof(buf1),"%r",tmp);
sprintf(buf,"%s %.3f鈩?%s",chip,temp,buf1);
if(write(sockfd,buf,strlen(buf)) <0 )
{
printf("write to serve unsuccessfully: %s\n",strerror(errno));
goto cleanup;
}
memset(buf,0,sizeof(buf));
if((rv = read(sockfd,buf,sizeof(buf))) < 0)
{
printf("read from serve unsuccessfully: %s\n",strerror(errno));
goto cleanup;
}
if(rv == 0)
{
printf("disconnect serve\n");
goto cleanup;
}
printf(" %s\n",buf);
memset(buf,0,sizeof(buf));
sleep(10);
}
close(sockfd);
cleanup:
close(sockfd);
return 0
}
4 温度采样函数,该树莓派上的温度传感器ds18b20测量到的温度会通过字符串的形式被记录到一个特定的文件夹下面,文件内容会随着温度的变化而变化。这时我们需要用到Linux下文件I/O的相关操作去获取温度值。
void DS_get_tem(float *temp,char *chip)
{
DIR *dp;
struct dirent *dirp;
char w1_path[30] = "/sys/bus/w1/devices/";
int found = 0;
int fd;
char *ptr;
char buf[100];
if((dp = opendir(w1_path)) < 0)
{
printf("opendir w1_path failed: %s\n",strerror(errno));
}
while((dirp = readdir(dp)) != NULL)
{
if(strstr(dirp->d_name,"28-") > 0)
{
strcpy(chip,dirp->d_name);
found = 1;
break;
}
}
closedir(dp);
strncat(w1_path,chip,sizeof(w1_path));
strncat(w1_path,"/w1_slave",sizeof(w1_path));
if(!found)
{
printf("readdir failed and can't find %s\n",dirp->d_name);
}
if((fd=open(w1_path,O_RDONLY)) < 0)
{
printf("open w1_path failed: %s\n",strerror(errno));
close(fd);
}
if(read(fd,buf,sizeof(buf)) < 0)
{
printf("read from w1_path failed: %s\n",strerror(errno));
close(fd);
}
ptr = strstr(buf,"t=");
if(!ptr)
printf("ERROR:can't get temperature\n");
ptr+=2;
*temp = atof(ptr)/1000;
}
oid sig_kill(int signo)
{
printf("SIGKILL[%d] caught\n",signo);
exit(0);
}
源码:https://gitee.com/yangjianing1/test