日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

网络编程项目(聊天室项目)

發布時間:2023/12/19 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 网络编程项目(聊天室项目) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、實現目標

一個在Linux下可以使用的聊天軟件,要求至少實現如下功能:
1. 采用Client/Server架構
2. Client A 登陸聊天服務器前,需要注冊自己的ID和密碼
3. 注冊成功后,Client A 就可以通過自己的ID和密碼登陸聊天服務器
4. 多個Client X 可以同時登陸聊天服務器之后,與其他用戶進行通訊聊天
5. Client A 成功登陸后可以查看當前聊天室內其他子啊先用戶Client x
6. Client A 可以選擇發消息給某個特定的 Client x,即“悄悄話”功能
7. Client A 可以選擇發消息給全部的在線用戶,即“群發消息”功能
8. Client A 在退出時需要保存聊天記錄
9. Server 端維護一個所有登陸用戶的聊天會的記錄文件,以便查看

可以選擇實現的附加功能:
1. Server 可以內建一個特殊權限的賬號admin,用于管理聊天室
2. Admin 可以將某個Client X“踢出聊天室”
3. Admin 可以將某個Client X“設為只能旁聽,不能發言”
4. Client 端發言增加表情符號,可以設置某些自定義的特殊組和來表達感情,如輸入:),則會自動發送“XXX向大家做了個笑臉”
5. Client 段增加某些常用話語,可以對其中某些部分進行“姓名替換”,例如,輸入/ClientA/welcome,則會自動發送“ClientA大俠,歡迎你來到咱們的聊天室”
Client.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> #include <sys/stat.h> #include <fcntl.h> #include <time.h>#define PORT 9999char myName[20]; // 保存用戶名 char msg1[1024]; // 保存聊天信息sqlite3 * database;int flag1 = 0; // 線程退出的判斷條件(不退出) int flag2 = 0; // 文件傳輸確認信號(無接收) int flag3 = 0; // 存在文件接收請求的判斷(不存在) int flag4 = 0; // 本地存儲是否被禁言(未被禁言)// 協議 struct Msg {char msg[1024]; // 消息內容int cmd; // 消息類型char filename[50]; // 保存文件名char toname[20]; // 接收者姓名char fromname[20]; // 發送者姓名int sig; // 用戶狀態(0:管理員、1:普通用戶、2:被禁言) };struct Msg msg; // 全局變量兩個線程共享// 注冊/登錄界面 void interface1() {system("clear");printf ("\t*************************** 網絡聊天室 *****************************\n");printf ("\t* *\n");printf ("\t* *\n");printf ("\t* 1、 注冊 *\n"); printf ("\t* 2、 登錄 *\n");printf ("\t* q、 退出 *\n");printf ("\t* *\n");printf ("\t* *\n");printf ("\t* BY szw *\n");printf ("\t********************************************************************\n\n");printf ("\t***** 請輸入命令: ");}// 普通用戶界面 void interface2() {system("clear");printf ("\t*************************** 網絡聊天室 *****************************\n");printf ("\t* *\n");printf ("\t* *\n");printf ("\t* 1、 查看當前在線人數 *\n"); printf ("\t* 2、 進入群聊界面 *\n");printf ("\t* 3、 進入私聊界面 *\n");printf ("\t* 4、 查看聊天記錄 *\n");printf ("\t* 5、 文件傳輸 *\n");printf ("\t* 6、 更改密碼 *\n"); printf ("\t* 7、 在線注銷 *\n"); printf ("\t* Q、 退出聊天室 返回登錄界面 *\n");printf ("\t* *\n");printf ("\t* *\n");printf ("\t* BY szw *\n");printf ("\t********************************************************************\n\n");printf ("\t***** 請輸入命令: "); }// 管理員界面 void interface3() {system("clear");printf ("\t*************************** 網絡聊天室 *****************************\n");printf ("\t* *\n");printf ("\t* *\n");printf ("\t* 1、 查看當前在線人數 *\n"); printf ("\t* 2、 進入群聊界面 *\n");printf ("\t* 3、 進入私聊界面 *\n");printf ("\t* 4、 查看聊天記錄 *\n");printf ("\t* 5、 文件傳輸 *\n");printf ("\t* 6、 更改密碼 *\n"); printf ("\t* 7、 在線注銷 *\n"); printf ("\t* 8、 管理員界面 *\n"); printf ("\t* Q、 退出聊天室 返回登錄界面 *\n");printf ("\t* *\n");printf ("\t* *\n");printf ("\t* BY szw *\n");printf ("\t********************************************************************\n\n");printf ("\t***** 請輸入命令: "); }// 用來保存收到的聊天信息 void keep_msg(char * msg1) {// 打開數據庫int ret = sqlite3_open("Histroy.db", &database);if (ret != SQLITE_OK){printf ("\t打開數據庫失敗\n");return;}// 往histroy表中添加信息char buf[100];char *errmsg = NULL;sprintf (buf, "insert into histroy values('%s','%s','%s')",msg.fromname,msg.toname,msg1);ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("\t數據庫操作失敗:%s\n", errmsg);return;} }// 接收文件 void receive() {printf ("\n\t正在接收文件.....\n");int fd2 = open(msg.filename, O_WRONLY|O_CREAT, 0777);if (fd2 == -1){perror ("open fd2");return;}write (fd2, msg.msg, 1023);close (fd2); }// 用來監聽收到的信息 void *readMsg(void *v) {int socketfd = (int)v;while(1){if (flag1 == 1) // 判斷線程的退出條件{flag1 = 0; // 重置線程退出條件pthread_exit(NULL);} read (socketfd, &msg, sizeof(msg));switch(msg.cmd){case 9001: // 群聊sprintf (msg1, "收到一條來自%s的群消息:\n\t%s", msg.fromname,msg.msg);printf ("\n\n\t%s\n", msg1);printf ("\n\t回車鍵返回 \n");keep_msg (msg1);break;case 9002: // 私聊printf ("\n\t%s 發來一條消息:\n\t%s\n", msg.fromname, msg.msg);sprintf (msg1,"%s 向 %s 發送一條信息:\n\t%s",msg.fromname, msg.toname, msg.msg);printf ("\n\t回車鍵返回 \n");keep_msg (msg1);break;case 9003: // 處理發送失敗sleep(3);printf ("\n\t用戶不在線或不存在,發送失敗\n");printf ("\n\t回車鍵返回 \n");break;case 9004: // 是否存在文件接收確認信號printf ("\n\n\t收到一條信息,輸入任一字符進行回復:");fflush(stdout);flag3 = 1;break; case 9005: // 文件傳輸請求被拒絕printf ("\n\t您發送的文件傳輸請求已被拒絕\n");printf ("\n\t回車鍵返回 \n");break;case 9006: // 文件傳輸請求已通過printf ("\n\t您發送的文件傳輸請求已通過,請打開文件傳輸界面進行文件傳輸\n");printf ("\n\t回車鍵返回 \n");break;case 9007: // 接收文件if (flag2 != 1)printf ("\n\t已成功攔截 %s 給您發送的文件\n", msg.fromname);elsereceive();break;case 9008: // 文件傳輸完成 printf ("\n\t%s 給您發送的文件已全部接收完畢,請及時查看\n", msg.fromname);printf ("\n\t回車鍵返回 \n");flag2 = 0; // 重置文件傳輸確認信號break;case 9009: // 密碼修改成功printf ("\n\t密碼修改成功!\n");sleep(1);break;case 9010: // 密碼輸入有誤printf ("\n\t密碼輸入有誤,修改失敗\n");usleep(1500000);break; case 9011: // 收到禁言信號printf ("\n\t您已被管理員禁言,將無法發送群聊信息\n");printf ("\n\t回車鍵返回 \n");flag4 = 1;break;case 9012: // 收到結除禁言信號printf ("\n\t您已被管理員解除禁言\n");printf ("\n\t回車鍵返回 \n");flag4 = 0;break;case 9013: // 收到被踢出信號printf ("\n\t您已被管理員踢出,即將退出聊天室....\n");//sleep (2);flag1 = 1; break;}usleep(400000);} }// 查看當前在線人數 void display (int socketfd) {msg.cmd = 1;write (socketfd, &msg, sizeof(struct Msg)); //向服務器發送請求usleep(100000);printf ("\n\t當前在線人數為:%d\n", msg.cmd);printf ("\n\t回車鍵返回 \n");getchar(); }// 退出聊天室,返回登錄界面 void quit_chatroom (int socketfd) {msg.cmd = 10;strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg)); //向服務器發送退出信號 }// 進入群聊界面 void chat1(int socketfd) {if (flag4 == 1){printf ("\n\t您已被管理員禁言,無法發送群聊信息...\n");return;}msg.cmd = 2;strcpy (msg.fromname, myName);strcpy(msg.toname, "all");printf ("\n\t請輸入您要發送的內容:\n\t");scanf ("%s",msg.msg);getchar();write (socketfd, &msg, sizeof(struct Msg)); //向服務器發送請求printf ("\n\t發送完成,等待處理結果.....\n"); // usleep (500000); }// 進入私聊界面 void chat2(int socketfd) { msg.cmd = 3;strcpy (msg.fromname, myName);printf ("\n\t請輸入您要發送的對象:\n\t");scanf ("%s",msg.toname);getchar();printf ("\t請輸入您要發送的內容:\n\t");scanf ("%s",msg.msg);getchar();write (socketfd, &msg, sizeof(struct Msg)); //向服務器發送請求printf ("\n\t發送完成,請稍候.....\n");usleep (500000); }// 打印群聊歷史記錄 void chat1_hst() {system("clear");printf ("\t*************************** 網絡聊天室 *****************************\n\n\n");printf ("\t群聊歷史記錄: \n");// 打開數據庫int ret = sqlite3_open("Histroy.db", &database);if (ret != SQLITE_OK){printf ("\t打開數據庫失敗\n");return;}// 獲取histroy表中的信息char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from histroy";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數據庫操作失敗:%s\n", errmsg);return;}int i;for (i = 1+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], "all") == 0){printf ("\n\t%s\n", resultp[i+1]);}}sqlite3_free_table(resultp);// 關閉數據庫sqlite3_close(database); }// 打印私聊歷史記錄 void chat2_hst() {system("clear");printf ("\t*************************** 網絡聊天室 *****************************\n\n\n");printf ("\t私聊歷史記錄:\n");// 打開數據庫int ret = sqlite3_open("Histroy.db", &database);if (ret != SQLITE_OK){printf ("\t打開數據庫失敗\n");return;}// 獲取histroy表中的信息char *errmsg = NULL;char **resultp = NULL;int nrow, ncolumn;char *sql = "select * from histroy";ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);if (ret != SQLITE_OK){printf ("數據庫操作失敗:%s\n", errmsg);return;}int i;for (i = 1+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn){if(strcmp(resultp[i], "all") != 0){printf ("\n\t%s\n", resultp[i+1]);}}sqlite3_free_table(resultp);// 關閉數據庫sqlite3_close(database); }// 查看聊天記錄 void dis_histroy(int socketfd) {printf ("\n\t a、查看群聊記錄\n\t b、查看個人聊天記錄\n\t");printf ("\n\t***** 請選擇: ");switch (getchar()){case 'a':chat1_hst();break;case 'b':chat2_hst();break;}printf ("\n\t回車鍵返回 ");getchar(); }// 確認傳輸對象 void convey_confirm(int socketfd) {msg.cmd = 5;strcpy (msg.fromname, myName);printf ("\n\t請輸入文件的傳輸對象:\n\t");scanf ("%s",msg.toname);getchar();printf ("\n\t傳輸請求發送完成,請稍等.....\n");write (socketfd, &msg, sizeof(struct Msg)); //向服務器發送請求 }// 文件傳輸過程 void convey_chose(int socketfd) {msg.cmd = 9007;strcpy (msg.toname, msg.fromname);strcpy (msg.fromname, myName);printf ("\n\t當前目錄下的文件有: \n\n\t");fflush(stdout);system ("ls");printf ("\n\t請輸入您要傳送的文件名: ");printf ("\n\t");scanf ("%s",msg.filename);getchar();// 打開要讀的文件int fd1 = open(msg.filename, O_RDONLY);if (fd1 == -1){perror ("open fd1");return;}int ret = 0;flag1 = 1; // 關閉線程while (ret = read (fd1, msg.msg, 1023)){if (ret == -1){perror("read");break;}printf ("\n\t正在傳輸文件,請稍候......\n");write (socketfd, &msg, sizeof(struct Msg));sleep(1);}msg.cmd = 9008;write (socketfd, &msg, sizeof(struct Msg));printf ("\n\t文件傳輸完成\n");close (fd1);// 重新開啟一個線程pthread_t id;pthread_create(&id, NULL, readMsg, (void*)socketfd);pthread_detach(id); // getchar(); }// 文件傳輸界面 void convey(int socketfd) {system("clear");printf ("\t*************************** 網絡聊天室 *****************************\n\n\n");printf ("\t 1、傳輸對象確認\n");printf ("\t 2、選擇文件\n");printf ("\n\t***** 請選擇: ");char ch[2];fgets(ch, 2, stdin);while (getchar()!= '\n');switch (ch[0]){case '1': // 確認傳輸對象convey_confirm(socketfd);break;case '2': // 文件選擇convey_chose(socketfd);break;}printf ("\n\t回車鍵返回 ");getchar(); }// 更改密碼 void change_pass(int socketfd) {char ch[2];msg.cmd = 6;printf ("\n\t您是否確定需要修改密碼?(y/n): ");fgets(ch, 2, stdin);while (getchar()!= '\n');if (ch[0] != 'y'){printf ("\n\t請稍候.....\n");usleep(700000);return;}printf ("\t請輸入舊密碼: ");scanf ("%s", msg.msg);getchar();printf ("\t請輸入新密碼: ");scanf ("%s", msg.filename);getchar();strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg)); // 向服務器發送注冊信息printf ("\n\t正在校驗數據,請稍候......\n");sleep(1); }// 在線注銷 void delete_user(int socketfd) {msg.cmd = 8;printf ("\n\t正在處理注銷操作......\n");write (socketfd, &msg, sizeof(struct Msg)); //向服務器發送請求sleep(1);printf ("\t注銷完成!\n"); }// 普通用戶操作 void user_do (int socketfd) { char ch[2];while(1){interface2();if (flag3 == 1){printf ("\n\n\t%s 請求傳輸文件,是否接收?(y/n):", msg.fromname);fflush(stdout);fgets(ch, 2, stdin);while (getchar()!= '\n');if (ch[0] != 'y'){printf ("\n\t您已拒絕接受文件傳輸\n");printf ("\n\t回車鍵返回 \n");}else {printf ("\n\t您已接受文件傳輸請求\n");printf ("\n\t回車鍵返回 \n");flag2 = 1;}if (flag2 == 0){msg.cmd = 9005; // 不接受文件strcpy (msg.toname,msg.fromname); // 修改信號發送對象strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg)); }else if (flag2 == 1){msg.cmd = 9006; // 接受文件strcpy (msg.toname,msg.fromname); // 修改信號發送對象strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg)); }flag3 = 0; // 重置是否存在文件接收請求的判斷flag2 = 0;}fgets(ch, 2, stdin);while (getchar()!= '\n'); switch(ch[0]){case '1': // 查看當前在線人數display(socketfd);break;case '2': // 進入群聊界面 chat1(socketfd);printf ("\n\t回車鍵返回 \n");getchar();break;case '3': // 進入私聊界面 chat2(socketfd);printf ("\n\t回車鍵返回 \n");getchar();break;case '4': // 查看聊天記錄dis_histroy(socketfd);getchar();break;case '5': // 文件傳輸convey(socketfd);break;case '6': // 更改密碼change_pass(socketfd);break;case '7': // 在線注銷printf ("\n\t是否確認注銷?(y/n): ");fgets(ch, 2, stdin);while (getchar()!= '\n');if (ch[0] != 'y'){printf ("\n\t請稍候.....\n");usleep(700000);break;}delete_user(socketfd);case 'q': // 退出聊天室 返回登錄界面flag1 = 1;quit_chatroom(socketfd);printf ("\n\t正在退出,請稍候......\n");break;}if (flag1 == 1) // 判斷退出條件{break;}system("clear");} }// 將成員禁言 void silent (int socketfd) {msg.cmd = 9011;strcpy (msg.fromname, myName);printf ("\n\t請輸入您要禁言的用戶:\n\t");scanf ("%s",msg.toname);getchar();write (socketfd, &msg, sizeof(struct Msg)); //向服務器發送請求printf ("\n\t操作完成,請稍候.....\n");usleep (500000); }// 將成員解除禁言 void silent_del (int socketfd) {msg.cmd = 9012;strcpy (msg.fromname, myName);printf ("\n\t請輸入您要解除禁言的用戶:\n\t");scanf ("%s",msg.toname);getchar();write (socketfd, &msg, sizeof(struct Msg)); //向服務器發送請求printf ("\n\t操作完成,請稍候.....\n");usleep (500000); }// 將成員踢出聊天室 void kickout (int socketfd) {msg.cmd = 9013;strcpy (msg.fromname, myName);printf ("\n\t請輸入您要踢出的用戶:\n\t");scanf ("%s",msg.toname);getchar();write (socketfd, &msg, sizeof(struct Msg)); //向服務器發送請求printf ("\n\t操作完成,請稍候.....\n");usleep (500000); }// 管理員權限 void supuser (int socketfd) {system("clear");printf ("\t*************************** 網絡聊天室 *****************************\n\n\n");printf ("\t 1、將成員禁言\n");printf ("\t 2、將成員解除禁言\n");printf ("\t 3、將成員踢出聊天室\n");printf ("\n\t***** 請選擇: ");char ch[2];fgets(ch, 2, stdin);while (getchar()!= '\n');switch (ch[0]){case '1': // 將成員禁言silent(socketfd);break;case '2': // 將成員解除禁言silent_del(socketfd);break; case '3': // 將成員踢出聊天室kickout(socketfd);break;}printf ("\n\t回車鍵返回 ");getchar(); }// 管理員操作 void supuser_do (int socketfd) { char ch[2];while(1){interface3();if (flag3 == 1){printf ("\n\n\t%s 請求傳輸文件,是否接收?(y/n):", msg.fromname);fflush(stdout);fgets(ch, 2, stdin);while (getchar()!= '\n');if (ch[0] != 'y'){printf ("\n\t您已拒絕接受文件傳輸\n");printf ("\n\t回車鍵返回 \n");}else {printf ("\n\t您已接受文件傳輸請求\n");printf ("\n\t回車鍵返回 \n");flag2 = 1;}if (flag2 == 0){msg.cmd = 9005; // 不接受文件strcpy (msg.toname,msg.fromname); // 修改信號發送對象strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg)); }else if (flag2 == 1){msg.cmd = 9006; // 接受文件strcpy (msg.toname,msg.fromname); // 修改信號發送對象strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg)); }flag3 = 0; // 重置是否存在文件接收請求的判斷flag2 = 0;}fgets(ch, 2, stdin);while (getchar()!= '\n'); switch(ch[0]){case '1': // 查看當前在線人數display(socketfd);break;case '2': // 進入群聊界面 chat1(socketfd);printf ("\n\t回車鍵返回 \n");getchar();break;case '3': // 進入私聊界面 chat2(socketfd);printf ("\n\t回車鍵返回 \n");getchar();break;case '4': // 查看聊天記錄dis_histroy(socketfd);getchar();break;case '5': // 文件傳輸convey(socketfd);break;case '6': // 更改密碼change_pass(socketfd);break;case '8': // 管理員權限操作supuser (socketfd);break;case '7': // 在線注銷printf ("\n\t是否確認注銷?(y/n): ");fgets(ch, 2, stdin);while (getchar()!= '\n');if (ch[0] != 'y'){printf ("\n\t請稍候.....\n");usleep(700000);break;}delete_user(socketfd);case 'q': // 退出聊天室 返回登錄界面flag1 = 1;quit_chatroom(socketfd);printf ("\n\t正在退出,請稍候......\n");break;}if (flag1 == 1) // 判斷退出條件{break;}system("clear");} }// 登錄 void log_in(int socketfd) {char password[20];msg.cmd = 2;printf ("\n\t用戶登錄:\n");printf ("\t請輸入用戶名: ");scanf ("%s", myName);getchar();printf ("\t請輸入密碼: ");scanf ("%s", password);getchar();strcpy (msg.fromname, myName);strcpy (msg.msg, password);write (socketfd, &msg, sizeof(struct Msg)); // 向服務器發送登錄請求read (socketfd, &msg, sizeof(struct Msg)); // 讀取服務器的登錄回應printf ("\n\t正在校驗數據......\n");sleep(1);if (msg.cmd == 1002){printf ("\n\t驗證通過,正在登錄......\n");usleep(1500000);flag4 = msg.sig; // 更新禁言狀態// 線程分離,用來監聽服務器返回信息pthread_t id;pthread_create(&id, NULL, readMsg, (void*)socketfd);pthread_detach(id); user_do (socketfd);}else if (msg.cmd == 1003){printf ("\n\t驗證通過,正在登錄......\n");usleep(1500000);// 線程分離,用來監聽服務器返回信息pthread_t id;pthread_create(&id, NULL, readMsg, (void*)socketfd);pthread_detach(id); supuser_do (socketfd);} else if (msg.cmd == -4){printf ("\n\t此賬號已在別處登錄\n");}else if (msg.cmd == -3){printf ("\n\t驗證失敗,請您確認信息后重新登錄\n");}else if (msg.cmd == -2){printf ("\t驗證失敗,數據庫打開失敗\n");}else if (msg.cmd == -1){printf ("\t數據庫操作失敗\n");}usleep(1500000); }// 注冊(可注冊管理員) void reg(int socketfd) {msg.cmd = 1;printf ("\t用戶注冊:\n");printf ("\t請輸入用戶名: ");scanf ("%s", myName);getchar();printf ("\t請輸入密碼: ");scanf ("%s", msg.msg);getchar();printf ("\t管理員: ");scanf ("%d", &msg.sig);getchar(); strcpy (msg.fromname, myName);write (socketfd, &msg, sizeof(struct Msg)); // 向服務器發送注冊信息read (socketfd, &msg, sizeof(struct Msg)); // 讀取服務器的注冊回應printf ("\n\t正在校驗數據......\n");sleep(1);if (msg.cmd == 1001){printf ("\n\t注冊成功!\n\t請稍候......\n");}else if (msg.cmd == -1){printf ("\t注冊失敗,該用戶名已被注冊\n");}else if (msg.cmd == -2){printf ("\t注冊失敗,數據庫打開失敗\n");}usleep(1500000); }// 向服務器發送請求 void ask_server(int socketfd) {char ch[2];while (1){interface1();fgets(ch, 2, stdin);while (getchar()!= '\n');switch(ch[0]){case '1': // 注冊reg(socketfd);break;case '2': // 登錄log_in(socketfd);break;case 'q': // 退出exit(1);}system("clear");} }int main(int argc, char **argv) {// 打開數據庫Histroy.dbint ret = sqlite3_open("Histroy.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\n");return -1;}// 創建 histroy 表char *errmsg = NULL;char *sql = "create table if not exists histroy(fromname TEXT,toname TEXT,msg TEXT)";ret = sqlite3_exec(database, sql, NULL, NULL, &errmsg);if (ret != SQLITE_OK){printf ("數據庫操作失敗:%s\n", errmsg);return -1;}// 關閉數據庫sqlite3_close(database);// 創建與服務器通信的套接字int socketfd = socket(AF_INET, SOCK_STREAM, 0);if (socketfd == -1){perror ("socket");return -1;}// 連接服務器struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET; // 設置地址族addr.sin_port = htons(PORT); // 設置本地端口inet_aton(argv[1],&(addr.sin_addr));// 連接服務器,如果成功,返回0,如果失敗,返回-1// 成功的情況下,可以通過socketfd與服務器進行通信ret = connect(socketfd, (struct sockaddr *)&addr, sizeof(addr));if (ret == -1){perror ("connect");return -1;}printf ("成功連上服務器\n");ask_server(socketfd);// 關閉套接字close(socketfd);return 0; }

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;// 協議 struct Msg {char msg[1024]; // 消息內容int cmd; // 消息類型char filename[50]; // 保存文件名char toname[20]; // 接收者姓名char fromname[20]; // 發送者姓名int sig; // 用戶狀態(0:管理員、1:普通用戶、2:被禁言) };// 初始化套接字,返回監聽套接字 int init_socket() {//1、創建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; // 設置地址族addr.sin_port = htons(PORT); // 設置本地端口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、監聽本地套接字ret = listen(listen_socket, 5);if (ret == -1){perror ("listen");return -1;}printf ("服務器已就緒,等待客戶端連接.......\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; }// 查看當前在線人數 void display (int client_socket, struct Msg *msg) {printf ("查看當前在線人數\n");// 確認flag參數// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\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 ("數據庫操作失敗:%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++;}}// 返回在線人數msg->cmd = count;printf ("當前在線人數為:%d\n", msg->cmd);write (client_socket, msg, sizeof(struct Msg));sqlite3_free_table(resultp);// 關閉數據庫sqlite3_close(database);printf ("操作完成,已關閉數據庫\n"); }// 退出聊天室,返回登錄界面 void quit_chatroom (int client_socket, struct Msg *msg) {printf ("%s 退出聊天室\n", msg->fromname);// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\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 ("數據庫操作失敗:%s\n", errmsg);return;}sqlite3_close(database);printf ("登錄狀態修改完畢,已關閉數據庫\n");write (client_socket, msg, sizeof(struct Msg)); }// 客戶端發送群聊消息 void chat1 (int client_socket, struct Msg *msg) {printf ("%s 發了一條群消息\n",msg->fromname);// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數據庫中的flag參數信息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 ("數據庫操作失敗:%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 ("群消息已全部發送完成\n"); }// 客戶端發送私聊消息 void chat2 (int client_socket, struct Msg *msg) {printf ("%s 向 %s 發了一條消息\n",msg->fromname,msg->toname);// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數據庫中的flag參數信息,判斷是否在線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 ("數據庫操作失敗:%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)); }// 處理確認文件傳輸對象 void convey_confirm (int client_socket, struct Msg *msg) {printf ("%s 向 %s 發送文件傳輸請求\n",msg->fromname,msg->toname);// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\n");return;}// 獲取數據庫中的flag參數信息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 ("數據庫操作失敗:%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);// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\n");return;}// 獲取數據庫中 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 ("數據庫操作失敗:%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);// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\n");return;}// 獲取數據庫中 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 ("數據庫操作失敗:%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);// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數據庫中的 flag 參數信息,判斷是否在線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 ("數據庫操作失敗:%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 ("文件傳輸結束\n");// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數據庫中的 flag 參數信息,判斷是否在線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 ("數據庫操作失敗:%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);// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\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 ("數據庫操作失敗:%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){// 返回確認信息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 ("數據庫操作失敗:%s\n", errmsg);return;}sqlite3_free_table(resultp);// 關閉數據庫sqlite3_close(database);printf ("密碼修改完成,已關閉數據庫\n");return;}} printf ("%s 驗證不通過,密碼輸入有誤\n", msg->fromname);msg->cmd = 9010;write (client_socket, msg, sizeof(struct Msg));sqlite3_free_table(resultp);// 關閉數據庫sqlite3_close(database);printf ("操作完成,已關閉數據庫\n"); }// 客戶端請求在線注銷 void delete_user (int client_socket, struct Msg *msg) {printf ("即將處理用戶注銷\n");// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\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 ("數據庫操作失敗:%s\n", errmsg);return;}// 關閉數據庫sqlite3_close(database);printf ("刪除成功,已關閉數據庫\n"); }// 處理禁言請求 void silent (int client_socket, struct Msg *msg) {printf ("正在處理管理員 %s 對成員 %s 的禁言請求\n",msg->fromname,msg->toname);// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數據庫中的 flag 參數信息,判斷是否在線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 ("數據庫操作失敗:%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 ("數據庫操作失敗:%s\n", errmsg);return;}sqlite3_close(database);printf ("禁言狀態修改完畢,已關閉數據庫\n");return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));sqlite3_close(database);printf ("用戶不在線,修改失敗,已關閉數據庫\n"); }// 處理解除禁言請求 void silent_del (int client_socket, struct Msg *msg) {printf ("正在處理管理員 %s 對成員 %s 的解除禁言請求\n",msg->fromname,msg->toname);// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數據庫中的 flag 參數信息,判斷是否在線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 ("數據庫操作失敗:%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 ("數據庫操作失敗:%s\n", errmsg);return;}sqlite3_close(database);printf ("禁言狀態修改完畢,已關閉數據庫\n");return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));sqlite3_close(database);printf ("用戶不在線,修改失敗,已關閉數據庫\n"); }// 處理踢出成員 void kickout (int client_socket, struct Msg *msg) {printf ("正在處理管理員 %s 對成員 %s 的踢出請求\n",msg->fromname,msg->toname);// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\n");msg->cmd = -2;write (client_socket, msg, sizeof(struct Msg));return;}// 獲取數據庫中的 flag 參數信息,判斷是否在線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 ("數據庫操作失敗:%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 ("數據庫操作失敗:%s\n", errmsg);return;}sqlite3_close(database);printf ("踢出完畢,已關閉數據庫\n");return;}}msg->cmd = 9003;write (client_socket, msg, sizeof(struct Msg));sqlite3_close(database);printf ("用戶不在線,修改失敗,已關閉數據庫\n"); }// 處理用戶操作請求函數 void user_do (int client_socket) {struct Msg msg;int sig = 0;while(1){// 從客戶端讀一個結構體數據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 : // 查看當前在線人數display (client_socket, &msg);break;case 2 : // 處理群聊消息 chat1 (client_socket, &msg);break;case 3 : // 處理私聊消息 chat2 (client_socket, &msg);break; case 5 : // 處理確認文件傳輸對象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("即將退出普通用戶操作請求函數\n");break;}} }// 處理客戶端的登錄請求 void log_in(int client_socket, struct Msg *msg) {printf ("%s 請求登錄\n", msg->fromname);// 將用戶信息進行比對// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\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 ("數據庫操作失敗:%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 已經在別處登錄\n", msg->fromname);write (client_socket, msg, sizeof(struct Msg));sqlite3_free_table(resultp);// 關閉數據庫sqlite3_close(database);printf ("操作完成,已關閉數據庫\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));} // 修改在線狀態、更新套接字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 ("數據庫操作失敗:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}sqlite3_free_table(resultp);// 關閉數據庫sqlite3_close(database);printf ("在線狀態已更新,已關閉數據庫\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);// 關閉數據庫sqlite3_close(database);printf ("操作完成,已關閉數據庫\n"); }// 處理客戶端的注冊請求 void reg(int client_socket, struct Msg *msg) {printf ("%s 進行注冊\n", msg->fromname);// 將用戶進行保存// 打開數據庫int ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\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 ("數據庫操作失敗:%s\n", errmsg);msg->cmd = -1;write (client_socket, msg, sizeof(struct Msg));return;}// 返回確認信息msg->cmd = 1001;printf ("%s 注冊成功\n", msg->fromname);write (client_socket, msg, sizeof(struct Msg));// 關閉數據庫sqlite3_close(database);printf ("操作完成,已關閉數據庫\n"); }// 線程的工作函數,即處理客戶端請求的函數 void* hanld_client(void* v) {int client_socket = (int)v;struct Msg msg;while(1){printf("處理客戶端請求的函數函數已就緒\n");// 從客戶端讀一個結構體數據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() {// 打開數據庫User.dbint ret = sqlite3_open("User.db", &database);if (ret != SQLITE_OK){printf ("打開數據庫失敗\n");return -1;}// 創建 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 ("數據庫操作失敗:%s\n", errmsg);return -1;}printf ("數據庫準備就緒......\n");// 關閉數據庫sqlite3_close(database);// 初始化套接字int listen_socket = init_socket();while (1){// 獲取與客戶端連接的套接字int client_socket = MyAccept(listen_socket);// 創建一個線程去處理客戶端的請求,主線程依然負責監聽pthread_t id;pthread_create(&id, NULL, hanld_client, (void *)client_socket);pthread_detach(id); // 線程分離} close (listen_socket);return 0; }

總結

以上是生活随笔為你收集整理的网络编程项目(聊天室项目)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。