我是靠谱客的博主 积极小蘑菇,最近开发中收集的这篇文章主要介绍智能门锁项目总结引言需求分析项目分工虚拟场景设备及器材我的详细部分大致架构遇到的问题代码详情启动顺序总结一些“证明”图片,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

引言

人们出行旅游住宿的话,住酒店是躲不过的,那么酒店的安全管理则愈发重要。本项目旨在打造一款模拟智能门锁产品,针对酒店服务。

需求分析

前期构思:

1、密码锁,动态生成密码

2、触摸屏输入密码,6位数密码

3、手机app填入手机号用短信接收密码

4、屏幕触碰显示,长不用息屏

5、密码可设置到期时间

6、门锁连WiFi

 

后期更改:

1、密码锁,前台发送设置动态密码

2、手机输入密码,6位数密码

3、手机web网页填入IP和短信接收到的随机密码

4、密码可设置到期时间

5、门锁连WiFi,开机自启程序

项目分工

同学A,查找相关资料,找到linux下与短信服务商的C接口,用作密码服务器,并发送给短信服务商发送短信。

同学B,在安卓手机上弄一个app,与云端linux服务器通信,进行用户信息传送。(后期改成了web)

我,处理数据,针对来自密码服务器的密码以及来自用户开锁的密码还有驱动程序进行处理和调试。

虚拟场景

设备及器材

ARM S5PV210开发板(装载linux系统)、linux虚拟机、阿里云linux、PC机、继电器、灯泡(前代替门锁)、手机

我的详细部分

接收来自服务端的字符串,判断其长度,若长度为9则将字符串分割成密码和天数(前六位为密码,后三位为天数)。密码和天数字符串传给等待开锁比对模块,并将天数与系统时间计算出有效期,过期则清空密码。板子服务端模块只需接收客户端给的字符串,如果为设置密码,则需要9个字符;如果为清空密码,则只需3个字符。(其中9个字符是“六位数密码加三位数时间”,例如"123456002";其中3个字符是“门牌号”,例如"001"。)

等待开锁比对模块则是控制驱动操控板子上的IO口(被人说过不安全), 也是,就一个IO口确实是有点简单了。

大致架构

本项目由两个服务器(1号密码短信服务器和2号用户服务器),门锁上一个“主进程”(main),两个“辅助进程”(c1, c2),用户手里一个app,前台一个app。后来发现我们弄的app只能在虚拟机上能连通云端,一放到手机上就没反应,找了很多资料也无法解决,有说是sdk等级太低,也有说手机系统等级过高。后来我决定采用web服务器的形式,将2号用户服务器用http实现,这样做的好处是甭管你是什么系统的什么端,手机也好电脑也罢,都可以实现和服务器的通信,做到了跨平台的效果。

通信过程最复杂的在于“门锁”上,由于会被随时更换密码的状况发生,那么有一个客户端程序必须一致待命接收1号服务器的信息,传给主程序,即用c1代替;2号服务器则是用户填入的密码,传给“门锁”上的c2接收,也传给主程序。它们之间用fifo通信,因此我把一个处理程序叫做“主程序”, 另外两个叫做“辅助程序”。

其实还有一个驱动程序,等待主程序中的模块来写入字符从而驱动开锁。

遇到的问题

在我负责的这一部分里遇到了许多问题。例如,如果只有一个进程的话,那么当客户端函数接收到服务器发来的消息后客户端函数就结束了,也就是说一运行程序只能收到一次消息,如果是每次执行完开锁后或者是密码输入错误后才跳转到客户端函数的话,这样就违背了即时性,因为服务器随时都可能给客户端发送消息。所以这里我需要把客户端函数分离出来,当成一个独立的进程,确切的说不能叫做独立的进程,因为进程本来就是独立的。

那么,有了客户端进程后,就可以随时接收服务器的讯息了。可是这样又衍生出一个新的问题,就是需要进行进程间通信,进程间通信有信号、管道、共享内存等方式,这里选择了命名管道fifo里来通信,因为fifo可以让两个没有半点关系的进程进行通信。好了,知道了用fifo之后更多的问题接踵而至,例如write是阻塞的,有一个注意事项就是要先开启write端的进程,也就是先开启客户端的进程,它会阻塞在write,如果read的进程没开的话。而一开始我就是纯粹用的read函数,没有加非阻塞,这我才意识到会出问题,必须让它非阻塞的读管道里的内容。

后续在读管道内容时,一旦更改密码多次之后会出现数据偏移情况,一直未能解决,所以这个fifo管道很让人捉摸不透。

代码详情

头文件:

/**
******************************************************************************
* @file    Func.h
* @author  邓子康
* @version V1.0
* @date    2018-05-02
* @brief   门锁头文件
******************************************************************************
**/
#ifndef __FUNC_H
#define __FUNC_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>

