使用epoll与sqlite3进行注册登录
将 epoll 服务器 客户端拿来用
客户端:写一个界面,里面有注册登录
服务器:处理注册和登录逻辑,注册的话将注册的账号密码写入数据库,登录的话查询数据库中是否存在账号,并验证密码是否正确
额外功能:客户端登录的时候,服务器向客户端发送一个验证码,只有验证码也正确的时候,才能登录成功·
server.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
#include <sys/epoll.h>
#include <sqlite3.h>
#include <time.h>
typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
int sqllen;
enum Type{
TYPE_REGIST,
TYPE_LOGIN
};
typedef struct pack{
enum Type type;
char name[20];
char pwd[20];
int auth;
}pack_t;
void read_data(int client);
int callback(void* arg,int argc,char** argv,char** col);
void* thread_main(void* arg)//验证码验证
{
int client=*(int *)arg;
pack_t pack={0};
srand(time(0));
pack.auth=rand()%10000+1;
int test=pack.auth;
write(client,&pack,sizeof(pack));
read(client,&pack,sizeof(pack));
if(test==pack.auth)
{
printf("登录成功");
}else
{
printf("验证码错误\n");
}
}
int main(int argc, const char *argv[])
{
if(argc!=2)
{
printf("请输入端口号\n");
return 0;
}
int port=atoi(argv[1]);
//为服务器准备套接字
int server=socket(AF_INET,SOCK_STREAM,0);
//准备网络地址结构体
addr_in_t addr={0};
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
addr.sin_addr.s_addr=inet_addr("0.0.0.0");
//为套接字绑定ip和port
if(bind(server,(addr_t*)&addr,sizeof(addr))==-1)
{
perror("bind");
return 1;
}
//监听
listen(server,10);
//动态监视列表
int epfd=epoll_create1(EPOLL_CLOEXEC);
//设定需要监视描述符,及激活形式
struct epoll_event event_server={.events=EPOLLIN, .data.fd=server};
struct epoll_event event_stdin={.events=EPOLLIN, .data.fd=0};
//添加到监视列表
epoll_ctl(epfd,EPOLL_CTL_ADD,server,&event_server);
epoll_ctl(epfd,EPOLL_CTL_ADD,0,&event_stdin);
//准备数组,存放激活的描述符
struct epoll_event arr[50]={0};
while(1)
{
int len=epoll_wait(epfd,arr,50,-1);
for(int i=0;i<len;i++)
{
int fd=arr[i].data.fd;//取出激活的描述符
if(fd==server)
{
printf("有新的客户端链接\n");
int client=accept(server,0,0);
struct epoll_event epoll_client={
.events=EPOLLIN,
.data.fd=client
};
epoll_ctl(epfd,EPOLL_CTL_ADD,client,&epoll_client);
}
else if(fd==0)
{
char buf[64]="";
scanf("%63s",buf);
while(getchar()!=10);
printf("键盘输入值为:%s\n",buf);
}
else
{
read_data(fd);
}
}
}
return 0;
}
void read_data(int client)
{
pack_t pack={0};
int res=read(client,&pack,sizeof(pack));
if(res==0)
{
printf("断开连接\n");
}
sqlite3* db=NULL;
if(sqlite3_open("./login.db",&db)!=SQLITE_OK)
{
printf("数据库打开失败\n");
return ;
}
switch(pack.type)
{
case TYPE_REGIST:
{
char sql[128]="";
char* errmsg=NULL;
sprintf(sql,"insert into login(name,pwd) values('%s','%s')",pack.name,pack.pwd);
if(sqlite3_exec(db,sql,0,0,&errmsg)!=SQLITE_OK)
{
fprintf(stderr,"errmsg=%s\n",errmsg);
}
printf("注册成功\n");
break;
}
case TYPE_LOGIN:
{
int flag=0;
pack_t arr[20]={0};
char* sql="select*from login;";
char* errmsg=NULL;
if(sqlite3_exec(db,sql,callback,arr,&errmsg)!=SQLITE_OK)
{
fprintf(stderr,"errmsg=%s\n",errmsg);
}
for(int i=0;i<sqllen;i++)
{
if(strcmp(arr[i].name,pack.name)==0 && strcmp(arr[i].pwd,pack.pwd)==0)//判断登录
{
pthread_t id;
pthread_create(&id,0,thread_main,&client);//线程判断验证码
pthread_detach(id);
flag=1;
}
}
if(flag==0)
{
printf("登录失败\n");
}
}
}
return ;
}
int callback(void* arg,int argc,char** argv,char** col)
{
pack_t* arr=(pack_t*)arg;
strcpy(arr[sqllen].name,argv[0]);
strcpy(arr[sqllen].pwd,argv[1]);
sqllen++;
printf("一共%d个数据\n",sqllen);
return 0;
}
client.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
enum Type{
TYPE_REGIST,
TYPE_LOGIN
};
typedef struct pack{
enum Type type;
char name[20];
char pwd[20];
int auth;
}pack_t;
void* thread_main(void* arg)
{
int client=*(int *)arg;
pack_t pack;
read(client,&pack,sizeof(pack));
printf("验证码为:%d\n",pack.auth);
printf("请输入验证码\n");
scanf("%d",&pack.auth);
while(getchar()!=10);
write(client,&pack,sizeof(pack));
}
int main(int argc, const char *argv[])
{
if(argc!=2)
{
printf("请输入端口号\n");
return 0;
}
int port=atoi(argv[1]);
int client=socket(AF_INET,SOCK_STREAM,0);
addr_in_t addr={0};
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
addr.sin_addr.s_addr=inet_addr("192.168.126.86");
if(connect(client,(addr_t*)&addr,sizeof(addr))==-1)
{
perror("connect");
return 1;
}
while(1)
{
int ch=-1;
printf("请选择\n");
printf("1:注册\n");
printf("2:登录\n");
printf("0:退出\n");
scanf("%d",&ch);
while(getchar()!=10);
switch(ch)
{
case 1:{
pack_t pack = {0};
printf("请输入账号:");
scanf("%s",pack.name);
while(getchar()!=10);
printf("请输入密码:");
scanf("%s",pack.pwd);
while(getchar()!=10);
pack.type = TYPE_REGIST;
write(client,&pack,sizeof(pack));
break;
}
case 2:{
pack_t pack = {0};
printf("请输入账号:");
scanf("%s",pack.name);
while(getchar()!=10);
printf("请输入密码:");
scanf("%s",pack.pwd);
while(getchar()!=10);
pack.type = TYPE_LOGIN;
write(client,&pack,sizeof(pack));
pthread_t id;
pthread_create(&id,0,thread_main,&client);
pthread_detach(id);
break;
}
case 0:
{
exit(0);
}
}
}
return 0;
}