网络编程项目(聊天室项目)
一、實現(xiàn)目標(biāo)
一個在Linux下可以使用的聊天軟件,要求至少實現(xiàn)如下功能:
1. 采用Client/Server架構(gòu)
2. Client A 登陸聊天服務(wù)器前,需要注冊自己的ID和密碼
3. 注冊成功后,Client A 就可以通過自己的ID和密碼登陸聊天服務(wù)器
4. 多個Client X 可以同時登陸聊天服務(wù)器之后,與其他用戶進行通訊聊天
5. Client A 成功登陸后可以查看當(dāng)前聊天室內(nèi)其他子啊先用戶Client x
6. Client A 可以選擇發(fā)消息給某個特定的 Client x,即“悄悄話”功能
7. Client A 可以選擇發(fā)消息給全部的在線用戶,即“群發(fā)消息”功能
8. Client A 在退出時需要保存聊天記錄
9. Server 端維護一個所有登陸用戶的聊天會的記錄文件,以便查看
可以選擇實現(xiàn)的附加功能:
1. Server 可以內(nèi)建一個特殊權(quán)限的賬號admin,用于管理聊天室
2. Admin 可以將某個Client X“踢出聊天室”
3. Admin 可以將某個Client X“設(shè)為只能旁聽,不能發(fā)言”
4. Client 端發(fā)言增加表情符號,可以設(shè)置某些自定義的特殊組和來表達(dá)感情,如輸入:),則會自動發(fā)送“XXX向大家做了個笑臉”
5. Client 段增加某些常用話語,可以對其中某些部分進行“姓名替換”,例如,輸入/ClientA/welcome,則會自動發(fā)送“ClientA大俠,歡迎你來到咱們的聊天室”
Client.c源文件
Server.c源文件
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> #include <stdlib.h> #include <sqlite3.h> #define PORT 9999sqlite3 * database;// 協(xié)議 struct Msg {char msg[1024]; // 消息內(nèi)容int cmd; // 消息類型char filename[50]; // 保存文件名char toname[20]; // 接收者姓名char fromname[20]; // 發(fā)送者姓名int sig; // 用戶狀態(tài)(0:管理員、1:普通用戶、2:被禁言) };// 初始化套接字,返回監(jiān)聽套接字 int init_socket() {//1、創(chuàng)建socketint listen_socket = socket(AF_INET, SOCK_STREAM, 0);if (listen_socket == -1){perror ("socket");return -1;}// 2、命名套接字,綁定本地的ip地址和端口struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET; // 設(shè)置地址族addr.sin_port = htons(PORT); // 設(shè)置本地端口addr.sin_addr.s_addr = htonl(INADDR_ANY); // 使用本地的任意IP地址int ret = bind(listen_socket, (struct sockaddr *)&addr, sizeof(addr));if (ret == -1){perror ("bind");return -1;}// 3、監(jiān)聽本地套接字ret = listen(listen_socket, 5);if (ret == -1){perror ("listen");return -1;}printf ("服務(wù)器已就緒,等待客戶端連接.......\n");return listen_socket; }// 處理客戶端連接,返回與連接上的客戶端通信的套接字 int MyAccept(int listen_socket) {// 4、接收連接struct sockaddr_in client_addr; // 用來保存客戶端的ip和端口信息int len = sizeof(client_addr);int client_socket = accept(listen_socket, (struct sockaddr *)&client_addr, &len);if (client_socket == -1){perror ("accept");}printf ("成功接收一個客戶端: %s\n", inet_ntoa(client_addr.sin_addr));return client_socket; }// 查看當(dāng)前在線人數(shù) void display (int client_socket, struct Msg *msg) {printf ("查看當(dāng)前在線人數(shù)\n");// 確認(rèn)flag參數(shù)// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 與User表中信息進行比對char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}int count = 0;int i;for (i = 3+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], "1") == 0){count++;}}// 返回在線人數(shù)msg->cmd = count;printf ("當(dāng)前在線人數(shù)為:%d\n", msg->cmd);write (client_socket, msg, sizeof(struct Msg));sqlite3_free_table(resultp);// 關(guān)閉數(shù)據(jù)庫sqlite3_close(database);printf ("操作完成,已關(guān)閉數(shù)據(jù)庫\n"); }// 退出聊天室,返回登錄界面 void quit_chatroom (int client_socket, struct Msg *msg) {printf ("%s 退出聊天室\n", msg->fromname);// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");return;}char buf[100];char *errmsg = NULL;errmsg = NULL;sprintf (buf, "update user set flag = 0 where name = '%s'",msg->fromname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);return;}sqlite3_close(database);printf ("登錄狀態(tài)修改完畢,已關(guān)閉數(shù)據(jù)庫\n");write (client_socket, msg, sizeof(struct Msg)); }// 客戶端發(fā)送群聊消息 void chat1 (int client_socket, struct Msg *msg) {printf ("%s 發(fā)了一條群消息\n",msg->fromname);// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數(shù)據(jù)庫中的flag參數(shù)信息char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}int i;for (i = 3+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){// 查詢所有在線的用戶if(strcmp(resultp[i], "1") == 0){msg->cmd = 9001; write (atoi(resultp[i-1]), msg, sizeof(struct Msg)); }}printf ("群消息已全部發(fā)送完成\n"); }// 客戶端發(fā)送私聊消息 void chat2 (int client_socket, struct Msg *msg) {printf ("%s 向 %s 發(fā)了一條消息\n",msg->fromname,msg->toname);// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數(shù)據(jù)庫中的flag參數(shù)信息,判斷是否在線char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){msg->cmd = 9002;write (atoi(resultp[i+2]), msg, sizeof(struct Msg));return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg)); }// 處理確認(rèn)文件傳輸對象 void convey_confirm (int client_socket, struct Msg *msg) {printf ("%s 向 %s 發(fā)送文件傳輸請求\n",msg->fromname,msg->toname);// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");return;}// 獲取數(shù)據(jù)庫中的flag參數(shù)信息char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);return;}int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){msg->cmd = 9004;write (atoi(resultp[i+2]), msg, sizeof(struct Msg));return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg)); }// 用戶不接受文件 void refuse (int client_socket, struct Msg *msg) {printf ("%s 拒絕了 %s 的文件傳輸請求\n",msg->fromname,msg->toname);// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");return;}// 獲取數(shù)據(jù)庫中 toname 的套接字char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);return;}int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){write (atoi(resultp[i+2]), msg, sizeof(struct Msg));return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg)); }// 用戶接受文件 void accept_ (int client_socket, struct Msg *msg) {printf ("%s 通過了 %s 的文件傳輸請求\n",msg->fromname,msg->toname);// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");return;}// 獲取數(shù)據(jù)庫中 toname 的套接字char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);return;}int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){write (atoi(resultp[i+2]), msg, sizeof(struct Msg));return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg)); }// 處理文件傳輸 void convey_chose (int client_socket, struct Msg *msg) {printf ("%s正在向%s傳輸文件......\n",msg->fromname,msg->toname);// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數(shù)據(jù)庫中的 flag 參數(shù)信息,判斷是否在線char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取toname的套接字int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){write (atoi(resultp[i+2]), msg, sizeof(struct Msg));return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg)); }// 文件傳輸完成 void convey_complete (int client_socket, struct Msg *msg) {printf ("文件傳輸結(jié)束\n");// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數(shù)據(jù)庫中的 flag 參數(shù)信息,判斷是否在線char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取toname的套接字int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){write (atoi(resultp[i+2]), msg, sizeof(struct Msg));return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg)); }// 更改密碼 void change_pass (int client_socket, struct Msg *msg) {printf ("%s請求修改密碼\n", msg->fromname);// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 與User表中信息進行比對char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from user";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);return;}int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->fromname)==0 && strcmp(resultp[i+1], msg->msg)==0){// 返回確認(rèn)信息msg->cmd = 9009;printf ("%s 驗證通過\n", msg->fromname);write (client_socket, msg, sizeof(struct Msg));// 修改密碼char buf[100];errmsg = NULL;sprintf (buf, "update user set password = '%s' where name = '%s'",msg->filename,msg->fromname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);return;}sqlite3_free_table(resultp);// 關(guān)閉數(shù)據(jù)庫sqlite3_close(database);printf ("密碼修改完成,已關(guān)閉數(shù)據(jù)庫\n");return;}} printf ("%s 驗證不通過,密碼輸入有誤\n", msg->fromname);msg->cmd = 9010;write (client_socket, msg, sizeof(struct Msg));sqlite3_free_table(resultp);// 關(guān)閉數(shù)據(jù)庫sqlite3_close(database);printf ("操作完成,已關(guān)閉數(shù)據(jù)庫\n"); }// 客戶端請求在線注銷 void delete_user (int client_socket, struct Msg *msg) {printf ("即將處理用戶注銷\n");// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");return;}// 刪除 user 表中的信息char buf[100];char *errmsg = NULL;sprintf (buf, "delete from user where name = '%s'", msg->fromname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);return;}// 關(guān)閉數(shù)據(jù)庫sqlite3_close(database);printf ("刪除成功,已關(guān)閉數(shù)據(jù)庫\n"); }// 處理禁言請求 void silent (int client_socket, struct Msg *msg) {printf ("正在處理管理員 %s 對成員 %s 的禁言請求\n",msg->fromname,msg->toname);// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數(shù)據(jù)庫中的 flag 參數(shù)信息,判斷是否在線char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取toname的套接字int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){msg->cmd = 9011;write (atoi(resultp[i+2]), msg, sizeof(struct Msg));char buf[100];errmsg = NULL;sprintf (buf, "update user set sig = 2 where name = '%s'",msg->toname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);return;}sqlite3_close(database);printf ("禁言狀態(tài)修改完畢,已關(guān)閉數(shù)據(jù)庫\n");return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));sqlite3_close(database);printf ("用戶不在線,修改失敗,已關(guān)閉數(shù)據(jù)庫\n"); }// 處理解除禁言請求 void silent_del (int client_socket, struct Msg *msg) {printf ("正在處理管理員 %s 對成員 %s 的解除禁言請求\n",msg->fromname,msg->toname);// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數(shù)據(jù)庫中的 flag 參數(shù)信息,判斷是否在線char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取toname的套接字int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){msg->cmd = 9012;write (atoi(resultp[i+2]), msg, sizeof(struct Msg));char buf[100];errmsg = NULL;sprintf (buf, "update user set sig = 1 where name = '%s'",msg->toname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);return;}sqlite3_close(database);printf ("禁言狀態(tài)修改完畢,已關(guān)閉數(shù)據(jù)庫\n");return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));sqlite3_close(database);printf ("用戶不在線,修改失敗,已關(guān)閉數(shù)據(jù)庫\n"); }// 處理踢出成員 void kickout (int client_socket, struct Msg *msg) {printf ("正在處理管理員 %s 對成員 %s 的踢出請求\n",msg->fromname,msg->toname);// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數(shù)據(jù)庫中的 flag 參數(shù)信息,判斷是否在線char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from User";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);return;}// 獲取toname的套接字int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->toname)==0 && strcmp(resultp[i+3], "1")== 0){msg->cmd = 9013;write (atoi(resultp[i+2]), msg, sizeof(struct Msg));char buf[100];errmsg = NULL;sprintf (buf, "update user set flag = 0 where name = '%s'",msg->toname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);return;}sqlite3_close(database);printf ("踢出完畢,已關(guān)閉數(shù)據(jù)庫\n");return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));sqlite3_close(database);printf ("用戶不在線,修改失敗,已關(guān)閉數(shù)據(jù)庫\n"); }// 處理用戶操作請求函數(shù) void user_do (int client_socket) {struct Msg msg;int sig = 0;while(1){// 從客戶端讀一個結(jié)構(gòu)體數(shù)據(jù)int ret = read(client_socket, &msg, sizeof(msg));if (ret == -1){perror ("read");break;}// 代表客戶端退出if (ret == 0){printf ("客戶端返回登錄界面\n");break;}switch (msg.cmd){case 10: // 退出聊天室,返回登錄界面quit_chatroom(client_socket, &msg);sig = 1;break;case 1 : // 查看當(dāng)前在線人數(shù)display (client_socket, &msg);break;case 2 : // 處理群聊消息 chat1 (client_socket, &msg);break;case 3 : // 處理私聊消息 chat2 (client_socket, &msg);break; case 5 : // 處理確認(rèn)文件傳輸對象convey_confirm (client_socket, &msg);break;case 6 : // 更改密碼change_pass (client_socket, &msg);break;case 8 : // 處理在線注銷delete_user (client_socket, &msg);break;case 9005 : // 用戶不接受文件refuse (client_socket, &msg);break;case 9006 : // 用戶接受文件accept_ (client_socket, &msg);break;case 9007 : // 處理文件傳輸convey_chose (client_socket, &msg);break; case 9008 : // 文件傳輸完成convey_complete (client_socket, &msg);break;case 9011: // 處理禁言請求silent (client_socket, &msg);break;case 9012: // 處理解除禁言請求silent_del (client_socket, &msg);break;case 9013: // 處理踢出成員kickout (client_socket, &msg);break;}if (sig == 1){printf("即將退出普通用戶操作請求函數(shù)\n");break;}} }// 處理客戶端的登錄請求 void log_in(int client_socket, struct Msg *msg) {printf ("%s 請求登錄\n", msg->fromname);// 將用戶信息進行比對// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 與User表中信息進行比對char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from user";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}int i;for (i = 0+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], msg->fromname)==0 && strcmp(resultp[i+1], msg->msg)==0){if (strcmp(resultp[i+3], "1") == 0){msg->cmd = -4;printf ("%s 已經(jīng)在別處登錄\n", msg->fromname);write (client_socket, msg, sizeof(struct Msg));sqlite3_free_table(resultp);// 關(guān)閉數(shù)據(jù)庫sqlite3_close(database);printf ("操作完成,已關(guān)閉數(shù)據(jù)庫\n"); return;}if (strcmp(resultp[i+4], "0") != 0){// 普通用戶msg->cmd = 1002;msg->sig = atoi(resultp[i+4]);printf ("普通用戶 %s 驗證通過\n", msg->fromname);write (client_socket, msg, sizeof(struct Msg));}else {// 管理員msg->cmd = 1003;msg->sig = atoi(resultp[i+4]);printf ("管理員 %s 驗證通過\n", msg->fromname);write (client_socket, msg, sizeof(struct Msg));} // 修改在線狀態(tài)、更新套接字char buf[100];errmsg = NULL;sprintf (buf, "update user set socket = '%d',flag = 1 where name = '%s'",client_socket,msg->fromname);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}sqlite3_free_table(resultp);// 關(guān)閉數(shù)據(jù)庫sqlite3_close(database);printf ("在線狀態(tài)已更新,已關(guān)閉數(shù)據(jù)庫\n");printf ("進入用戶操作請求處理功能\n");user_do (client_socket);return;}} printf ("%s 驗證不通過\n", msg->fromname);msg->cmd = -3;write (client_socket, msg, sizeof(struct Msg));sqlite3_free_table(resultp);// 關(guān)閉數(shù)據(jù)庫sqlite3_close(database);printf ("操作完成,已關(guān)閉數(shù)據(jù)庫\n"); }// 處理客戶端的注冊請求 void reg(int client_socket, struct Msg *msg) {printf ("%s 進行注冊\n", msg->fromname);// 將用戶進行保存// 打開數(shù)據(jù)庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 往User表中添加信息char buf[100];char *errmsg = NULL;sprintf (buf, "insert into user values('%s','%s',%d,%d,%d)",msg->fromname,msg->msg,client_socket,0,msg->sig);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}// 返回確認(rèn)信息msg->cmd = 1001;printf ("%s 注冊成功\n", msg->fromname);write (client_socket, msg, sizeof(struct Msg));// 關(guān)閉數(shù)據(jù)庫sqlite3_close(database);printf ("操作完成,已關(guān)閉數(shù)據(jù)庫\n"); }// 線程的工作函數(shù),即處理客戶端請求的函數(shù) void* hanld_client(void* v) {int client_socket = (int)v;struct Msg msg;while(1){printf("處理客戶端請求的函數(shù)函數(shù)已就緒\n");// 從客戶端讀一個結(jié)構(gòu)體數(shù)據(jù)int ret = read(client_socket, &msg, sizeof(msg));if (ret == -1){perror ("read");break;}// 代表客戶端退出if (ret == 0){printf ("客戶端退出\n");break;}switch (msg.cmd){case 1 : // 客戶端進行注冊reg(client_socket, &msg);break;case 2 : // 客戶端進行登錄log_in(client_socket, &msg);break;}}close (client_socket); }int main() {// 打開數(shù)據(jù)庫User.dbint ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數(shù)據(jù)庫失敗\n");return -1;}// 創(chuàng)建 user 表char *errmsg = NULL;char *sql = "create table if not exists user(name TEXT,password TEXT,socket INTEGER,flag INTEGER,sig INTEGER,primary key(name))";ret = sqlite3_exec(database, sql, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("數(shù)據(jù)庫操作失敗:%s\n", errmsg);return -1;}printf ("數(shù)據(jù)庫準(zhǔn)備就緒......\n");// 關(guān)閉數(shù)據(jù)庫sqlite3_close(database);// 初始化套接字int listen_socket = init_socket();while (1){// 獲取與客戶端連接的套接字int client_socket = MyAccept(listen_socket);// 創(chuàng)建一個線程去處理客戶端的請求,主線程依然負(fù)責(zé)監(jiān)聽pthread_t id;pthread_create(&id, NULL, hanld_client, (void *)client_socket);pthread_detach(id); // 線程分離} close (listen_socket);return 0; }總結(jié)
以上是生活随笔為你收集整理的网络编程项目(聊天室项目)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python分类预测_python做lo
- 下一篇: 数字电子技术基础第三版杨志忠_阎石数字电