int fdsocket;

void mybzero(char *str)
{
	bzero(str, sizeof(str));
	str[sizeof(str) - 1] = '';
}

#endif

门锁的主程序代码:

/**
******************************************************************************
* @file    main.c
* @author  邓子康
* @version V1.0
* @date    2018-05-02
* @brief   开锁主程序
******************************************************************************
**/
#include "Func.h"

void main()
{
	while(1)																 //无限循环(好像没什么用,不过嵌入式程序一般都是无限循环)
	{
		flag = 0;
		int ret = 0;														 //接收各模块的返回值,还有他用
		char *namer = "CtoP";												 //命名管道的名字(读端)读取客户端
		char *namew = "PtoS";												 //命名管道的名字(写端)写入“屏幕”
		ret = myfifo(namew, namer); 										 //创建管道并打开读、写管道
		if(ret != 0)														 //判断函数返回是否正确
		{
			printf("func myfifo() err: %dn", ret);							 //不正确打印错误信息
			return;															 //结束程序
		}
		usleep(1000);														 //睡一下等待接收信息
		char buffer[10] = {0};												 //装载来自客户端的信息
		char buffptos[2] = {0}; 											 //发给屏幕的标志
		read(fdCtoP, buffer, sizeof(buffer));								 //读取客户端的信息给buffer
		
		char *pwd1 = NULL, *pwd2 = NULL, *day = NULL, *time = NULL;			 //pwd1:服务器密码 pwd2:来自屏幕的密码 day:天数 time:过期时间
		char buff[10] = {0}; 												 //装载服务器信息(备份,为了跳转)	
		
		pwd1 = (char *)malloc(pwdlen + 1);									 //开辟空间(+ 1是为了放'')
		pwd2 = (char *)malloc(pwdlen + 1);									 //同上
		day = (char *)malloc(dwdlen + 1);									 //同上
		time = (char *)malloc(30);											 //同上,装载时间的空间需要大一点
		
 loop:  																	 //loop标号
		ret = strlen(buffer);												 //ret这里是为了获取信息的长度
		strcpy(buff, buffer);												 //备份信息,用作比对	
		printf("密码:%s %dn", buffer, ret);
		switch(ret)															 //选择分支,9为密码和天数(拆分开),3为门牌号(清空密码和时间)
		{
			case 9: incisePWDandDAY(buffer, pwd1, day);						 //是9则进入拆分密码和天数模块
					timeConvers(day, time);							 	     //设置过期时间
			break;															 //跳出
			case 3: bzero(pwd1, sizeof(pwd1));                               //是3则清除密码
					bzero(time, sizeof(time));                               //清除时间
			break;
			default:printf("Not pwd or dwd err:%dn", ret);                  //不是9或3则打印错误信息
			mybzero(buffer);
			read(fdCtoP, buffer, sizeof(buffer));	
			goto loop;
		}
		
	that:																     //that标号
		mybzero(pwd2);
		receiveScreenPWD(pwd2);								        		 //接收屏幕密码
		
		read(fdCtoP, buffer, sizeof(buffer));								 //中途读取客户端的信息给buffer容器
		buffer[9] = '';
		printf("客户端密码1:%sn", buffer);
		if(strcmp(buffer, buff) != 0 && strcmp(pwd2, P) != 0)                //若和备份不相同,则代表密码更改或发送了门牌号
		{
			mybzero(buffptos);							     				 //清空buffptos容器
			strcpy(buffptos, "0");										 //将"0"写入buffptos
			write(fdPtoS, buffptos, strlen(buffptos));                       //写入管道(“屏幕”)
			goto loop;                                                       //跳转至loop,重来一遍上面的流程
		}

		ret = setOpenLock(pwd1, pwd2, time);           						 //设置开锁	
		writetophone(ret, buffptos);
		goto that;															 //跳转至that
	}
}

主程序里要调用的函数们:

/**
******************************************************************************
* @file    SmartDoor.c
* @author  邓子康
* @version V1.0
* @date    2018-05-02
* @brief   开锁功能模块
******************************************************************************
**/
#include "Func.h"

/**
  * @brief  创建管道并打开读、写管道
  * @param  namew: 写管道的文件名 
  * @param  namer: 读管道的文件名					
  * @retval ret: 小于零则出错,等于零正常
  */
