搭建服務器客戶端,要求 服務器使用 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數據庫