网络安全传输系统(5)-账号管理系统

1、SQlite介绍

账号管理系统显然需要用到数据库,开源的数据库有MySQL,SQlite等,由于SQlite是一个轻量级、跨平台的数据库,非常适用于嵌入式系统中,因此我们选用SQlite数据库。

SQlite有如下优点:

◇轻量级
先说它的第一个特色:轻量级。想必SQLite的作者很看重这个特性,连它的Logo都是用的“羽毛”,来显摆它的轻飘飘。
SQLite和C/S模式的数据库软件不同,它是进程内的数据库引擎,因此不存在数据库的客户端和服务器。使用SQLite一般只需要带上它的一个动态 库,就可以享受它的全部功能。而且那个动态库的尺寸也挺小,以版本3.6.11为例,Windows下487KB、Linux下347KB。


◇绿色软件
SQLite的另外一个特点是绿色:它的核心引擎本身不依赖第三方的软件,使用它也不需要“安装”。所以在部署的时候能够省去不少麻烦。


◇单一文件
所谓的“单一文件”,就是数据库中所有的信息(比如表、视图、触发器、等)都包含在一个文件内。这个文件可以copy到其它目录或其它机器上,也照用不误。


◇跨平台/可移植性
如果光支持主流操作系统,那就没啥好吹嘘的了。除了主流操作系统,SQLite还支持了很多冷门的操作系统。我个人比较感兴趣的是它对很多嵌入式系统(比如Android、Windows Mobile、Symbin、Palm、VxWorks等)的支持。


◇内存数据库(in-memory database)
这年头,内存越来越便宜,很多普通PC都开始以GB为单位来衡量内存(服务器就更甭提了)。这时候,SQLite的内存数据库特性就越发显得好用。

 

2、SQlite配置及安装

下载源代码,解压后进入目录,创建_install目录用于存放目标文件。

配置:

#./configure --host=arm-linux --prefix=${PWD}/_install

编译:

#make

如果发现报错,提示
arm-none-linux-gnueabi-gcc: 3.7.8":no such file or directory
<command-line>:waring:missing terminating " character
可以打开Makefile,查找3.7.8,发现有个包含3.7.8的目录前面多了一个空格,去掉后保存

 

再次编译和安装:

#make

#make install

 

编译后在_install/bin目录下生成一个sqlite3文件,如果需要在开发板上运行,可以
把它拷贝到开发板的sbin目录下
把lib下的库动态库文件拷贝到开发板的lib目录下

 

3、SQlite编程

首先需要打开数据库,如果不存在这个数据库文件会新建一个

sqlite3 *db; 
int rc;
//创建数据库
rc = sqlite3_open("user.db",&db);
if(rc)
{
	printf("Can't open database: %s\n", sqlite3_errmsg(db)); 
	sqlite3_close(db); 
}	sqlite3_close(db); 
}

 

创建一张表,它它命名为stu,成员包括char类型的username和password:

sprintf(sql,"create table stu(username char(20), password char(20));");
rc = sqlite3_exec(db, sql, callback, 0, NULL); 
if(rc != SQLITE_OK)
{
	printf("create tables error!\n");
}

callback是一个回调函数,一般用来保存查询结果,如果没有输出,则没有什么作用。
callback函数:

static int callback(void *NotUsed, int argc, char **argv, char **azColName) 
{ 
     int i; 
     for(i=0; i<argc; i++) 
     {          
     	strcpy(passwd_d,argv[i]);
     } 
    return 0;
} 

 

往表中插入数据:

sprintf(sql,"insert into stu(username,password) values('%s','%s');",username,password);
printf("username:%s password:%s\n",username,password);
rc = sqlite3_exec(db, sql, callback, 0, NULL);


查询:

sprintf(sql, "select password from stu where username='%s';",username); 
sqlite3_exec(db, sql, callback, 0, NULL);

 

查询结果通过callback回调函数保存在passwd_d中

 

4、改进后的代码

由于加入了数据库,编译时需要加上-lsqlite。

服务器:

#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<errno.h>
#include<fcntl.h>
#include<unistd.h>