int myfifo(char *namew, char *namer)
{
	int ret = 0;                                         
	unlink(namew);                              //删除存在的文件
	int res = mkfifo(namew, 0666);				//创建管道,权限所有可读可写
	if(res < 0)
	{
		ret = -1;
		perror("mkfifo");
		return ret;
	}
			
	fdPtoS = open(namew, O_WRONLY);             //打开管道,只写
	if(fdPtoS < 0)
	{
		ret = -2;
		perror("open");
		return ret;
	}

	fdCtoP = open(namer, O_RDONLY | O_NONBLOCK);//打开管道,只读且非阻塞
	if(fdCtoP < 0) 
	{
		ret = -3;
		perror("open");
		return ret;
	}	
	return 0;
}

/**
  * @brief  切割密码和天数
  * @param  str: 接收到的客户端信息 
  * @param  pwd: 返回出去的密码		
  * @param  pwdlen: 密码天数长度 
  * @param  dwd: 读管道的文件名
  * @param  dwdlen: 读管道的文件名
  * @retval ret: 小于零则出错,等于零正常
  */
int incisePWDandDAY(char *str, char *pwd, char *dwd)
{
	int ret = 0;
	if(str == NULL || pwd == NULL, dwd == NULL)                           //为NULL则退出
	{
		ret = -1;
		printf("str == NULL || pwd == NULL, dwd == NULL. err: %dn", ret);
		return ret;
	}

	strncpy(pwd, str, pwdlen);											  //拷贝前6个字符给pew
	str += pwdlen;                                                        //str指针移动6个字节
	pwd[pwdlen] = '';													  //末尾填上''
	strncpy(dwd, str, dwdlen);                                            //接着拷贝3个字符给dwd
	dwd[dwdlen] = '';													  //末尾填上''
	return ret;
}

/**
  * @brief  过期时间转换
  * @param  str: 接收到的天数字符串
  * @param  pwd: 返回出去的过期时间		
  * @retval ret: 小于零则出错,等于零正常
  */
int timeConvers(const char *str, char *times)
{
	int ret = 0, day = 0, num = 0;                         //初始化
	char tmp[3] = {0};                                     //临时数组
	char *mtime = NULL;                                    //当前时间指针
	if(str == NULL || times == NULL)
	{
		ret = -1;
		printf("The str or times is NULL. err: %dn", ret); 
		return ret;
	}

	day = atoi(str);                                       //字符串转整型
	time_t t = time(NULL);                                 //初始化时间
	mtime = ctime(&t);                                     //获取当前时间字符串 Wed May  2 20:17:29 2018
	strncpy(tmp, mtime + 11, 2);                           //拷贝小时
	tmp[2] = '';                                         
	num = atoi(tmp);                                       //转整数
	if(num < 12)                                           //小于12即还没到下午,所以算作一天
	{
		day--;                                             //天数减一
	}
	
	t += day * T;                              			   //当前时间加上开房天数
	mtime = ctime(&t);                                     //增加后的时间
	mtime[11] = '1';                                       //将小时置为12
	mtime[12] = '2';
	mtime[14] = mtime[15] = mtime[17] = mtime[18] = '0';   //将分钟秒钟置为0 即12:00:00// Fri May  4 12:00:00 2018
	strcpy(times, mtime);                                  //拷贝给times传出
	return ret;
}

/**
  * @brief  接收屏幕密码	
  * @param  buf:  待返回的出去给主函数的屏幕密码
  * @retval ret: 小于零则出错;等于1则屏幕未输入密码;等于2开锁失败
  */
int receiveScreenPWD(char *buf)
{
	int ret = 0;
	char pwdbuf[7] = {0};                                     //装载屏幕密码
	char *name = "StoP";                                      //管道名
	if(buf == NULL)
	{
		ret = -1;
		printf("The buf is NULL. err: %dn", ret);
		return ret;
		return ret;
	}
	
	int fdStoP = open(name, O_RDONLY);         			 		//打开管道
	if(fdStoP < 0) 
    {
		ret = -2;
		perror("open");
		return ret;
	}
	
	if(flag == 0)
	{
		read(fdStoP, pwdbuf, sizeof(pwdbuf));
	}
	flag++;
	
	while(1)
	{
		bzero(pwdbuf, strlen(pwdbuf));
		read(fdStoP, pwdbuf, sizeof(pwdbuf));                	//阻塞读取屏幕管道信息
		if(strlen(pwdbuf) != 0)									//接收到的密码长度不为0则跳出
		{
			break;
		}
	}
	strcpy(buf, pwdbuf);                                 		//拷贝给buf传出
	close(fdStoP);
	return ret;
}

/**
  * @brief  设置开锁
  * @param  pwd1: 客户端密码
  * @param  pwd2: 屏幕密码	
  * @param  mtime: 过期时间  
  * @retval ret: 小于零则出错;等于1视为开锁成功,驱动开锁;等于2开锁失败
  */
