搭建服务器客户端,要求 服务器使用 epoll 模型 客户端使用多线程 服务器打开数据库,表单格式如下 name text primary key pswd text not null 客户端做一个简单的界面:
1:注册
2:登录
无论注册还是登录,都需要输入账号密码后,发送给服务器 服务器接受到账号密码之后,判断一下是注册还是登录
如果是注册: 将账号密码写入数据库 如果写入失败,则通知客户端 "该账号已存在"
如果写入成功,则通知客户端 "注册成功"
如果是登录 判断账号是否存在 如果不存在,则通知客户端 "该账号不存在"
如果存在,则继续比对密码 如果密码错误,则通知客户端 "密码错误"
如果密码正确,则通知客户端 "登录成功"
client代码段:#include <25051head.h>
#include <sqlite3.h>
enum Type{TYPE_REGIST,TYPE_LOGIN
};enum Err{SUCCESS,ERR_NAME,ERR_PSWD
};typedef struct Pack{enum Type type;enum Err err;char name[16];char pswd[16];
}pack_t;pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;void* pthread_func(void* arg)
{pthread_mutex_lock(&mutex2);int client = *(int*)arg;pack_t pack = {0};while(1){int n = read(client,&pack,sizeof(pack));if (n <= 0){printf("服务器断开连接\n");break;}switch(pack.type){case TYPE_REGIST:{if (pack.err == SUCCESS){printf("\n账号创建成功!\n\n");}else{printf("\n账号创建失败!\n\n");}pthread_mutex_unlock(&mutex1);break;}case TYPE_LOGIN:{if (pack.err == SUCCESS){printf("\n登录成功!\n\n");}else if (pack.err == ERR_NAME){printf("\n请检查用户名是否输入有误!\n\n");}else{printf("\n请检查密码是否输入有误!\n\n");}pthread_mutex_unlock(&mutex1);break;}}}return NULL;
}int main(int argc, const char *argv[])
{if (argc < 2){printf("请输入端口号:");return 1;}short port = atoi(argv[1]);int client = socket(AF_INET,SOCK_STREAM,0);struct sockaddr_in addr4 = {0};addr4.sin_family = AF_INET;addr4.sin_port = htons(port);addr4.sin_addr.s_addr = inet_addr("127.0.0.1");connect(client,(struct sockaddr*)&addr4,sizeof(addr4));pthread_t tid;int *client_ptr = malloc(sizeof(int));*client_ptr = client;pthread_create(&tid, 0, pthread_func, client_ptr);int ch = 0;pthread_mutex_lock(&mutex2);while(1){pthread_mutex_lock(&mutex1);pack_t pack = {0};printf("====菜单====\n");printf("1.注册\n");printf("2.登录\n");printf("请输入你的选择:");scanf("%d",&ch);getchar();putchar('\n');switch(ch){case 1:{printf("请设置您的账号:");scanf("%s",pack.name);getchar();printf("请设置您的密码:");scanf("%s",pack.pswd);getchar();pack.type = TYPE_REGIST;write(client,&pack,sizeof(pack));break;}case 2:{printf("请输入账号:");scanf("%s",pack.name);getchar();printf("请输入密码:");scanf("%s",pack.pswd);getchar();pack.type = TYPE_LOGIN;write(client,&pack,sizeof(pack));sleep(1);break;}default:{printf("输入错误,请重新输入!\n");break;}}pthread_mutex_unlock(&mutex2);}return 0;
}
server服务器端代码:(epoll模型)#include <25051head.h>
#include <sqlite3.h>
enum Type{TYPE_REGIST,TYPE_LOGIN
};enum Err{SUCCESS,ERR_NAME,ERR_PSWD
};typedef struct Pack{enum Type type;enum Err err;char name[16];char pswd[16];
}pack_t;void regist(pack_t* pack,int client,sqlite3* db)
{sqlite3_stmt* stmt = NULL;char* sql = "insert into users(name,pswd) values(?,?)";int res = sqlite3_prepare_v2(db,sql,-1,&stmt,NULL);if (res != SQLITE_OK){pack->err = ERR_NAME;}sqlite3_bind_text(stmt,1,pack->name,-1,NULL);sqlite3_bind_text(stmt,2,pack->pswd,-1,NULL);res = sqlite3_step(stmt);if(res == SQLITE_DONE){pack->err = SUCCESS;}else{pack->err = ERR_NAME;}//pack.type = TYPE_REGIST;sqlite3_finalize(stmt);write(client,pack,sizeof(*pack));
}void login(pack_t* pack,int client,sqlite3* db)
{sqlite3_stmt* stmt = NULL;char* sql = "select pswd from users where name = ?";int res = sqlite3_prepare_v2(db,sql,-1,&stmt,NULL);if (res != SQLITE_OK){pack->err = ERR_NAME;}sqlite3_bind_text(stmt,1,pack->name,-1,NULL);res = sqlite3_step(stmt);if(res == SQLITE_DONE){pack->err = ERR_NAME; }else if (res == SQLITE_ROW){const char* db_pswd = sqlite3_column_text(stmt,0);if(strcmp(db_pswd,pack->pswd) == 0){pack->err = SUCCESS;}else{pack->err = ERR_PSWD;}}sqlite3_finalize(stmt);write(client,pack,sizeof(*pack));
}int main(int argc, const char *argv[])
{if(argc < 2){printf("请输入端口号\n");return 1;}short port = atoi(argv[1]);// "abc123" -> 0int server = socket(AF_INET,SOCK_STREAM,0);struct sockaddr_in addr = {0};addr.sin_family = AF_INET; addr.sin_port = htons(port);addr.sin_addr.s_addr = inet_addr("0.0.0.0");if(bind(server,(struct sockaddr*)&addr,sizeof(addr)) == -1){perror("bind");return 1;}listen(server,10);sqlite3* db = NULL;sqlite3_open("./lx.db",&db);int epfd = epoll_create1(EPOLL_CLOEXEC);struct epoll_event epoll_stdin = {.events = EPOLLIN , .data.fd = 0};struct epoll_event epoll_server = {.events = EPOLLIN , .data.fd = server};epoll_ctl(epfd,EPOLL_CTL_ADD,0,&epoll_stdin);epoll_ctl(epfd,EPOLL_CTL_ADD,server,&epoll_server);int eplen = 2;while(1){// 提前准备一个激活列表struct epoll_event list[20] = {0};int count = epoll_wait(epfd,list,20,-1);for(int i=0;i<count;i++){int fd = list[i].data.fd;if(fd == 0){char buf[1024] = "";scanf("%s",buf);getchar();printf("键盘输入数据:%s\n",buf);continue;}if(fd == server){printf("有客户端连接\n");struct sockaddr_in client_addr = {0};int client_len = sizeof(client_addr);int client = accept(server,(struct sockaddr*)&client_addr,&client_len);printf("新连接的客户端的ip = %s\n",inet_ntoa(client_addr.sin_addr));printf("新连接的客户端的port = %d\n",ntohs(client_addr.sin_port));struct epoll_event epoll_client = {.events = EPOLLIN , .data.fd = client};epoll_ctl(epfd,EPOLL_CTL_ADD,client,&epoll_client);eplen ++;continue;}pack_t pack = {0};int res = read(fd,&pack,sizeof(pack));if(res == 0){printf("客户端断开连接\n");epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);continue;}switch(pack.type){case TYPE_REGIST:{regist(&pack,fd,db);break;}case TYPE_LOGIN:{login(&pack,fd,db);break;}}}}return 0;
}
选择使用的是sqlite3数据库