#include <openssl/err.h>
#include <openssl/ssl.h>
#include <pthread.h> 
#include <sqlite3.h> 

#define port 3333

typedef struct task 
{ 
    void *(*process) (int arg); 
    int arg;
    struct task *next; 
} Cthread_task; 


/*线程池结构*/ 
typedef struct 
{ 
    pthread_mutex_t queue_lock; 
    pthread_cond_t queue_ready; 

    /*链表结构,线程池中所有等待任务*/ 
    Cthread_task *queue_head; 

    /*是否销毁线程池*/ 
    int shutdown; 
    pthread_t *threadid; 
    
    /*线程池中线程数目*/ 
    int max_thread_num; 
    
    /*当前等待的任务数*/ 
    int cur_task_size; 

} Cthread_pool; 

static Cthread_pool *pool = NULL; 

void *thread_routine (void *arg); 


int sockfd;
struct sockaddr_in sockaddr;
struct sockaddr_in client_addr;
int sin_size;
char passwd_d[20];

SSL_CTX *ctx;
sqlite3 *db; 

void pool_init (int max_thread_num) 
{ 
    int i = 0;
    
    pool = (Cthread_pool *) malloc (sizeof (Cthread_pool)); 

    pthread_mutex_init (&(pool->queue_lock), NULL); 
    /*初始化条件变量*/
    pthread_cond_init (&(pool->queue_ready), NULL); 

    pool->queue_head = NULL; 

    pool->max_thread_num = max_thread_num; 
    pool->cur_task_size = 0; 

    pool->shutdown = 0; 

    pool->threadid = (pthread_t *) malloc (max_thread_num * sizeof (pthread_t)); 

    for (i = 0; i < max_thread_num; i++) 
    {  
        pthread_create (&(pool->threadid[i]), NULL, thread_routine, NULL); 
    } 
} 

void * thread_routine (void *arg) 
{ 
    printf ("starting thread 0x%x\n", pthread_self ()); 
    while (1) 
    { 
        pthread_mutex_lock (&(pool->queue_lock)); 

        while (pool->cur_task_size == 0 && !pool->shutdown) 
        { 
            printf ("thread 0x%x is waiting\n", pthread_self ()); 
            pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock)); 
        } 

        /*线程池要销毁了*/ 
        if (pool->shutdown) 
        { 
            /*遇到break,continue,return等跳转语句,千万不要忘记先解锁*/ 
            pthread_mutex_unlock (&(pool->queue_lock)); 
            printf ("thread 0x%x will exit\n", pthread_self ()); 
            pthread_exit (NULL); 
        } 

        printf ("thread 0x%x is starting to work\n", pthread_self ()); 

         
        /*待处理任务减1,并取出链表中的头元素*/ 
        pool->cur_task_size--; 
        Cthread_task *task = pool->queue_head; 
        pool->queue_head = task->next; 
        pthread_mutex_unlock (&(pool->queue_lock)); 

        /*调用回调函数,执行任务*/ 
        (*(task->process)) (task->arg); 
        free (task); 
        task = NULL; 
    } 
    /*这一句应该是不可达的*/ 
    pthread_exit (NULL); 
}

/*向线程池中加入任务*/ 
int pool_add_task (void *(*process) (int arg), int arg) 
{ 
    /*构造一个新任务*/ 
    Cthread_task *task = (Cthread_task *) malloc (sizeof (Cthread_task)); 
    task->process = process; 
    task->arg = arg; 
    task->next = NULL;

    pthread_mutex_lock (&(pool->queue_lock)); 
    /*将任务加入到等待队列中*/ 
    Cthread_task *member = pool->queue_head; 
    if (member != NULL) 
    { 
        while (member->next != NULL) 
            member = member->next; 
        member->next = task; 
    } 
    else 
    { 
        pool->queue_head = task; 
    } 

    pool->cur_task_size++; 
    pthread_mutex_unlock (&(pool->queue_lock)); 
    //唤醒一个线程
    //加入
    pthread_cond_signal (&(pool->queue_ready)); 
    
    return 0; 
} 