int setOpenLock(const char *pwd1, const char *pwd2, const char *mtime)
{
	int ret = 0;
	if(pwd1 == NULL || pwd2 == NULL || mtime == NULL)
	{
		ret = -1;
		printf("pwd1 == NULL || pwd2 == NULL || time == NULL. err: %dn", ret);
		return ret;
	}

	char *tmp = NULL;
	time_t t = time(NULL);
	tmp = ctime(&t);                                                                    //获取当前时间
	if((strcmp(pwd1, pwd2) == 0) && (strcmp(tmp, mtime) != 0) || (strcmp(P, pwd2) == 0))//密码相等并且时间没到期或者是万能密码则开锁
	{
		                                                                                //驱动开锁
		ret = 1;
		int fdlock = open("/dev/mydevice", O_RDWR);                                     //fdr为驱动文件描述符
		write(fdlock, &ret, 4);                                                         //把这个内容写到fdr中
		ret = 2;
		sleep(5);
		write(fdlock, &ret, 4);
		ret = 1;
		close(fdlock);
		return ret;
	}
	else
	{
		ret = 2;
		return ret;
	}
}
/**
  * @brief  清除字符串
  * @param  str: 字符串首地址  
  */
void mybzero(char *str)
{
	int num = sizeof(str);
	bzero(str, num);
	str[num - 1] = '';
}

/**
  * @brief  写信息给"手机"
  * @param  num: setOpenLock()的返回值
  * @param  str: 信息的容器  
  */
void writetophone(int num, char *str)
{
	char snum[2] = {0};
	printf("%dn", num);
	sprintf(snum, "%d", num);
	mybzero(str);
	strcpy(str, snum);											 
	printf("buffptos %sn", str);
	write(fdPtoS, str, strlen(str)); 
}


辅助C1:

/**
******************************************************************************
* @file    client1.c
* @author  邓子康
* @version V1.0
* @date    2018-05-02
* @brief   门锁客户端1号
******************************************************************************
**/
#include "Func.h"

void main()
{
	int num = 0, i = 0;
	char buffer[10] = {0};
	char *name = "CtoP";
	unlink(name);
			
	int res = mkfifo(name, 0666);
	if(res < 0)
	{
		perror("mkfifo");
		return;
	}
	int fdCtoP = open(name, O_WRONLY);
	if(fdCtoP < 0) 
	{
        perror("open");
		return;
	}
	
	strcpy(buffer, "000000000");
	write(fdCtoP, buffer, strlen(buffer));
	
	fdsocket = socket(AF_INET, SOCK_STREAM, 0);
	if(fdsocket < 0)
	{
		perror("socket");
		return;
	}
	
	struct sockaddr_in sockin;
	bzero(&sockin, sizeof(sockin));
	sockin.sin_family = AF_INET;
	sockin.sin_port = htons(60000);
	inet_pton(AF_INET, "47.106.103.130"/*"127.0.0.1"*/, &sockin.sin_addr);
		
	if(connect(fdsocket, (struct sockaddr *)&sockin, sizeof(sockin)) < 0)
	{
		perror("connect");
		return;
	}
	

	
	while(1)
	{
		read(fdsocket, buffer, sizeof(buffer));				//读取服务器发来的信息
		printf("%s, %dn", buffer, strlen(buffer));
		if(strlen(buffer) == 9)
		{
			write(fdCtoP, buffer, strlen(buffer));			//将信息写入管道
		}
		else if(strlen(buffer) == 3)
		{
			strcat(buffer, "");
			write(fdCtoP, buffer, sizeof(buffer));
		}
	}

	close(fdsocket);
	close(fdCtoP);
}

辅助C2:

/**
******************************************************************************
* @file    client2.c
* @author  邓子康
* @version V1.0
* @date    2018-05-02
* @brief   门锁客户端2号
******************************************************************************
**/
#include "Func.h"

void main()
{
	sleep(3);

	char buffer[10] = {0};
	char buffptos[2] = {0};
	char buff[7] = {""};
	char *namew = "StoP";
	char *namer = "PtoS";
	unlink(namew);
			
	int res = mkfifo(namew, 0666);
	if(res < 0)
	{
		perror("mkfifo");
		return;
	}
	
	int fdPtoS = open(namer, O_RDONLY);
	if(fdPtoS < 0) 
    {
		perror("open");
		return;
	}

	int fdStoP = open(namew, O_WRONLY);
	if(fdStoP < 0) 
    {
		perror("open");
		return;
	}
	
	strcpy(buffer, "666");
	write(fdStoP, buffer, strlen(buffer));
	
	fdsocket = socket(AF_INET, SOCK_STREAM, 0);
	if(fdsocket < 0)
	{
		perror("socket");
		return;
	}
	
	struct sockaddr_in sockin;
	bzero(&sockin, sizeof(sockin));
	sockin.sin_family = AF_INET;
	sockin.sin_port = htons(2222);
	inet_pton(AF_INET, "47.106.103.130"/*"127.0.0.1"*/, &sockin.sin_addr);
		
	if(connect(fdsocket, (struct sockaddr *)&sockin, sizeof(sockin)) < 0)
	{
		perror("connect");
		return;
	}
	
	while(1)
	{
		mybzero(buffer);
		mybzero(buffptos);
		read(fdsocket, buffer, sizeof(buffer));			//读取服务器发来的信息
		printf("%sn", buffer);
		
		write(fdStoP, buffer, strlen(buffer));			//将信息写入管道给主程序
		
		read(fdPtoS, buffptos, sizeof(buffptos));		//阻塞接收主程序信息
		printf("%sn", buffptos);
		write(fdsocket, buffptos, strlen(buffptos));	//发给服务器
	}

	close(fdsocket);
	close(fdStoP);
}
	

