头文件:
#ifndef __HEAD_H__
#define __HEAD_H__
#include <stdio.h>
#include <errno.h> //错误码的头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //open的头文件
#include <unistd.h> //close\sleep的头文件
#include <string.h> //str系列函数头文件
#include <math.h> //数学头文件
#include <stdlib.h> //标准库文件
#include <time.h> //时间头文件
#include <dirent.h> //目录操作头文件
#include <sys/wait.h> //进程回收
#include <pthread.h> //关于线程操作的头文件
#include <semaphore.h> //信号量头文件
#include <signal.h> //信号的头文件
#include <sys/ipc.h> //system V进程通信头文件
#include <sys/msg.h> //消息队列头文件
#include <sys/shm.h> //共享内存头文件
#include <sys/sem.h> //信号灯集头文件
#include <arpa/inet.h> //字节序转换函数
#include <sys/socket.h>
#include <netinet/in.h> //点分十进制--网络字节序的操作头文件
#include <linux/input.h>
#include <sys/epoll.h>
#include <poll.h> //监测集合中文件描述符的头文件
#include <sys/un.h> //域套接字头文件
#include <sqlite3.h> //数据库头文件
#define ERR_MSG(msg) do{printf("%s:%s:%d\n",__FILE__,__func__,__LINE__);\
perror(msg);\
return -1;}while(0)
#endif
源文件:
#include "head.h"
#define IP "192.168.125.170 "
#define PORT 8888
/*
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events;
epoll_data_t data;
};
*/
struct message{
char head[20];
char msg[128];
char name[32];
};
sqlite3* db_books = NULL;
int epfd=0;
int create_table(sqlite3* db_books);
int determine_member(int cfd,struct message cli_buf);
int search(int cfd,struct message cli_buf);
int add_book(int cfd,struct message cli_buf);
int update(int cfd,struct message cli_buf);
int delete(int cfd,struct message cli_buf);
int search_history(int cfd);
int borrow_books(int cfd,struct message cli_buf);
int return_books(int cfd,struct message cli_buf);
int main(int argc, const char *argv[])
{
//打开数据库,并创建人员信息表,图书信息表,借阅信息表
if(sqlite3_open("./books.db",&db_books) != SQLITE_OK)
{
printf("errmsg:%s\n",sqlite3_errmsg(db_books));
fprintf(stderr,"__%d__ sqlite3_open failed\n",__LINE__);
return -1;
}
printf("打开数据库成功\n");
create_table(db_books);
//创建流式套接字
int sfd = socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
ERR_MSG("socket");
}
printf("socket success\n");
//允许端口快速被重用
int reuse=1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
{
ERR_MSG("setsockopt");
}
printf("setsockopt success\n");
//填充服务器的ip和端口
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(PORT);
sin.sin_addr.s_addr=inet_addr(IP);
//绑定服务器的地址信息
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("bind");
}
printf("bind success\n");
//设置套接字为被动监听状态
if(listen(sfd,128)<0)
{
ERR_MSG("listen");
}
printf("listen success\n");
//存储客户端地址信息
struct sockaddr_in cin;
socklen_t addrlen=sizeof(cin);
//定义事件结构体
struct epoll_event event;
//定义存放就绪事件描述符的数组
struct epoll_event events[20];
//创建红黑树根节点
epfd = epoll_create(1);
if(epfd<0)
{
ERR_MSG("epoll_create");
}
printf("成功创建红黑树根节点\n");
//添加要检测的事件描述符
event.events=EPOLLIN;
event.data.fd=sfd;
if(epoll_ctl(epfd,EPOLL_CTL_ADD,sfd,&event)<0)
{
ERR_MSG("epoll_ctl");
}
printf("成功将sfd事件描述符挂载到红黑树上\n");
struct message buf;
char msg[sizeof(buf)]="";
int newfd=-1;
while(1)
{
memset(&buf,0,sizeof(buf));
int ret=epoll_wait(epfd,events,20,-1);
for(int i=0;i<ret;i++)
{
if(events[i].data.fd == sfd)
{
//获取连接成功后的新套接字
newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
if(newfd<0)
{
ERR_MSG("accept");
}
printf("[%s : %d] newfd=%d 客户端连接成功\n", \
inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);
//添加要检测的事件描述符
event.events=EPOLLIN;
event.data.fd=newfd;
if(epoll_ctl(epfd,EPOLL_CTL_ADD,newfd,&event)<0)
{
ERR_MSG("epoll_ctl");
}
printf("成功将newfd:%d事件描述符挂载到红黑树上\n",newfd);
}
else
{
int cfd=events[i].data.fd;
int len=read(cfd,msg,sizeof(msg));
memcpy(&buf,msg,sizeof(msg));
if(len<=0)
{
close(cfd);
epoll_ctl(epfd,EPOLL_CTL_DEL,cfd,NULL);
}
char c=buf.head[0];
switch(c)
{
case '1':
//1.查询图书信息
search(cfd,buf);
break;
case '2':
//2.添加图书
add_book(cfd,buf);
break;
case '3':
//3.更改图书信息
update(cfd,buf);
break;
case '4':
//4.删除图书
delete(cfd,buf);
break;
case '5':
//5.查阅借阅记录
search_history(cfd);
break;
case '6':
//6.退出
epoll_ctl(epfd,EPOLL_CTL_DEL,cfd,NULL);
close(cfd);
printf("成功退出\n");
break;
case '7':
//7.借阅书籍
borrow_books(cfd,buf);
break;
case '8':
//8.归还书籍
return_books(cfd,buf);
break;
case '9':
//判断是管理员还是普通用户
determine_member(cfd,buf);
break;
}
}
}
}
//关闭文件描述符
if(close(sfd) < 0)
{
ERR_MSG("close");
return -1;
}
return 0;
}
//打开数据库,并创建人员信息表,图书信息表,借阅信息表
int create_table(sqlite3* db_books)
{
//创建一个人员信息表格(用于判断是否是管理员id--管理员:y,普通用户:n)
char sql[128] = "create table if not exists members (id char,name char,password char)";
char* errmsg = NULL;
if(sqlite3_exec(db_books,sql,NULL,NULL,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"__%d__ sqlite3_exec:%s\n",__LINE__,errmsg);
return -1;
}
//创建一个图书信息表格(书名,作者,个数)
bzero(sql,sizeof(sql));
strcpy(sql, "create table if not exists books (title char,author char,number char)");
if(sqlite3_exec(db_books,sql,NULL,NULL,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"__%d__ sqlite3_exec:%s\n",__LINE__,errmsg);
return -1;
}
//创建一个借阅信息表格(书名,借书人,状态0-归还,1-借阅)
bzero(sql,sizeof(sql));
strcpy(sql, "create table if not exists history (title char,name char,state char)");
if(sqlite3_exec(db_books,sql,NULL,NULL,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"__%d__ sqlite3_exec:%s\n",__LINE__,errmsg);
return -1;
}
}
//判断是管理员还是普通用户
int determine_member(int cfd,struct message cli_buf)
{
char name[128]="";
char password[128]="";
bzero(name,sizeof(name));
bzero(password,sizeof(password));
sprintf(name,"%s",cli_buf.name);
sprintf(password,"%s",cli_buf.msg);
struct message buf;
memset(&buf,0,sizeof(buf));
char **results=NULL;
int rows, cols;
char* errmsg=NULL;
//查询用户登录是否正确,并且是否是管理员
char sql[256]="";
bzero(sql,sizeof(sql));
snprintf(sql, sizeof(sql), "SELECT id FROM members WHERE name='%s' AND password='%s';", name, password);
if(sqlite3_get_table(db_books,sql,&results,&rows,&cols,&errmsg)!=SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
ssize_t res=0;
if(rows>0)
{
if(strcmp((char*)results[1],"1")==0)
{
strcpy(buf.head,"1");
res=write(cfd,&buf,sizeof(buf));
}
else
{
strcpy(buf.head,"2");
res=write(cfd,&buf,sizeof(buf));
}
}
if(res<0)
{
printf("发送数据失败\n");
}
else{
printf("发送数据成功\n");
}
return 0;
}
//1.查询图书信息
int search(int cfd,struct message cli_buf)
{
char title[32]="";
bzero(title,sizeof(title));
sprintf(title,"%s",cli_buf.msg);
struct message buf;
memset(&buf,0,sizeof(buf));
char **results=NULL;
int rows, cols;
char* errmsg=NULL;
//查询图书信息
char sql[256]="";
snprintf(sql, sizeof(sql), "SELECT * FROM books WHERE title='%s'", title);
if(sqlite3_get_table(db_books,sql,&results,&rows,&cols,&errmsg)!=SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
printf("%s %s %s\n",results[3],results[4],results[5]);
ssize_t res=0;
if(rows>0)
{
if(strcmp((char*)results[3],title)==0)
{
strcpy(buf.head,results[3]);
strcpy(buf.name,results[4]);
strcpy(buf.msg,results[5]);
res=write(cfd,&buf,sizeof(buf));
}
else
{
strcpy(buf.msg,"没有相关的书名,请重新输入");
res=write(cfd,&buf,sizeof(buf));
}
}
if(res<0)
{
printf("发送数据失败\n");
}
else{
printf("发送数据成功\n");
}
return 0;
}
//2.添加图书
int add_book(int cfd,struct message cli_buf)
{
struct message buf;
memset(&buf,0,sizeof(buf));
char title[32]="";
sprintf(title,"%s",cli_buf.head+1);
char* errmsg=NULL;
//查询图书信息
char sql[256]="";
bzero(sql,sizeof(sql));
snprintf(sql, sizeof(sql), "INSERT INTO books ('title','author','number') values (\"%s\",\"%s\",\"%s\")",title,cli_buf.name,cli_buf.msg);
if(sqlite3_exec(db_books,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
strcpy(buf.msg,"insert success");
write(cfd,&buf,sizeof(buf));
printf("插入%s成功\n",cli_buf.head);
return 0;
}
//3.更改图书信息
int update(int cfd,struct message cli_buf)
{
struct message buf;
memset(&buf,0,sizeof(buf));
char title[12]="";
sprintf(title,"%s",cli_buf.head+1);
char* errmsg=NULL;
char **results=NULL;
int rows, cols;
//查询图书信息
char sql[256]="";
bzero(sql,sizeof(sql));
snprintf(sql, sizeof(sql), "update books set author=\"%s\",number=\"%s\" where title=\"%s\";",cli_buf.name,cli_buf.msg,title);
if(sqlite3_get_table(db_books,sql,&results,&rows,&cols,&errmsg)!=SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
if(rows>0)
{
strcpy(buf.msg,"update success");
write(cfd,&buf,sizeof(buf));
printf("修改%s信息成功\n",title);
}
else if(rows<0)
{
strcpy(buf.msg,"update failed");
write(cfd,&buf,sizeof(buf));
printf("没有%s的书籍,删除失败\n",title);
}
return 0;
}
//4.删除图书
int delete(int cfd,struct message cli_buf)
{
struct message buf;
memset(&buf,0,sizeof(buf));
char title[12]="";
sprintf(title,"%s",cli_buf.head+1);
char* errmsg=NULL;
char **results=NULL;
int rows, cols;
//删除图书
char sql[256]="";
snprintf(sql, sizeof(sql), "delete from books where title='%s'",title);
if(sqlite3_get_table(db_books,sql,&results,&rows,&cols,&errmsg)!=SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
if(rows>0)
{
strcpy(buf.msg,"delete success");
write(cfd,&buf,sizeof(buf));
printf("删除%s信息成功\n",title);
}
else
{
strcpy(buf.msg,"delete failed");
write(cfd,&buf,sizeof(buf));
printf("没有%s的书籍,删除失败\n",title);
}
return 0;
}
//5.查阅借阅记录
int search_history(int cfd)
{
char sql[128]="";
char **results=NULL;
int rows,cols;
char *errmsg=NULL;
struct message buf;
bzero(sql,sizeof(sql));
sprintf(sql,"select *from history");
if(sqlite3_get_table(db_books,sql,&results,&rows,&cols,&errmsg)!=SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
if(rows>0)
for(int i=3;i<(rows*cols);i++)
{
strcpy(buf.msg,results[i]);
}
else
{
strcpy(buf.msg,"没有借阅信息");
}
write(cfd,&buf,sizeof(buf));
printf("成功查阅借阅记录\n");
return 0;
}
//7.借阅书籍
int borrow_books(int cfd,struct message cli_buf)
{
struct message buf;
memset(&buf,0,sizeof(buf));
char book_name[32]="";
bzero(book_name,sizeof(book_name));
strcpy(book_name,cli_buf.head+1);
char **results=NULL;
int rows=0, cols=0;
char* errmsg=NULL;
//借阅书籍
char sql[256]="";
snprintf(sql, sizeof(sql), "select number from books where title=\"%s\";",book_name);
if(sqlite3_get_table(db_books,sql,&results,&rows,&cols,&errmsg)!=SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
if(rows>0)
{
//运行到这,说明有这本书,判断输出个数,对id进行操作
if(strcmp(results[5],"0")==0)
{
//查到有此书,但是书的个数为0不能被借阅
strcpy(buf.msg,"已全部被借阅");
}
else
{
//可以被借阅,书的个数-1
bzero(sql,sizeof(sql));
snprintf(sql,sizeof(sql),"update books set number=\"%s\" where title=\"%s\";",results[5]-1,book_name);
if(sqlite3_get_table(db_books,sql,&results,&rows,&cols,&errmsg)!=SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
//添加记录到历史记录表中
bzero(sql,sizeof(sql));
char c[5]="1";
snprintf(sql,sizeof(sql),"insert into history (title,name,state) values (\"%s\",\"%s\",\"%s\")",book_name,cli_buf.name,c);
if(sqlite3_exec(db_books,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
printf("成功添加借阅记录\n");
strcpy(buf.msg,"borrow success");
printf("成功借阅%s\n",book_name);
}
}
else if(rows<0)
{
strcpy(buf.msg,"delete failed");
printf("没有%s的书籍,借阅失败\n",book_name);
}
write(cfd,&buf,sizeof(buf));
return 0;
}
//8.归还书籍
int return_books(int cfd,struct message cli_buf)
{
struct message buf;
memset(&buf,0,sizeof(buf));
char title[32]="";
bzero(title,sizeof(title));
sprintf(title,"%s",cli_buf.msg);
char* errmsg=NULL;
char **results=NULL;
int rows, cols;
//归还书籍
char sql[256]="";
bzero(sql,sizeof(sql));
snprintf(sql, sizeof(sql), "select number from books where title='%s'",title);
if(sqlite3_get_table(db_books,sql,&results,&rows,&cols,&errmsg)!=SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
if(rows>0)
{
//可以归还,书的个数+1
bzero(sql,sizeof(sql));
snprintf(sql,sizeof(sql),"update books set number=\"%s\" where title=\"%s\"",results[5]+1,title);
if(sqlite3_get_table(db_books,sql,&results,&rows,&cols,&errmsg)!=SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
//修改借阅记录的状态,显示已归还
bzero(sql,sizeof(sql));
snprintf(sql,sizeof(sql),"update history set state=\"%s\" where title='%s'","0",title);
if(sqlite3_get_table(db_books,sql,&results,&rows,&cols,&errmsg)!=SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
strcpy(buf.msg,"return success");
printf("成功归还图书\n");
}
else if(rows==0)
{
strcpy(buf.msg,"delete failed");
printf("没有%s的书籍,归还失败\n",title);
}
write(cfd,&buf,sizeof(buf));
return 0;
}