void handle(char cmd,SSL *ssl)
{
	char filename[30]={0};
	int FileNameSize=0;
	int fd;
	int filesize=0;
	int count=0,totalrecv=0;
	char buf[1024];
	struct stat fstat;
	switch(cmd)
	{
		case 'U':
		{
			//接收文件名
			SSL_read(ssl, &FileNameSize, 4);
			SSL_read(ssl, (void *)filename, FileNameSize);
			filename[FileNameSize]='\0';
			//创建文件
			if((fd = open(filename,O_RDWR|O_CREAT)) == -1)
			{
				perror("creat:");
				_exit(0);	
			}
			//接收文件长度
			SSL_read(ssl, &filesize, 4);
			
			//接收文件
			while((count = SSL_read(ssl,(void *)buf,1024)) > 0)
			{
				write(fd,&buf,count);
				totalrecv += count;
				if(totalrecv == filesize)
					break;	
			}			
			//关闭文件
			close(fd);
		}
		break;
		
		case 'D':
		{
			//接收文件名
			SSL_read(ssl, &FileNameSize, 4);
			SSL_read(ssl, filename, FileNameSize);
			filename[FileNameSize]='\0';
			//打开文件
			if((fd = open(filename,O_RDONLY)) == -1)
			{
				perror("creat:");
				_exit(0);	
			}
			//发送文件长度和文件名
			if((stat(filename,&fstat)) == -1)
				return;
			SSL_write(ssl,&fstat.st_size,4);
			
			while((count = read(fd,(void *)buf,1024)) > 0)
			{
				SSL_write(ssl,&buf,count);	
			}
			close(fd);
		}
		break;	
	}
}

static int callback(void *NotUsed, int argc, char **argv, char **azColName) 
{ 
     int i; 
     for(i=0; i<argc; i++) 
     {          
     	strcpy(passwd_d,argv[i]);
     } 
    return 0;
} 

int login(SSL *ssl)
{
	char username[20];
	char password[20];
	int login_or_create;
	char temp[100];
	char buf[10];
	int  login_flag=0;
	char sql[100];
	int rc;

	sqlite3_open("user.db",&db);
	SSL_read(ssl,temp,100);
	sscanf(temp,"log:%d username:%s password:%s",&login_or_create,username,password);
	//注册
	if(login_or_create == 2)
	{
		sprintf(sql,"insert into stu(username,password) values('%s','%s');",username,password);
		printf("username:%s password:%s\n",username,password);
		rc = sqlite3_exec(db, sql, callback, 0, NULL);
		if(rc == SQLITE_OK)
		{ 
			login_flag = 1;
		} 
		else
		{
			login_flag = 0;
			printf("insert to database error!\n");
		}
	}
	//登录
	else
	{
		sprintf(sql, "select password from stu where username='%s';",username); 
		sqlite3_exec(db, sql, callback, 0, NULL);
		printf("username:%s password:%s\n",username,passwd_d);
		if(strcmp(password,passwd_d) == 0)
		{
			login_flag = 1;
		}
		else
		{
			login_flag = 0;
			return 0;
		}
	}
	sqlite3_close(db);
	sprintf(buf,"login:%d",login_flag);
	SSL_write(ssl,buf,10);
	
	return login_flag;

}
void *myprocess(int args)
{
	SSL *ssl;
	int tmp_fd = args;
	char cmd;

	//产生新的SSL
	ssl = SSL_new(ctx);
	SSL_set_fd(ssl,tmp_fd);
	SSL_accept(ssl);
	//处理事件
	while(1)
	{
		if(login(ssl) == 0)
		{
			SSL_shutdown(ssl);
			SSL_free(ssl);
			close(tmp_fd);
			break;	
		}

		SSL_read(ssl,&cmd,1);
		
		if(cmd == 'Q')
		{
			SSL_shutdown(ssl);
			SSL_free(ssl);
			close(tmp_fd);
			break;	
		}
		else
		{
			handle(cmd,ssl);	
		}
	}
	return NULL;
}