用户服务器:

/**
******************************************************************************
* @file    httpSer.c
* @author  邓子康
* @version V1.0
* @date    2018-05-02
* @brief   http用户服务器
******************************************************************************
**/
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char buffclient[2] = {0};
void mybzero(char *str)
{
	bzero(str, sizeof(str));
	str[sizeof(str) - 1] = '';
}


int getpwd(int fd, char *buff)
{
	char buffer[1024*1024] = {0};
	read(fd, buffer, sizeof(buffer));//获取请求报文
	printf("%sn", buffer);
	char pwd[10] = {0};
    char *begin = strstr(buffer, "/") + 1;
    char *end = strstr(begin, " ");
	int num = (int)end - (int)begin;
	if(num == 6)
	{
		memcpy(pwd, begin, num);
		if(strspn(pwd, "0123456789") == 6)
		{
			strcpy(buff, pwd);
			return 1;
		}
		else
		{
			return -1;           //非法字符
		}
	}
	else
	{
		return -2;             //长度不对
	}
}


/*接收请求,解析,然后发送相应的数据*/
void handle(int fdphone, int fdblock)
{
	int num = 0;
	char buffer[1024 * 1024] = {0};
	num = getpwd(fdphone, buffer);
	printf("图片%dn", num);
	if(num >= 0)
	{
		printf("%sn", buffer);
		write(fdblock, buffer, strlen(buffer));       //将内容转发给板子端
		mybzero(buffclient);
		read(fdblock, buffclient, sizeof(buffclient));//读取板子端的消息
		printf("%sn", buffclient);
		num = atoi(buffclient);
		bzero(buffer, sizeof(buffer));
		if(num == 1)
		{
			/*构建状态码和响应头*/
			strcpy(buffer, "HTTP/1.1 200 OKrnContent-type: image/jpgrnrn");
			write(fdphone, buffer, strlen(buffer));   //先发过去给客户端

			/*打开具体的文件,发给客户端*/ 
			char *file = "succ.jpg";
			int filefd = open(file, O_RDONLY);    
			bzero(buffer, sizeof(buffer));   
			size_t len = read(filefd, buffer, sizeof(buffer));   
			write(fdphone, buffer, len);			 //发给客户端 
			close(filefd); 
		}

		if(num == 2)
		{
			strcpy(buffer, "HTTP/1.1 200 OKrnContent-type: image/jpgrnrn");
			write(fdphone, buffer, strlen(buffer));
 
			char *file = "errpwd.jpg";
			int filefd = open(file, O_RDONLY);    
			bzero(buffer, sizeof(buffer));  
			size_t len = read(filefd, buffer, sizeof(buffer));  
			write(fdphone, buffer, len);
			close(filefd);  
		}
		
		if(num == 0)
		{
			strcpy(buffer, "HTTP/1.1 200 OKrnContent-type: image/jpgrnrn");
			write(fdphone, buffer, strlen(buffer));
 
			char *file = "change.jpg";
			int filefd = open(file, O_RDONLY);    
			bzero(buffer, sizeof(buffer));  
			size_t len = read(filefd, buffer, sizeof(buffer));
			write(fdphone, buffer, len);
			close(filefd); 
		}
	}
	
	if (num == -1)
	{
		printf("字符不对n");
		
		strcpy(buffer, "HTTP/1.1 200 OKrnContent-type: image/jpgrnrn");
		write(fdphone, buffer, strlen(buffer));

		char *file = "err_str.jpg";
		int filefd = open(file, O_RDONLY);    
		bzero(buffer, sizeof(buffer));    
		size_t len = read(filefd, buffer, sizeof(buffer));  
		write(fdphone, buffer, len);
		close(filefd);
	}
	
	if(num == -2)
	{
		printf("长度不对n");
		strcpy(buffer, "HTTP/1.1 200 OKrnContent-type: image/jpgrnrn");
		write(fdphone, buffer, strlen(buffer));

		char *file = "err_len.jpg";
		int filefd = open(file, O_RDONLY);    
		bzero(buffer, sizeof(buffer));   
		size_t len = read(filefd, buffer, sizeof(buffer));   
		write(fdphone, buffer, len); 
		close(filefd);
	}
}