int main()
{
	int newfd;
	char sql[100];
	int rc;
	//初始化线程池
	pool_init(5);

	//创建数据库
	rc = sqlite3_open("user.db",&db);
	if(rc)
	{
		printf("Can't open database: %s\n", sqlite3_errmsg(db)); 
        sqlite3_close(db); 
	}
	sprintf(sql,"create table stu(username char(20), password char(20));");
	rc = sqlite3_exec(db, sql, callback, 0, NULL); 
	if(rc != SQLITE_OK)
	{
		printf("create tables error!\n");
	}
	//建立连接
	
	//SSL连接
	SSL_library_init();
	OpenSSL_add_all_algorithms();
	SSL_load_error_strings();
	ctx = SSL_CTX_new(SSLv23_server_method());
	//载入数字证书
	SSL_CTX_use_certificate_file(ctx,"./cacert.pem",SSL_FILETYPE_PEM);
	//载入私钥
	SSL_CTX_use_PrivateKey_file(ctx,"./privkey.pem",SSL_FILETYPE_PEM);
	SSL_CTX_check_private_key(ctx);
	//创建socket
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
	{
		perror("socket:");
		_exit(0);	
	}
	
	memset(&sockaddr,0, sizeof(sockaddr));
	sockaddr.sin_family = AF_INET;
	sockaddr.sin_port = htons(port);
	sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	//绑定地址
	if(bind(sockfd,(struct sockaddr *)&sockaddr,sizeof(sockaddr)) == -1)
	{
		perror("bind:");
		_exit(0);	
	}
	//监听
	if(listen(sockfd,10) == -1)
	{
		perror("listen");	
	}
	
	while(1)
	{
		//连接
		if((newfd = accept(sockfd, (struct sockaddr *)(&client_addr),&sin_size)) == -1)
		{
			perror("accept:");	
			_exit(0);
		}
		//给线程池添加任务
		pool_add_task(myprocess,newfd);
	}	
	close(sockfd);
	SSL_CTX_free(ctx);
	return 0;
}



客户机:

#include<stdio.h>
#include<string.h>
#include<conio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<unistd.h>

#include <openssl/err.h>
#include <openssl/ssl.h>

#define port 3333

char ipaddr[15];
int sockfd;
struct sockaddr_in sockaddr;
//声明SSL套接字
SSL_CTX *ctx;
SSL *ssl;

int login()
{
	char username[20];
	char password[20];
	char ch;
	int  cnt_ch=0;
	int login_or_create;
	char temp[100];
	char buf[10];
	int  login_flag=0;
	
	printf("please input your selection: 1 to login 2 to create\n");
	printf("selection:");
	scanf("%d",&login_or_create);
	if(login_or_create != 1 && login_or_create != 2)
	{
		return 0;
	}
	printf("username:");
	scanf("%s",username);
	printf("password:");
	while((ch = getch()) != '\n')
	{
		password[cnt_ch] = ch;
		putchar('*');
		cnt_ch++;
	}
	password[cnt_ch] = '\0';
	getchar();
	sprintf(temp,"log:%d username:%s password:%s",login_or_create,username,password);

	SSL_write(ssl,temp,100);
	SSL_read(ssl,buf,10);
	sscanf(buf,"login:%d",&login_flag);

	if(login_flag == 0)
	{
		printf("-----wrong username or password!-------\n");
	}
	else if(login_or_create == 1)
	{
		printf("----------login successufl!------------\n");
	}
	else
	{
		printf("----------create successufl!------------\n");
	}
	//0失败1成功
	return login_flag;
}
int linkS()
{
	//创建socket
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
	{
		perror("socket\n");
		_exit(0);
	}
	//连接
	memset(&sockaddr,0, sizeof(sockaddr));
	sockaddr.sin_family = AF_INET;
	sockaddr.sin_port = htons(port);
	sockaddr.sin_addr.s_addr = inet_addr(ipaddr);
	if(connect(sockfd,(struct sockaddr *)&sockaddr,sizeof(sockaddr)) == -1)
	{
		perror("connect\n");
		_exit(0);
	}
	
	ssl = SSL_new(ctx);
	SSL_set_fd(ssl,sockfd);
	if(SSL_connect(ssl) == -1)
	{
		printf("SSL connect error!\n");	
		_exit(0);
	}

	return login();
}

void upload_file(char *filename)
{
	int fd;
	char cmd = 'U';
	int FileNameSize = strlen(filename);
	char buf[1024];
	int count=0;
	struct stat fstat;
	
	//打开文件
	fd = open(filename,O_RDONLY);
	//发送命令
	SSL_write(ssl,&cmd,1);
	
	//发送文件名
	SSL_write(ssl,(void *)&FileNameSize,4);
	SSL_write(ssl,filename, FileNameSize);
	//发送文件长度
	if((stat(filename,&fstat)) == -1)
		return;
	SSL_write(ssl,(void *)&fstat.st_size,4);
	
	//发送文件数据
	while((count = read(fd,(void *)buf,1024)) > 0)
	{
		SSL_write(ssl,buf,count);	
	}
	//关闭文件
	close(fd);
}

void download_file(char *filename)
{
	int fd;
	char cmd = 'D';
	char buf[1024];
	int FileNameSize = strlen(filename);
	int filesize=0,count=0,totalrecv=0;
	
	//发送命令
	SSL_write(ssl,&cmd,1);
	
	//发送文件名
	SSL_write(ssl,(void *)&FileNameSize,4);
	SSL_write(ssl,filename,FileNameSize);
	
	//打开并创建文件
	if((fd = open(filename,O_RDWR|O_CREAT)) == -1)
	{
		perror("open:");
		_exit(0);	
	}
	
	//接收数据
	SSL_read(ssl,&filesize,4);
	while((count = SSL_read(ssl,(void *)buf,1024)) > 0)
	{
		write(fd,buf,count);
		totalrecv += count;
		if(totalrecv == filesize)
			break;	
	}
	
	//关闭文件
	close(fd);
}

void quit()
{
	char cmd = 'Q';
	//发送命令
	SSL_write(ssl,(void *)&cmd,1);
	//关闭及释放SSL连接
	SSL_shutdown(ssl);
	SSL_free(ssl);
	//退出
	_exit(0);
}
void menu()
{
	char cmd;
	char c;
	char file_u[30];
	char file_d[30];
	while(1)
	{
		printf("----------1.Upload Files---------------\n");
		printf("----------2.Download Files-------------\n");
		printf("----------3.Exit-----------------------\n");
		printf("Please input the Client command:");
		scanf("%c",&cmd);	
		
		switch(cmd)
		{
			case '1':
			{
				printf("Upload Files:");
				//输入文件名
				while((c = getchar()) != '\n' && c != EOF);
				fgets(file_u, 30, stdin);
				file_u[strlen(file_u)-1] = '\0';
				//上传文件
				upload_file(file_u);
			}
			break;	
			case '2':
			{
				printf("Download Files:");
				//输入文件名
				while((c = getchar()) != '\n' && c != EOF);
				fgets(file_d, 30, stdin);
				file_d[strlen(file_d)-1] = '\0';
				//下载文件
				download_file(file_d);
			}
			break;	
			case '3':
			{
				//退出
				quit();
				break;
			}
			break;	
			default:
			{
				printf("Please input right command!\n");	
			}
			break;	
		}
	}	
}
int main(int argc, char *args[])
{
	if(argc != 2)
	{
		printf("format error: you mast enter ipaddr like this : client 192.168.0.6\n");
	    	_exit(0);	
	}
	strcpy(ipaddr,args[1]);
	
	//初始化SSl
	SSL_library_init();
	OpenSSL_add_all_algorithms();
	SSL_load_error_strings();
	//创建SSL套接字,参数表明支持版本和客户机
	ctx = SSL_CTX_new(SSLv23_client_method());
	if(ctx == NULL)
	{
		printf("Creat CTX error!!!");	
	}
	
	//建立连接
	if(linkS() == 0)
	{
		printf("user name or password error!\n");
		//关闭及释放SSL连接
		SSL_shutdown(ssl);
		SSL_free(ssl);
		//清屏
		system("clear");
		_exit(0);
	}
	//打印菜单
	menu();
	//结尾操作
	close(sockfd);
	//释放CTX
	SSL_CTX_free(ctx);
	return 0;	
}

更多Linux资料及视频教程点击这里

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值