void main()
{
	int ret = 0;
	/*1、创建套接字*/
	int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
	if(listen_fd < 0)
	{
		perror("socket");
		exit(EXIT_FAILURE);
	}
	
	int on=1;
    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);

	struct sockaddr_in sockin;
	bzero(&sockin, sizeof(sockin));
	sockin.sin_family = AF_INET;
	sockin.sin_port = htons(80);
	sockin.sin_addr.s_addr = htonl(INADDR_ANY);
	
    if(bind(listen_fd, (struct sockaddr *)&sockin, sizeof(sockin)) < 0)
	{
		perror("bind");
		exit(EXIT_FAILURE);
	}
    

	if(listen(listen_fd, 10) < 0)
	{
		perror("listen");
		exit(EXIT_FAILURE);
	}
	

    struct sockaddr_in clientaddr;
	bzero(&clientaddr, sizeof(clientaddr));
	size_t len = sizeof(clientaddr);
	
	while(1)
	{
		int fdblock = accept(listen_fd, (struct sockaddr *)&clientaddr, &len);	//板子客户端
		printf("板子客户端已连接n");
		if(fdblock < 0)
		{
			perror("accept");
			exit(EXIT_FAILURE);
		}
	loop:while(1)											//给手机连接
		{
			int fdphone = accept(listen_fd, NULL, NULL);	//遥控客户端
			printf("手机客户端已连接n");
			if(fdphone< 0)
			{
				perror("accept");
				exit(EXIT_FAILURE);
			}
			
			handle(fdphone, fdblock);
			close(fdphone);		
		}
		close(fdblock);										//板子客户端
	}
	close(listen_fd); 
}

同学A的密码短信服务器:

#include <unistd.h>
#include <sys/socket.h>  //套接字相关
#include <arpa/inet.h> //因特网地址结构体 struct sockaddr_in定义
#include <time.h> //时间相关
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/sha.h>
#include <malloc.h>
//int类型转字符串
char *myitoa(int num, char *str, int radix) 
{  
	/* 索引表 */ 
	char index[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
	unsigned unum; /* 中间变量 */ 
	int i = 0,j,k; 
	/* 确定unum的值 */ 
	if(radix == 10 && num < 0) /* 十进制负数 */ 
	{ 
		unum= (unsigned) - num; 
		str[i++] = '-'; 
	} 
	else unum = (unsigned)num; /* 其它情况 */ 
	/* 逆序 */ 
	do  
	{ 
		str[i++] = index[unum%(unsigned)radix]; 
		unum /= radix; 
	}while(unum); 
	str[i] = ''; 
	/* 转换 */ 
	if(str[0] == '-') 
	{
		k = 1; /* 十进制负数 */ 
	}
	else 
	{
		k=0;
	}		
	/* 将原来的“/2”改为“/2.0”,保证当num在16~255之间,radix等于16时,也能得到正确结果 */ 
	char temp; 
	for(j = k;j <= (i - k - 1) / 2.0; j++) 
	{ 
		temp = str[j]; 
		str[j] = str[i - j - 1]; 
		str[i - j - 1] = temp; 
	} 
	return str; 
}

int main(void)
{
	/*1、创建套接字*/
	int listen_fd = socket(AF_INET,SOCK_STREAM,0);
	if(listen_fd < 0)
	{
		perror("socket");
		exit(EXIT_FAILURE);
	}
	int on = 1;
	setsockopt(listen_fd,SOL_SOCKET, SO_REUSEADDR, &on,sizeof on);
    /*2、将套接字和地址进行绑定*/
		/*2-1 先准备地址结构体*/
		struct sockaddr_in sockin;
		bzero(&sockin, sizeof(sockin));
		sockin.sin_family = AF_INET;//地址族
		sockin.sin_port = htons(2018);//本机监听端口
		//inet_pton(AF_INET,"127.0.0.1",&sockin.sin_addr);//将点分十进制转成整型数,保存在地址结构体里
		//还可以这样写ip,让系统选择任意一块网卡(ip)监听
		sockin.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY的值0

		/*2-2 绑定 */
	if(bind(listen_fd, (struct sockaddr *)&sockin, sizeof(sockin))<0)
		{
			perror("bind");
			exit(EXIT_FAILURE);
		}
		/*3、开放套接字,开始监听*/
	if(listen(listen_fd,10) < 0)
	{
		perror("listen");
		exit(EXIT_FAILURE);
	}
	struct sockaddr_in clientaddr;
	bzero(&clientaddr, sizeof(clientaddr));
	size_t len = sizeof(clientaddr);//长度必须要有初始值
	
	int fd = accept(listen_fd, (struct sockaddr *)&clientaddr, &len);//经过本函数可以得到客户端地址和长度,返回的fd是可以用来通信的,它是和某个客户端的连接相对应的
	
	/*将客户端的信息打出来*/
	char buffip2[16] = {0};
	inet_ntop(AF_INET, &clientaddr.sin_addr,buffip2, sizeof(buffip2));
	printf("客户端%s(%u)已连接n", buffip2, ntohs(clientaddr.sin_port));
	
	if(fd<0)
	{
		perror("accept");
		exit(EXIT_FAILURE);
	}

	//APP的循环开始处
	while(1)
	{
		int ad=accept(listen_fd,(struct sockaddr *)&clientaddr,&len);
			//accept在没有客户端连接的情况下会阻塞等待
		
		/*将客户端的信息打出来*/
		char buffip1[16]={0};
		inet_ntop(AF_INET,&clientaddr.sin_addr,buffip1,sizeof(buffip1));
		printf("客户端%s(%u)已连接n",buffip1,ntohs(clientaddr.sin_port));
		if(ad<0)
		{
			perror("accept");
			exit(EXIT_FAILURE);
		}
	//______________随机六位验证码____________________________________________
		
	//	char CAPTCHA[10]={0}; //验证码
		char *CAPTCHA = (char *)malloc(10); //必须使用malloc
		char temp[1] = {0};
		int m,j;
		srand(time(NULL));
		for(m=0;m<6;m++)
		{
			j=rand()%10;
			myitoa(j,temp,10);
			strcat(CAPTCHA,temp);
		}

	//______________读取APP信息_______________________________________________
		
		char buffer_r[1024]={0};
		read(ad,buffer_r,sizeof(buffer_r));
		write(STDOUT_FILENO,buffer_r,strlen(buffer_r));
		
		//发送验证码和天数过程
		if(strlen(buffer_r) == 17)
		{
			printf("读到17个字节!n");


		//______________发送给板子信息____________________________________________
			
			char buffer_w[1024] = {0};
			strcpy(buffer_w, CAPTCHA);
			strcat(buffer_w, &buffer_r[strlen(buffer_r) - 3]);
			write(fd, buffer_w, strlen(buffer_w));//将字符串发出去

		//——————————————发送给网易云短信接口信息__________________________________
			SHA_CTX s;
			time_t t;
			t = time(0);
			int i;
			char c[512] = "d673f918bc1e4tgggergigwow323t23t"; //密钥
			char time[11] = {0};
			myitoa(t, time, 10);
			strcat(c, time);
			unsigned char hash[SHA_DIGEST_LENGTH];

			SHA1_Init(&s);
			SHA1_Update(&s, c, strlen(c));
			SHA1_Final(hash, &s); 
			//加密过程
			
			char mdString[SHA_DIGEST_LENGTH*2+1];
			for (i = 0; i < SHA_DIGEST_LENGTH; i++) 
			{		
				sprintf(&mdString[i*2], "%02x", (unsigned int)hash[i]);   
			}	
			printf("SHA1 hash: %sn", mdString);
			//curl发送短信命令
			char curl[400] = "curl -X POST -H "";
			//AppKey 短信商提供的密钥
			strcat(curl, "AppKey: 9b8bf4eec06d9347812ae37bf208e7f7" -H "CurTime: ");
			//CurTime 截取系统时间戳
			strcat(curl, time);
			//CheckSum 加密后的校验和
			strcat(curl, "" -H "CheckSum: ");
			strcat(curl, mdString);
			//Nonce 自定义的密钥
			strcat(curl, "" -H "Nonce: 4tgggergigwow323t23t" -H "");	
			//Content-Type
			strcat(curl, "Content-Type: application/x-www-form-urlencoded" -d 'mobile=");
			//mobile APP提供的电话号码
			char mobile[15] ={ 0};
			strncat(mobile, buffer_r, 11); //接收来自APP的电话信息
			strcat(curl, mobile);
			//templateid短信模板自定义类型id
			strcat(curl, "' -d 'templateid=3892731' -d 'authCode=");
			//authCode自定义验证码
			strcat(curl, CAPTCHA); //六位随机密码
			//发送网址
			strcat(curl, "' 'https://api.netease.im/sms/sendcode.action'");
			
			//拼装完成系统发送
			system(curl);	
			}
			//发送门牌号
			else if(strlen(buffer_r) == 3){
			printf("读到了3个字节!");
			char buffer_w[1024] = {0};
			strcpy(buffer_w, CAPTCHA);
			write(fd, buffer_w, strlen(buffer_w));//将字符串发出去
		}
		//APP出错
		else
		{
			printf("APP发送信息出错!");
			free(CAPTCHA);
			close(ad);
			continue;
		}
		//死循环到这里(*注意)
		free(CAPTCHA);
		close(ad);
	}
	close(fd);//关闭这个连接,第三次挥手
	close(listen_fd);
}


 

驱动代码:

/*
驱动程序
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h> //copy_to_user, copy_from_user
#include <linux/io.h> //ioremap, writeb, readb等

MODULE_LICENSE("GPL");
dev_t devno;

struct class *cls;

volatile unsigned int *GPH3CON = NULL;
volatile unsigned int *GPH3DAT = NULL;

//准备一个open函数,用来服务open请求
int myopen(struct inode *ino, struct file *file)
{
    printk(KERN_CRIT"fake file was open!n");
    GPH3CON = ioremap(0xE0200C60, 4);//地址重映射
    GPH3DAT = ioremap(0xE0200C64, 4);
    writel(0x1 << 8, GPH3CON); //gpio设置成输出功能
    return 0;
}

//close函数
int myclose(struct inode *ino, struct file *file)
{
    printk(KERN_CRIT"fake file was close!n");
    iounmap(GPH3CON);//取消映射
    iounmap(GPH3DAT);
    return 0;
}

//read函数,从内核空间将数据拷贝到用户空间
ssize_t myread(struct file *file, char __user *buffer, size_t len, loff_t *off)
{
    int num = 2018;
    ssize_t ret = copy_to_user(buffer, &num, sizeof num);
    return ret;
}

//write函数,从用户空间将数据拷贝到内核空间
ssize_t mywrite(struct file *file, const char __user *buffer, size_t len, loff_t *off)
{
    unsigned int num;
    ssize_t re = copy_from_user(&num, buffer, len);
    writel(0x00, GPH3DAT);
    writel(~(0x1 << num), GPH3DAT);

    return re;
}

//准备好文件操作结构体
struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = myopen,//将自定义的open服务函数交给它
    .release = myclose,
    .read = myread,
    .write = mywrite
};


int __init mydriverinit(void)
{
    alloc_chrdev_region(&devno, 10, 1, "mydriver");
    //注册驱动
    register_chrdev(MAJOR(devno), "mydriver", &fops);
    cls = class_create(THIS_MODULE, "myclass");
    device_create(cls, NULL, devno, NULL, "mydevice");
    return 0;
}

module_init(mydriverinit);

void __exit mydriverexit(void)
{
    device_destroy(cls, devno);
    class_destroy(cls);
    unregister_chrdev(MAJOR(devno), "mydriver");
    unregister_chrdev_region(devno, 1);

}

module_exit(mydriverexit);

 

makefile:

target=pro
src=$(wildcard ./*.c)
obj=$(patsubst ./%.c, %.o, $(src))

CC=arm-linux-gcc
CPPFLAGS=-I
$(target):$(obj)
	$(CC) $(obj) -o $(target)
%.o:%.c
	$(CC) -c $< -o $@
clean:
	rm $(obj) $(target) 

启动顺序


在板子上连好WiFi
start-wifi wpa 账号 密码

加载驱动
insmod mydriver
服务器随意顺序,但是必须先开启两个服务器(密码短信服务器开启,用户服务器)
然后&./c1&./pro&./c2
先客户端1,与接收密码的服务器连接
然后主程序,其次客户端2,与用户服务器

在虚拟机上交叉编译,在板子上给权限

 

全程可以开机自启这些步骤,这里就不详述了

总结

这次项目没有拍照和视频等,以及善后工作没有处理好(这篇博客也是事后过了N个月才写的),而且很“初级”,考虑不周到,没有真正按照软件工程那样做到很细致,也没有日志文件反映错误,所以本项目拿到市面上是极为不成熟的,有许多地方需要亟待改进的地方。但是我从中得到了历练,尝到了调试之苦,明白了如何取舍以及改进。

 

一些“证明”图片

谢谢观看,本文原创,版权属于邓子康本人,转载或引用请注明出处。

 

 

最后

以上就是积极小蘑菇为你收集整理的智能门锁项目总结引言需求分析项目分工虚拟场景设备及器材我的详细部分大致架构遇到的问题代码详情启动顺序总结一些“证明”图片的全部内容,希望文章能够帮你解决智能门锁项目总结引言需求分析项目分工虚拟场景设备及器材我的详细部分大致架构遇到的问题代码详情启动顺序总结一些“证明”图片所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部