方案二、三SELECT、UDP完成聊天室
Select 多路復用
服務器類型中
循環服務器:同一時刻只可以響應一個客戶端的請求
并發服務器:同一時刻 可以響應 多個 客戶端的請求
?
實現:
服務器:
1.創建socket
2.綁定 bind 記得創建server_address :( struct sockaddr_in server_addr)
3.設置監聽隊列 listen//(TCP這里和accept配合使用
一個while循環listen和accept(阻塞)搭配完成一次新socket創建)
//SELECT中 listen在while循環外面
/****** ???????????????????上面同第一篇TCP實現原理相同 ???????????????*******/
?
4.Select 用以監聽fd(文件描述符 所有的~~)
(函數原型)
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
Nfds:(maxfd)代表目前已打開的 文件fd 數目 + 1
Readfds ?writefds ?exceptfds :
都是集合(是所有fd 的集合)
用以監聽 fd 是否 可讀 / 可寫 / 有異常發生
作為服務器 我們只需要監聽 是否可讀 :客戶端發起請求,服務器可以讀到客戶 的信息
Timeout:?是結構體 結構體內有兩個值 一個秒 一個微秒
Timeout取值:
0 :不管有無 fd 可讀 都直接返回
NULL: 阻塞狀態 不斷掃描所有的 fd 直到有 fd 發生變化 才返回
正整數:等待的最長時間t;t秒內如果沒有 fd 可讀 程序繼續向下執行
?
?
(
fd_set ReadFd,TmpFd;//(是一個fd集合)用于select 參數
FD_ZERO(&ReadFd);//將兩個參數初始化
FD_ZERO(&TmpFd);
FD_SET(sockfd,&ReadFd);//先將sockfd加入集合:監聽是否有人發起連接
)
客戶端不變
其余信息看代碼解釋
?
?
UDP:
UDP是最簡單的
服務器:
客戶端:
?
?服務器:
Socket 和 bind同TCP
?
3 . ?recvfrom()
(函數原型)ssize_t recvfrom(int s, void *buf, size_t len, int flags,
???????????????????????? struct sockaddr *from, socklen_t *fromlen);
S?: ? ? ? ? ? ? ?就是自己創建的sockfd
Buf: ? ? ? ? ? ?自己想要發送的內容
Len : ? ? ? ? ??buf的大小
Flags: ? ? ? ? 默認為0
From: ? ? ? 就是自己本身啊 從自己發消息出去(看到這個前綴就知道 又要創建一個自己的 地址 別忘了 struct sockaddr ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *client_addr)
Fromlen: ? ? 是地址的長度 因為是指針所以回頭 自己定義的length 記得取地址 &
?
?
客戶端一樣如此
?
4.sendto()
(函數原型)ssize_t ?sendto(int ?s, ?const ?void *buf, size_t len, int flags, const
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?struct sockaddr *to, socklen_t tolen);
S: ? ? ? ? ? 創建的sockfd
Buf: ? ? ? ?接受發來的消息
Len : ???? ?buf的大小
Flags: ????默認為0
To: ? ? ??發送給誰(服務器啊) (看到這個前綴就知道 又要創建一個地址 別忘了 struct sockaddr *server_addr)
Tolen: ? ? 是地址的長度 ?這里不是指針所以不用取地址
?
?
附上源碼:感覺可以的點個贊再走
TCP:
client.c
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/types.h> #include<sys/socket.h> #include<sqlite3.h>struct user {char name[10]; //用戶昵稱char ID[20]; //帳號char password[20]; //密碼int type; //消息種類int state; //1表示在線,0表示離線char toname[10]; //私聊信息發送對象char record[100]; //聊天記錄int level; //用戶權限:2表示管理員,1為普通用戶,0表示被禁言,-1表示被踢出 struct user *next; };char NAME[20]={0}; //用于檢測有無此用戶名 char NAME2[20]={0}; //用于存放登錄用戶的用戶名 char id[20]={0}; char PASSWORD[20]={0}; int SIGN=0; int SIGN2=10; int SIGN3=0; int count=0; //記錄會員的數量(只能有一個)int Tname(void *para,int columnCount,char **columnValue,char **columnName) {if(strcmp(columnValue[0],NAME) == 0){SIGN=1;}return 0; }int Tid(void *para,int columnCount,char **columnValue,char **columnName) {if(strcmp(columnValue[0],id) == 0){SIGN=1;}return 0; }void zhuce(int sockfd) //注冊 {sqlite3 *pdb;char sql[100]={0};struct user User;int ret;ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite_open");return;}printf("****************************************\n");printf(" 請輸入您想要的昵稱:\n");fflush(stdout);while(1){scanf("%s",User.name);memset(NAME,0,sizeof(NAME));strcpy(NAME,User.name);sprintf(sql,"select name from user1 where name='%s';",User.name);ret=sqlite3_exec(pdb,sql,Tname,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}if(SIGN == 0)//昵稱未被注冊{break;}else{SIGN=0;printf(" 該已用戶昵稱被注冊!\n");printf(" 請重新輸入用戶昵稱:\n");fflush(stdout);}}SIGN=0;//復位printf("\n");printf(" 清輸入您的帳號:\n");fflush(stdout);while(1){scanf("%s",User.ID);memset(id,0,sizeof(id));strcpy(id,User.ID);sprintf(sql,"select ID from user1 where ID='%s';",User.ID);ret=sqlite3_exec(pdb,sql,Tid,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}if(SIGN == 0)//帳號未被注冊{break;}else{SIGN=0;printf(" 該帳號已被注冊!\n");printf(" 請重新輸入帳號:\n");fflush(stdout);}}SIGN=0;//復位ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;}printf("\n");printf(" 請輸入您的密碼:\n");fflush(stdout);scanf("%s",User.password);while(strlen(User.password) <= 5){printf(" 密碼長度過短,請重新輸入:\n");fflush(stdout);scanf("%s",User.password);}printf("\n");printf(" 恭喜您用戶注冊成功!\n");printf("****************************************\n");sleep(2);User.type=1;//設置消息類型為注冊(1)User.state=0;//表示不在線User.level=1;//表示為普通用戶ret=send(sockfd,&User,sizeof(User),0);//打包發送給服務器if(ret == -1){perror("send");return;}}int Tid2(void *para,int columnCount,char **columnValue,char **columnName) {memset(NAME2,0,sizeof(NAME2));strcpy(NAME2,columnValue[0]);if(strcmp(columnValue[1],id) == 0){SIGN=1; }if(strcmp(columnValue[3],"1") == 0){SIGN=2;}return 0; }int Tpassword(void *para,int columnCount,char **columnValue,char **columnName) {if(strcmp(columnValue[0],PASSWORD) == 0){SIGN=1;}return 0; }void login(int sockfd)//登錄 {int ret;sqlite3 *pdb;char sql[100]={0};struct user User;ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite_open");return;}printf("********************************\n");printf(" 清輸入您的帳號:\n");fflush(stdout);while(1){scanf("%s",User.ID);memset(id,0,sizeof(id));strcpy(id,User.ID);sprintf(sql,"select * from user1 where ID='%s';",User.ID);ret=sqlite3_exec(pdb,sql,Tid2,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}if(SIGN == 1){break;}else if(SIGN == 2){SIGN=0;printf(" 該帳號已在別處登錄!\n");printf(" 請重新輸入:\n");fflush(stdout);}else{SIGN=0;printf(" 該帳號不存在,請重新輸入:\n");fflush(stdout);} }SIGN=0;printf(" 清輸入您的密碼:\n");fflush(stdout);while(1){scanf("%s",User.password);memset(PASSWORD,0,sizeof(PASSWORD));strcpy(PASSWORD,User.password);sprintf(sql,"select password from user1 where ID='%s';",User.ID);ret=sqlite3_exec(pdb,sql,Tpassword,NULL,NULL);//取出user表中的帳號信息if(ret != SQLITE_OK){perror("sqlite_exec");return;}if(SIGN == 1){break;}else{SIGN=0;printf(" 密碼錯誤,請重新輸入:\n");fflush(stdout);}}SIGN=0;printf(" 登錄成功!\n");printf("********************************\n");sleep(2);ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;}strcpy(User.name,NAME2);User.type=2;//設置消息類型為登錄(2)User.state=1;//設置用戶在線ret=send(sockfd,&User,sizeof(User),0);//打包發送給服務器if(ret == -1){perror("send");return;}}int print(void *para,int columnCount,char **columnValue,char **columnName) {printf("%s:%s\n",columnName[0],columnValue[0]);return 0; }void listonline() //查看當前在線用戶 {sleep(1);system("clear");int ret;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite_open");return;}printf("?????????????????????????????????\n");printf(" 當前在線用戶為:\n");sprintf(sql,"select name from user1 where state=1;");ret=sqlite3_exec(pdb,sql,print,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}printf("?????????????????????????????????\n");ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;}sleep(2);}int Tlevel(void *para,int columnCount,char **columnValue,char **columnName) //檢測用戶是否被禁言 {if(strcmp(columnValue[0],"1") == 0 || strcmp(columnValue[0],"2") == 0){SIGN2=5;}if(strcmp(columnValue[0],"0") == 0){SIGN2=0;}return 0; }int Tprivatechat(void *para,int columnCount,char **columnValue,char **columnName) //檢測用戶是否存在 {if(strcmp(columnValue[0],NAME) == 0){SIGN=1;}if(strcmp(columnValue[0],NAME2) == 0){SIGN=2;}return 0; }//檢測該用戶是否在線 int Tonline(void *para,int columnCount,char **columnValue,char **columnName) {if(strcmp(columnValue[0],"1") == 0){SIGN3=1;}return 0; }void chatprivate(int sockfd) //私聊 {sleep(1);system("clear");printf("?????????????????????????????????\n");int ret;sqlite3 *pdb;char sql[100]={0};struct user User;ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite_open");return;}sprintf(sql,"select level from user1 where name='%s';",NAME2);ret=sqlite3_exec(pdb,sql,Tlevel,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}if(SIGN2 == 0){printf(" 您已被管理員禁言!\n");sleep(1);SIGN2=10;return;}printf(" 請選擇您想私聊的用戶:\n");fflush(stdout);while(1){SIGN=0;SIGN3=0;memset(NAME,0,sizeof(NAME));scanf("%s",NAME);sprintf(sql,"select name from user1 where name='%s';",NAME);ret=sqlite3_exec(pdb,sql,Tprivatechat,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}sprintf(sql,"select state from user1 where name='%s';",NAME);ret=sqlite3_exec(pdb,sql,Tonline,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}//表示存在該用戶且該用戶在線if(SIGN == 1 && SIGN3 ==1){break;}if(SIGN == 2){printf(" 不能和自己聊天!\n");printf(" 請重新輸入您想私聊的用戶:");fflush(stdout);}if(SIGN3 == 0 && SIGN == 1){ printf(" 該用戶不在線!\n");printf(" 請重新輸入您想私聊的用戶:");fflush(stdout);}if(SIGN == 0){printf(" 該用戶不存在!\n");printf(" 請重新輸入您想私聊的用戶:");fflush(stdout);} }ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;}SIGN=0;//復位SIGN3=0;printf("?????????????????????????????????\n");printf("******聊天室******\n");printf(" 常用表情\n");printf("smile ( ^_^ ) cry T_T \n ");printf("sweat -_-! angry >_< \n ");printf("dizzy +_+ suprise (⊙?⊙)\n");while(1){User.type=3;//設置消息類型為私聊(3),最后哦發送給服務器;strcpy(User.name,NAME2);strcpy(User.toname,NAME);scanf("%s",User.record);if(strcmp(User.record,"end") == 0){printf(" 再見!\n");printf("******聊天室******\n");sleep(1);SIGN2=10;break;}ret=send(sockfd,&User,sizeof(User),0);if(ret == -1){perror("send");return;}memset(&User,0,sizeof(User));}}void chatall(int sockfd) //群聊 {sleep(1);system("clear");int ret;struct user User;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite_open");return;}sprintf(sql,"select level from user1 where name='%s';",NAME2);ret=sqlite3_exec(pdb,sql,Tlevel,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;}if(SIGN2 == 0){printf(" 您已被管理員禁言!\n");sleep(1);SIGN2=10;return;}printf("?????????????Chatting room????????????????\n");while(1){User.type=4;//設置消息類型為私聊(4),最后發送給發服務器;scanf("%s",User.record);if(strcmp(User.record,"end") == 0){printf(" 通話結束!\n");sleep(1);SIGN2=10;break;}strcpy(User.name,NAME2);ret=send(sockfd,&User,sizeof(User),0);if(ret == -1){perror("send");return;}memset(&User,0,sizeof(User));} }int Tprivate(void *para,int columnCount,char **columnValue,char **columnName) {if(strcmp(columnValue[0],NAME) == 0){SIGN=1;}if(strcmp(columnValue[0],NAME2) == 0){SIGN=2;}return 0; }int printprivate(void *para,int columnCount,char **columnValue,char **columnName) //打印私聊 {printf("%s:%s\n",columnValue[0],columnValue[2]);return 0; }void findprivate() {sleep(1);system("clear");int key=1;int ret;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite_open");return;}printf(" 您想查詢與誰的聊天記錄:");fflush(stdout);while(1){SIGN=0;memset(NAME,0,sizeof(NAME));scanf("%s",NAME);sprintf(sql,"select name from user1 where name='%s';",NAME);ret=sqlite3_exec(pdb,sql,Tprivate,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}//判斷用戶是否存在且不是自己if(SIGN == 1){break;}else if(SIGN == 2){printf(" 您無法查詢與自己的聊天記錄!\n");printf(" 請重新輸入您想查詢的用戶:");fflush(stdout);}else{printf(" 該用戶不存在!\n");printf(" 請重新輸入您想查詢的用戶:");fflush(stdout);} }SIGN=0;//復位sprintf(sql,"select * from Privatechatrecord where name='%s' AND toname='%s' OR name='%s' AND toname='%s';",NAME,NAME2,NAME2,NAME);ret=sqlite3_exec(pdb,sql,printprivate,NULL,NULL); if(ret != SQLITE_OK){perror("sqlite_exec");return;}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;}}int printall(void *para,int columnCount,char **columnValue,char **columnName) //打印群聊 {printf("%s:%s\n",columnValue[0],columnValue[1]);return 0; }void findall() {sleep(1);system("clear");int key=1;int ret;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite_open");return;}sprintf(sql,"select * from Groupchatrecord;");ret=sqlite3_exec(pdb,sql,printall,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;}}int TVIP(void *para,int columnCount,char **columnValue,char **columnName) //統計會員數,一開始作判斷,管理數目只有一個; {if(strcmp(columnValue[0],"2") == 0){count++;}return 0; }void VIP(int sockfd)//vip {sleep(1);system("clear");char key[2]={0};int ret;struct user User;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite_open");return;}sprintf(sql,"select level from user1;");ret=sqlite3_exec(pdb,sql,TVIP,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;}if(count >= 1){printf(" 會員名額為0,請下次再來!\n");count=0;sleep(1);return;}printf(" 確定要支付998成為會員嗎?(y/n)\n");scanf("%s",key);if(key[0] == 'y'){User.type=5;User.level=2;strcpy(User.name,NAME2);ret=send(sockfd,&User,sizeof(User),0);if(ret == -1){perror("send");return;}printf(" 恭喜您成為會員,享受踢人禁言功能!\n");}if(key[1] == 'n'){printf(" sorry,開通失敗!\n");}sleep(1); }int ifvip(void *para,int columnCount,char **columnValue,char **columnName) //檢驗用戶是否為vip {if(strcmp(columnValue[0],"2") == 0){SIGN=1;}return 0; }int Tcunzai(void *para,int columnCount,char **columnValue,char **columnName) //檢驗用戶是否存在 {if(strcmp(columnValue[0],NAME) == 0){SIGN=1;}return 0; }void shutup(int sockfd) {sleep(1);system("clear");int ret;sqlite3 *pdb;char sql[100]={0};struct user User;ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite_open");return;}sprintf(sql,"select level from user1 where name='%s';",NAME2);ret=sqlite3_exec(pdb,sql,ifvip,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}if(SIGN == 0){printf(" 對不起,您的權限不足!\n"); sleep(1);return;}else{printf(" 請選擇您想禁言的用戶:");fflush(stdout);while(1){SIGN=0;SIGN3=0;scanf("%s",User.name);memset(NAME,0,sizeof(NAME));strcpy(NAME,User.name);sprintf(sql,"select name from user1 where name='%s';",User.name);ret=sqlite3_exec(pdb,sql,Tcunzai,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}sprintf(sql,"select state from user1 where name='%s';",User.name);ret=sqlite3_exec(pdb,sql,Tonline,NULL,NULL);//判斷用戶是否存在且是否在線if(ret != SQLITE_OK){perror("sqlite_exec");return;}if(SIGN == 1 && SIGN3 == 1){break;}else if(SIGN == 1 && SIGN3 == 0){printf(" 此用戶不在線!\n");printf(" 請重新輸入:");fflush(stdout);}else{printf(" 此用戶不存在!\n");printf(" 請重新輸入:");fflush(stdout);}}SIGN=0;User.type=6;ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;}ret=send(sockfd,&User,sizeof(User),0);if(ret == -1){perror("send");return;}printf(" %s用戶已被禁言!\n",User.name);sleep(1);}}void jiejin(int sockfd) {sleep(1);system("clear");int ret;sqlite3 *pdb;char sql[100]={0};struct user User;ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite_open");return;}sprintf(sql,"select level from user1 where name='%s';",NAME2);ret=sqlite3_exec(pdb,sql,ifvip,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}if(SIGN == 0){printf(" 對不起,您的權限不足!\n"); sleep(1);return;}else{printf(" 請選擇您想解禁的用戶:");fflush(stdout);while(1){SIGN=0;SIGN3=0;scanf("%s",User.name);memset(NAME,0,sizeof(NAME));strcpy(NAME,User.name);sprintf(sql,"select name from user1 where name='%s';",User.name);ret=sqlite3_exec(pdb,sql,Tcunzai,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}sprintf(sql,"select state from user1 where name='%s';",User.name);ret=sqlite3_exec(pdb,sql,Tonline,NULL,NULL);//判斷用戶是否存在且是否在線if(ret != SQLITE_OK){perror("sqlite_exec");return;}if(SIGN == 1 && SIGN3 == 1){break;}else if(SIGN == 1 && SIGN3 == 0){printf(" 此用戶不在線!\n");printf(" 請重新輸入:");fflush(stdout);}else{printf(" 此用戶不存在!\n");printf(" 請重新輸入:");fflush(stdout);}}SIGN=0;User.type=9;ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;}ret=send(sockfd,&User,sizeof(User),0);if(ret == -1){perror("send");return;}printf(" %s用戶已解除禁言!\n",User.name);sleep(1);}}void Kickout(int sockfd) {sleep(1);system("clear");int ret;sqlite3 *pdb;char sql[100]={0};struct user User;ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite_open");return;}sprintf(sql,"select level from user1 where name='%s';",NAME2);ret=sqlite3_exec(pdb,sql,ifvip,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}if(SIGN == 0){printf(" 對不起,您的權限不足!\n"); sleep(1);return;}else{printf(" 請選擇您想踢出的用戶:");fflush(stdout);while(1){SIGN=0;SIGN3=0;scanf("%s",User.name);memset(NAME,0,sizeof(NAME));strcpy(NAME,User.name);sprintf(sql,"select name from user1 where name='%s';",User.name);ret=sqlite3_exec(pdb,sql,Tcunzai,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}sprintf(sql,"select state from user1 where name='%s';",User.name);ret=sqlite3_exec(pdb,sql,Tonline,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}if(SIGN == 1 && SIGN3 == 1){break;}else if(SIGN == 1 && SIGN3 == 0){printf(" 此用戶不在線!\n");printf(" 請重新輸入:");fflush(stdout);}else {printf(" 此用戶不存在!\n");printf(" 請重新輸入:");fflush(stdout);}}SIGN=0;User.type=7;ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;}ret=send(sockfd,&User,sizeof(User),0);if(ret == -1){perror("send");return;}printf(" %s用戶已被您踢出!\n",User.name);sleep(1);}}void Quit(int sockfd) //退出 {sleep(1);system("clear");int ret;struct user User;User.state=0; User.type=8;strcpy(User.name,NAME2);ret=send(sockfd,&User,sizeof(User),0);if(ret == -1){perror("send");return;}printf("???????????????????????????????????????\n");printf("???? ? goodbye!~ ? ???? \n");printf("???????????????????????????????????????\n");sleep(1);}void TERMIN() {sleep(1);system("clear");printf("???????????????????????????????????????\n");printf("???? 您選擇了退出聊天室~ ????\n");printf("???????????????????????????????????????\n");sleep(1); }client-main.c
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<strings.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<pthread.h>#define PORT 1234struct user {char name[10];char ID[20];char password[20];int type;int state;char toname[10];char record[100];int fd;int level;struct user *next; };pthread_t tid[2]; int out=1; //標志位:表示是否退出客戶端void* denglu(void *arg) {int ret;char key1[10]={0}; //登錄界面功能選擇按鍵char key2[10]={0}; //登錄后功能選擇按鍵system("clear");printf("??????????????????????????????????\n");printf("????? ? 聊天室 ? ?????\n");printf("??????????????????????????????????\n");sleep(2);while(1){system("clear");printf("??????????????????????????????????????????\n");printf("????? 1.注冊 ????? \n");printf("????? 2.登錄 ????? \n");printf("????? 3.退出 ????? \n");printf("??????????????????????????????????????????\n");printf("????? 請選擇您的功能 ?????\n");printf("??????????????????????????????????????????\n");scanf("%s",key1);switch(key1[0]){case '1':system("clear");zhuce(*(int*)arg);//注冊界面break;case '2':system("clear");login(*(int*)arg);//登錄界面 getin: system("clear");printf("??????????????????????????????????????????\n");printf("????? 1.在線用戶 ????? \n");printf("????? 2.私聊 ????? \n");printf("????? 3.群聊 ?????\n");printf("????? 4.查詢私聊記錄 ????? \n");printf("????? 5.查詢群聊記錄 ?????\n");printf("????? 6.開通會員 ?????\n");printf("????? 7.禁言 ?????\n");printf("????? 8.踢人 ????? \n");printf("????? 9.退出 ????? \n");printf("????? 0.解禁 ????? \n");printf("??????????????????????????????????????????\n");printf("? 請選擇您的功能 ?\n");printf("??????????????????????????????????????????\n");scanf("%s",key2);switch(key2[0]){case '1':listonline();//查看在線用戶sleep(2);goto getin;case '2':chatprivate(*(int*)arg);//私聊sleep(2);goto getin;case '3':chatall(*(int*)arg);//群發sleep(2);goto getin;case '4':findprivate();//查詢私聊記錄sleep(2);goto getin;case '5':findall();//查詢群聊記錄sleep(2);goto getin;case '6':VIP(*(int*)arg);//開通會員sleep(2);goto getin;case '7':shutup(*(int*)arg);//禁言sleep(2);goto getin;case '8':Kickout(*(int*)arg); //踢人sleep(2);goto getin;case '9':Quit(*(int*)arg); //退出界面sleep(2);break;case '0':jiejin(*(int*)arg);//解除禁言sleep(2);goto getin;default:printf("??????????????????????????????????????????\n");printf("????? 錯誤按鈕(登錄后)! ?????\n");printf("??????????????????????????????????????????\n");sleep(2);goto getin; }break;case '3':goto breakout;default:printf("??????????????????????????????????????????\n");printf("????? 錯誤按鈕(登錄前)! ?????\n");printf("??????????????????????????????????????????\n");printf("錯誤按鈕(登錄前)!\n");break;}}breakout:TERMIN();//退出客戶端out=0;//復位pthread_cancel(tid[0]);//退出客戶端后,將接受信息的進程殺死,不然一直阻塞在那里}void* Receive(void *arg) {int ret;struct user User;while(1){memset(&User,0,sizeof(User));ret=recv(*(int*)arg,&User,sizeof(User),0);if(ret == -1){perror("recv");exit(1);}if(User.type == 3)//私聊{printf("%s:%s\n",User.name,User.record);}if(User.type == 4)//群發{printf("%s:%s\n",User.name,User.record);}if(User.type == 7)//踢人{break;}} }int main() {int sockfd;int ret;char key1[10]={0};//登錄選擇char key2[10]={0};//登錄后選擇struct sockaddr_in server_addr;sockfd=socket(PF_INET,SOCK_STREAM,0);if(sockfd == -1){perror("socket");exit(1);}bzero(&server_addr,sizeof(server_addr));server_addr.sin_family=PF_INET;server_addr.sin_port=htons(PORT);server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");ret=connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));//連接服務器if(ret == -1){perror("connect");exit(1);}while(1){ret=pthread_create(&tid[0],NULL,Receive,(void*)&sockfd);if(ret != 0){perror("pthread_create");exit(1);}ret=pthread_create(&tid[1],NULL,denglu,(void*)&sockfd);if(ret != 0){perror("pthread_create");exit(1);}pthread_join(tid[0],NULL);if(out == 0){break;}pthread_cancel(tid[1]);//先退出登錄后的界面,回到注冊登錄退出界面,完成被踢就退出的功能printf("??????????????????????????????????????????\n");printf("????? 您被管理員踢出了聊天室! ?????\n");printf("??????????????????????????????????????????\n");sleep(3);}return 0; }server.c
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<strings.h> #include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h> #include<sys/select.h> #include<sys/time.h> #include<unistd.h> #include<sqlite3.h>struct user {char name[10];char ID[20];char password[20];int type;int state;char toname[10];char record[100];int fd;int level;struct user *next; };int tofd=0; //私聊的通信管道號 char NAME[20]={0}; //暫時存儲用戶昵稱 int onlineflag=0; void zhuce(struct user User,int fd) //消息類型1:注冊 {int ret;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite3_open");return; } sprintf(sql, "create table if not exists user1 (name text,ID text,password text,state integer,level integer);");//繼續使用user1表 ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL); if(ret != SQLITE_OK){perror("sqlite_create"); return;}sprintf(sql,"insert into user1 (name,ID,password,state,level) values('%s','%s','%s',%d,%d);",User.name,User.ID,User.password,User.state,User.level);//插入用戶信息ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_insert");return;}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;} }void login(struct user User,int fd) //消息類型12:登錄 {int ret;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite3_open");return;}sprintf(sql,"create table if not exists user2 (name text,fd integer);");//繼續使用user2表 ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_create");return;}sprintf(sql,"insert into user2(name,fd) values('%s',%d);",User.name,fd);//將客戶端的通信管道號插入表中ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_update");return;}sprintf(sql,"update user1 set state=1 where ID='%s';",User.ID);//設置在線ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_update");return;}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;} }void Turn(char a[]) {if(strcmp(a,"smile") == 0){strcpy(a,"( ^_^ )");}if(strcmp(a,"cry") == 0){strcpy(a,"T_T");}if(strcmp(a,"sweat") == 0){strcpy(a,"-_-!");}if(strcmp(a,"angry") == 0){strcpy(a,">_<");}if(strcmp(a,"dizzy") == 0){strcpy(a,"+_+");}if(strcmp(a,"suprise") == 0){strcpy(a,"(⊙?⊙)");} }int assign(void *para,int columnCount,char **columnValue,char **cloumnName) //通過用戶昵稱找到通信管道號 {tofd=atoi(columnValue[0]);return 0; }void chatprivate(struct user User,int fd) //消息類型13:私聊 {int ret;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite3_open");return;}sprintf(sql,"select fd from user2 where name='%s';", User.toname);ret=sqlite3_exec(pdb,sql,assign,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite3_exec");return;}Turn(User.record);//將文字轉換為表情符號ret=send(tofd,&User,sizeof(User),0); if(ret == -1){perror("send");return;}sprintf(sql, "create table if not exists Privatechatrecord (name text,toname text,record text);"); //創建Privatechat表ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL); if(ret != SQLITE_OK){perror("sqlite_create"); return;}sprintf(sql,"insert into Privatechatrecord (name,toname,record) values('%s','%s','%s');",User.name,User.toname,User.record);//存儲私聊ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_insert");return;}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;}tofd=0; }int Tstate(void *para,int columnCount,char **columnValue,char **columnName) //檢測是否在線 {if(strcmp(columnValue[0],"0") != 0){onlineflag=1;}return 0; }void chatall(struct user User,int source_fd,int fd[],int k) //消息類型14:群聊 {int i;int ret;sqlite3 *pdb;char sql[100]={0};Turn(User.record);ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite3_open");return;}sprintf(sql, "create table if not exists Groupchatrecord (name text,record text);");//創建Groupchat表 ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL); if(ret != SQLITE_OK){perror("sqlite_create"); return;}sprintf(sql,"insert into Groupchatrecord (name,record) values('%s','%s');",User.name,User.record);//存儲群聊ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_insert");return;}for(i=0;i<k;i++){if(fd[i] == source_fd)//給除了自己以外的用戶發送消息{continue;}sprintf(sql,"select fd from user2 where fd='%d';",fd[i]);ret=sqlite3_exec(pdb,sql,Tstate,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_exec");return;}if(onlineflag == 1){ret=send(fd[i],&User,sizeof(User),0);if(ret == -1){perror("send");return;}onlineflag=0;}}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;} }void VIP(struct user User) //消息類型15:開通會員 {int ret;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite3_open");return;}sprintf(sql,"update user1 set level=2 where name='%s';",User.name);//更新用戶權限為管理員ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_update");return;}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;} }void shutup(struct user User) //消息類型16:禁言 {int ret;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite3_open");return;}sprintf(sql,"update user1 set level=0 where name='%s';",User.name);//更新用戶權限為被禁言ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_update");return;}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;} }void kickout(struct user User) //消息類型17:踢人 { int ret;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite3_open");return;}sprintf(sql,"update user1 set state=0 where name='%s';",User.name);//更新用戶不在線ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_update");return;}sprintf(sql,"select fd from user2 where name='%s';", User.name);//找到對應通信管道號ret=sqlite3_exec(pdb,sql,assign,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite3_exec");return;}sprintf(sql,"delete from user2 where name='%s';",User.name);//將被踢用戶從表中刪除ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_delete");return;}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;} ret=send(tofd,&User,sizeof(User),0);if(ret == -1){perror("send");return;}tofd=0; }void quit(struct user User) //消息類型18:退出 {int ret;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite3_open");return;}sprintf(sql,"update user1 set state=0 where name='%s';",User.name);//更新用戶不在線ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_update");return;}sprintf(sql,"delete from user2 where name='%s';",User.name);//將用戶從表中刪除ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_delete");return;}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;} } void jiejin(struct user User) //消息類型16:禁言 {int ret;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite3_open");return;}sprintf(sql,"update user1 set level=1 where name='%s';",User.name);//更新用戶權限為解除禁言ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);if(ret != SQLITE_OK){perror("sqlite_update");return;}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");return;} }server_main.c
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<strings.h> #include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h> #include<sys/select.h> #include<sys/time.h> #include<unistd.h> #include<sqlite3.h>#define PORT 1234struct user {char name[10];char ID[20];char password[20];int type;int state;char toname[10];char record[100];int fd;int level;struct user *next; };int main() {int sockfd;int ret;int fd[100]; int MaxFd;int i=0,j;fd_set ReadFd,TmpFd;struct sockaddr_in server_addr;struct sockaddr_in client_addr;struct user User;sqlite3 *pdb;char sql[100]={0};ret=sqlite3_open("Database.db",&pdb);if(ret != SQLITE_OK){perror("sqlite3_open");exit(1);}sprintf(sql,"create table if not exists user1 (name text,ID text,password text,state integer,level integer);"); //創建user1表 ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL); if(ret != SQLITE_OK){perror("sqlite_create1"); exit(1);}sprintf(sql,"create table if not exists user2 (name text,fd integer);");//創建user2表 ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL); if(ret != SQLITE_OK){perror("sqlite_create1"); exit(1);}sprintf(sql,"create table if not exists Privatechatrecord (name text,toname text,record text);");//創建Private chat record表 ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL); if(ret != SQLITE_OK){perror("sqlite_create2"); exit(1);}sprintf(sql, "create table if not exists Groupchatrecord (name text,record text);");//創建Group chat record表 ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL); if(ret != SQLITE_OK){perror("sqlite_create3"); exit(1);}ret=sqlite3_close(pdb);if(ret != SQLITE_OK){perror("sqlite_close");exit(1);} sockfd=socket(PF_INET,SOCK_STREAM,0);//創建平臺if(sockfd == -1){perror("socket");exit(1);}int opt=1;setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//允許多開,避免地址覆蓋bzero(&server_addr,sizeof(server_addr));server_addr.sin_family=PF_INET;server_addr.sin_port=htons(PORT);server_addr.sin_addr.s_addr=htonl(INADDR_ANY);ret=bind(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr));//把自己綁定好if(ret == -1){perror("bind");exit(1);}ret=listen(sockfd,10);//監聽信息if(ret == -1){perror("listen");exit(1);}FD_ZERO(&ReadFd);FD_ZERO(&TmpFd);FD_SET(sockfd,&ReadFd);MaxFd=sockfd;while(1){TmpFd=ReadFd;ret=select(MaxFd+1,&TmpFd,NULL,NULL,NULL);//用select阻塞if(ret == -1){perror("select");exit(1);}if(FD_ISSET(sockfd,&TmpFd))//看看是不是 有客戶(fd)向服務sockfd發起連接{int length=sizeof(client_addr);fd[i]=accept(sockfd,(struct sockaddr*)&client_addr,&length);//如果有 則sockfd接受 保存客戶信息if(fd[i] == -1){perror("accept");exit(1);}FD_SET(fd[i],&ReadFd);//將客戶加入監聽集合MaxFd=fd[i];//更新maxfd i++;//每有一個客戶發起連接 人數加一}else//fd 在發消息{for(j=0;j<i;j++){if(FD_ISSET(fd[j],&TmpFd))//查看是哪個客戶在發消息 引起了fd 的變化{memset(&User,0,sizeof(User));ret=recv(fd[j],&User,sizeof(User),0);if(ret == -1){perror("recv");exit(1);}if(User.type == 1)//消息類型1:注冊{zhuce(User,fd[j]); }if(User.type == 2)//消息類型12:登錄{login(User,fd[j]); }if(User.type == 3)//消息類型13:私聊{chatprivate(User,fd[j]);}if(User.type == 4)//消息類型14:群聊{chatall(User,fd[j],fd,i);}if(User.type == 5)//消息類型15:開通會員{VIP(User); }if(User.type == 6)//消息類型16:禁言{shutup(User);}if(User.type == 7)//消息類型17:踢人{kickout(User);}if(User.type == 8)//消息類型18:退出{quit(User);}if(User.type == 9)//消息類型18:退出{jiejin(User);}}}}}return 0; }?
UDP參考網上小姐姐的代碼 我做了封裝
#ifndef _CHAT_H_ #define _CHAT_H_#include <stdio.h> #include <sqlite3.h> #include <sys/types.h> #include <sys/socket.h> #include <string.h> #include <strings.h> #include <stdlib.h> #include <netinet/in.h> //包含socketaddr_in #include <arpa/inet.h> #include <unistd.h> #include <signal.h> #include <pthread.h> #include <semaphore.h> #include <termios.h> #include <time.h> #include <sys/stat.h> #include <fcntl.h> #define PORT 9999#define reg 11 //注冊,cmd #define reg_success 12 //注冊成功 #define existing 13 //賬號已存在 #define log_in 14 //登錄,cmd #define log_success 15 //登錄成功 #define logged 16 //賬號已登錄 #define log_error 17 //賬號或密碼錯誤#define private_chat 18 //私聊 #define group_chat 19 //群聊 #define Gchat_failure 20 //群聊失敗 #define online 21 //在線人數 #define Vip 22 //會員 #define shutup 23 //禁言 #define relieve 24 //解除禁言 #define kick 25 //踢人 #define face 26 //群發表情 #define send_useful 27 //發送常用語 #define Exit 28 //退出 #define quit 31 //下線#define Send_success 29 //發送成功 #define Pchat_failure 30 //私聊失敗 #define Send_failure 32 //發送失敗 #define face_failure 33 //發送表情失敗 #define vip_success 34 //開通會員成功 #define shutup_success 35 //禁言成功 #define kick_success 36 //踢人成功 #define shutup_failure 37 //禁言失敗 #define kick_failure 38 //踢人失敗#endifclient_function.h
#ifndef _CLIENT_H_ #define _CLIENT_H_struct info {char username[20]; //用戶名 char password[20]; //密碼 int cmd; //提取操作類型 int result; //返回標記int port; //端口號char message[50]; //保存信息char toname[20]; //發送給誰char fromname[20]; //從誰那里接收char online_name[20][20]; //在線人員名單int num;int p_f;char emoj[20]; //表情int p_u;char useful[20];int vip;char question[50];char answer[50];char file_name[50];char file_content[2048]; };//時間函數 自己百度查找 void time_show();void welcome(void);void bye(void);void show();//防止空格影響 void SCAN_N();//登錄之后的聊天界面 int chatshow();//注冊 將注冊信息發送給服務器 進行注冊 這里是確認注冊信息的過程 int Register();//登錄 同上 確認登錄信息 int Login();//處理登陸后的函數 int deal_login();//接收服務器發送的結果的接口函數 void *Recv_Server(void *arg);#endifclient_main.c
\
#include "clientfunction.h" #include "chat.h"struct info RecvBuf; //接收方 的信息保存 struct info SendBuf; //發送方 的信息保存struct sockaddr_in server_addr; //記錄服務器地址 便于信息傳輸char name[20] = { 0 }; int ret; int sockfd; int flag; int out = 0;//時間函數 自己百度查找 void time_show() {time_t rawtime;struct tm *timeinfo;time(&rawtime);timeinfo = localtime(&rawtime);printf("時間: %d 年 %d 月 %d 日 %d 時 %d 分 %d 秒\n\n", timeinfo->tm_year + 1900, timeinfo->tm_mon + 1,timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);}void welcome(void) {system("clear");printf("\t\t\t*********************************************\n");printf("\t\t\t* *\n");printf("\t\t\t* *\n");printf("\t\t\t* *\n");printf("\t\t\t* Welcome To UDP Chatting Room ! *\n");printf("\t\t\t* *\n");printf("\t\t\t* *\n");printf("\t\t\t* *\n");printf("\t\t\t* *\n");printf("\t\t\t*********************************************\n");sleep(2); }void bye(void) {system("clear");printf("\t\t\t*********************************************\n");printf("\t\t\t\t* *\n");printf("\t\t\t* *\n");printf("\t\t\t* *\n");printf("\t\t\t* Hope To See You Again ! *\n");printf("\t\t\t* *\n");printf("\t\t\t* *\n");printf("\t\t\t* *\n");printf("\t\t\t* *\n");printf("\t\t\t*********************************************\n");sleep(2);}void show() {system("clear");printf("\t\t\t**********************************************\n");printf("\t\t\t* *\n");printf("\t\t\t* UDP聊天室 *\n");printf("\t\t\t* *\n");printf("\t\t\t* 1 注冊 *\n");printf("\t\t\t* 2 登錄 *\n");printf("\t\t\t* 3 退出 *\n");printf("\t\t\t* *\n");printf("\t\t\t* 請輸入選擇: *\n");printf("\t\t\t**********************************************\n"); }//防止空格影響 void SCAN_N() {char ch;while ((getchar()) != '\n' && ch != EOF);//消除非法輸入 }//登錄之后的聊天界面 int chatshow() {system("clear");printf("\t\t\t");time_show();printf("\t\t\t**********************************************\n");printf("\t\t\t* UDP聊天室!祝您聊天愉快! *\n");printf("\t\t\t* 用戶名:%s *\n", name);if (SendBuf.vip == 1){printf("\t\t\t* 尊貴的會員 *\n");}else{printf("\t\t\t* 普通用戶 *\n");}printf("\t\t\t* *\n");printf("\t\t\t* a 私聊 *\n");printf("\t\t\t* b 群聊 *\n");printf("\t\t\t* c 查看在線人數 *\n");printf("\t\t\t* d 發送表情 *\n");printf("\t\t\t* e 常用語 *\n");printf("\t\t\t* f 開通會員 *\n");printf("\t\t\t* g 禁言(需開通會員) *\n");printf("\t\t\t* h 踢人(需開通會員) *\n");printf("\t\t\t* i 查看聊天記錄 *\n");printf("\t\t\t* j 解禁 *\n");printf("\t\t\t* k 退出 *\n");printf("\t\t\t* 請輸入您的選擇: *\n");printf("\t\t\t**********************************************\n"); }//注冊 將注冊信息發送給服務器 進行注冊 這里是確認注冊信息的過程 int Register() {flag = 0;system("clear");SendBuf.cmd = reg;char pass1[20] = { 0 };char pass2[20] = { 0 };printf("\t\t\t注冊中......\n");printf("\n\n");printf("\t\t\t請輸入你的用戶名:\n");printf("\t\t\t");scanf("\t\t\t%s", SendBuf.username);SCAN_N();printf("\t\t\t請輸入你的密碼:\n");printf("\t\t\t");scanf("\t\t\t%s", pass1);SCAN_N();printf("\t\t\t請確認你的密碼:\n");printf("\t\t\t");scanf("\t\t\t%s", pass2);SCAN_N();if (strcmp(pass1, pass2) != 0){printf("\t\t\t密碼輸入不一致!請重新輸入密碼!\n");printf("請在此重新輸入你的密碼:\n");scanf("%s", pass2);}else{strcpy(SendBuf.password, pass1);} }//登錄 同上 確認登錄信息 int Login() {system("clear");SendBuf.cmd = log_in;printf("\t\t\t登錄中......\n");printf("\n\n");printf("\t\t\t請輸入你的賬號:\n");printf("\t\t\t");scanf("\t\t\t%s", SendBuf.username);SCAN_N();printf("\t\t\t請輸入你的密碼:\n");printf("\t\t\t");scanf("\t\t\t%s", SendBuf.password);}//處理登陸后的函數 int deal_login() {if (out == 1){out--;return Exit;}char choice2[10] = { 0 };char file[2048] = { 0 };char filename[50] = { 0 };int fd;while (1){chatshow();scanf("%s", choice2); //讀入用戶選擇的功能字母switch (choice2[0]){case 'a': //私聊 {system("clear"); //清屏if (flag == 23) //判斷是否被禁言{printf("\n\t\t\t您已經被禁言了!\n");sleep(2);break;}printf("\t\t\t請輸入對方的名字:\n");printf("\t\t\t");scanf("%s", SendBuf.toname);SCAN_N();printf("\t\t\t請輸入您想要說的話:\n");printf("\t\t\t");scanf("%s", SendBuf.message);SCAN_N();SendBuf.cmd = private_chat; //操作符 為私聊strcpy(SendBuf.username, name);if (strcmp(SendBuf.toname, name) == 0){sleep(1);system("clear");printf("\t\t\t不可以給自己發信息!\n");printf("\t\t\t請重新輸入用戶名!\n");break;}ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));/* 發送給服務器 我要私聊某某 */if (ret < 0){perror("sendto_pchat");exit(1);}sprintf(filename, "%s chat with %s.txt", name, SendBuf.toname);fd = open(filename, O_CREAT | O_RDWR | O_APPEND, S_IRUSR | S_IWUSR);if (fd == -1){perror("open");exit(1);}sprintf(file, "%s 給 %s 發送了一條消息:%s", name, SendBuf.toname, SendBuf.message);ret = write(fd, file, strlen(file));if (ret == -1){perror("write");exit(1);}printf("\t\t\t\t發送中...\n");sleep(2);break;}case 'b'://群聊{system("clear");if (flag == 23) //同上{printf("\n\t\t\t您已經被禁言了!\n");sleep(2);break;}printf("\t\t\t請發送消息:\n");scanf("%s", SendBuf.message);SendBuf.cmd = group_chat;strcpy(SendBuf.username, name);ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));if (ret < 0){perror("sendto_groupchat");exit(1);}printf("\t\t\t發送中......\n");sleep(2);break;}case 'c': //查看在線人數{system("clear");SendBuf.cmd = online; //操作符 查看在線ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));if (ret < 0){perror("sendto_onlinenum");exit(1);}sleep(3); //注意如果人數很多 睡眠時間建議稍微長點 不然查看的效果很差break;}case 'd': //群發表情{system("clear");if (flag == 23){printf("\n\t\t\t您已經被禁言了!\n");sleep(2);break;}char choice3[10] = { 0 };SendBuf.cmd = face;printf("\t\t\t**************************\n");printf("\t\t\t1 感動 ≧◇≦ \n");printf("\t\t\t2 無奈 ╮( ̄▽  ̄)╭\n");printf("\t\t\t3 哭泣 T_T\n");printf("\t\t\t4 驚訝 ⊙?⊙\n");printf("\t\t\t5 喵 (= ̄ω ̄=)\n");printf("\t\t\t6 害羞 (# ̄▽ ̄#)\n");printf("\t\t\t請輸入你的選擇\n");scanf("%s", choice3);SendBuf.p_f = choice3[0];strcpy(SendBuf.username, name);ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));if (ret < 0){perror("sendto_face");exit(1);}printf("\t\t\t發送中......\n");sleep(2);break;}case 'e': //發送常用語{system("clear");if (flag == 23){printf("\n\t\t\t您已經被禁言了!\n");sleep(2);break;}char choice4[10] = { 0 };printf("\t\t\t請輸入對方的名字:\n");printf("\t\t\t");scanf("%s", SendBuf.toname);strcpy(SendBuf.username, name);SendBuf.cmd = send_useful;printf("\t\t\t**************************\n");printf("\t\t\t1 I see. 我明白了.\n");printf("\t\t\t2 My god! 天哪!\n");printf("\t\t\t3 No way! 不行!\n");printf("\t\t\t4 Cheer up! 振作起來!\n");printf("\t\t\t5 Good job! 做得好!\n");printf("\t\t\t6 Bless you! 祝福你!\n");printf("\t\t\t7 Thank you! 謝謝!\n");printf("\n\t\t請輸入你想發送的常用語:\n");scanf("%s", choice4);SCAN_N();SendBuf.p_u = choice4[0];if (strcmp(name, SendBuf.toname) == 0){sleep(1);system("clear");printf("\t\t\t不可以給自己發送常用語");printf("\t\t\t請重新輸入用戶名!\n");return -1;}ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));if (ret < 0){perror("sendto_useful");exit(1);}printf("\n\t\t正在發送...\n");sleep(2);break;}case 'f': //開通會員{system("clear");if (SendBuf.vip == 0){char a[2];system("clear");printf("\n\n\n\t\t\t您確定要支付十萬塊成為會員嗎?\n");printf("\n\t\t\t您確認支付嗎?(y/n)");scanf("%s", a);if (a[0] == 'y'){strcpy(SendBuf.username, name);SendBuf.vip = 1;SendBuf.cmd = Vip;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));if (ret < 0){perror("sendto_vip");exit(1);}printf("\n\n\t\t請稍等...\n");sleep(2);}else{break;}}else if (SendBuf.vip == 1){printf("您已經是會員了,無需再次開通!\n");}break;}case 'g': //禁言{if (SendBuf.vip == 1){system("clear");printf("請選擇您想要禁言的人:\n");scanf("%s", SendBuf.toname);SendBuf.cmd = shutup;strcpy(SendBuf.username, name);if (strcmp(SendBuf.toname, name) == 0){sleep(1);system("clear");printf("\t\t\t不可以禁言自己!\n");printf("\t\t\t請重新輸入用戶名!\n");break;}ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));if (ret < 0){perror("sendto_shutup1");exit(1);}printf("\n\n\t\t請稍等...\n");sleep(2);}else if (SendBuf.vip == 0){printf("您需要開通會員才能禁言別人哦!\n");}break;}case 'h': //踢人{if (SendBuf.vip == 1) //這里就不注意對方是不是會員了 會員之間相互踢還是可以的{system("clear");printf("請選擇您想要讓他下線的人:\n");scanf("%s", SendBuf.toname);SendBuf.cmd = kick;strcpy(SendBuf.username, name);ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));if (ret < 0){perror("sendto_kick1");exit(1);}printf("\n\n\t\t請稍等...\n");sleep(2);}else if (SendBuf.vip == 0){printf("您需要開通會員才能讓別人下線哦!");}break;}case 'i': //查看聊天記錄 {system("clear");char n[20];char filename1[50];char file1[2048];char kl;int fd1;int i = 0;printf("\n\n\n\n\n\n\t\t\t您想看和誰的聊天記錄呢?\n");scanf("%s", n);SCAN_N();sprintf(filename1, "%s chat with %s.txt", name, n);fd1 = open(filename1, O_RDONLY, S_IRUSR | S_IWUSR);if (fd1 == -1){system("clear");printf("\n\n\n\n\n\n\n\t\t\t您與%s還沒有聊天記錄!\n", n);break;}while (1){memset(&kl, 0, sizeof(kl));ssize_t read_bytes = read(fd1, &kl, sizeof(kl));if (read_bytes == -1){perror("read");return -1;}if (read_bytes == 0){break;}file1[i] = kl;i++;}file1[i] = '\0';printf("\n%s\n", file1);sleep(3);break;}case 'j': //解禁 {char x[2];if (flag == 0){system("clear");printf("\n\n\n\t\t\t您沒有被禁言!\n");}else if (flag == 23){if (SendBuf.vip == 0){system("clear");printf("\n\n\n\n\t\t\t您還沒有開通會員,請先開通會員!\n");}else if (SendBuf.vip == 1){system("clear");printf("\n\n\n\n\t\t\t您想現在解禁嗎!(y/n)\n");scanf("%s", x);SCAN_N();if (x[0] == 'y'){flag = 0;system("clear");printf("\n\n\n\t\t\t恭喜您成功解禁!\n");}}}break;}case 'k': //下線{system("clear");SendBuf.cmd = quit;strcpy(SendBuf.username, name);ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));if (ret < 0){perror("sendto_quit1");exit(1);}sleep(1);return Exit;}case 'q':return Exit;default:{system("clear");printf("\n\n\n\n");printf("\n\n\t\t請輸入a--z之間的選擇!\n");sleep(2);break;}}} }//接收服務器發送的結果的接口函數 void *Recv_Server(void *arg) {char q;int i;int length = sizeof(server_addr);while (1){ret = recvfrom(*(int *)arg, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&server_addr, &length);if (ret < 0){perror("recvfrom");exit(1);}switch (RecvBuf.result){case(private_chat) :{printf("\t\t\t%s 給你發了一條消息:%s\n", RecvBuf.fromname, RecvBuf.message);memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));break;}case(Send_success) :{system("clear");printf("\t\t\t發送成功\n");memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));break;}case(Send_failure) :{system("clear");printf("\t\t\t發送失敗,對方不在線\n");memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));break;}case(Pchat_failure) :{system("clear");printf("\t\t\t對不起,對方不在線!\n");memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));break;}case(group_chat) :{printf("\t\t\t%s 群發了一條消息:%s\n", RecvBuf.fromname, RecvBuf.message);memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));break;}case(Gchat_failure) :{system("clear");printf("\t\t\t群聊失敗!\n");memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));break;}case(online) :{system("clear");printf("\t\t\t當前在線好友人數: %d\n", RecvBuf.num);for (i = 0; i < RecvBuf.num; i++){printf("\t\t\t%s\n", RecvBuf.online_name[i]);}memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));break;}case(face) :{char emoj1[20] = { 0 };switch (RecvBuf.p_f){case '1':{strcpy(emoj1, "感動 ≧◇≦");printf("\t\t\t%s 給大家發了一個表情:%s\n", RecvBuf.fromname, emoj1);break;}case '2':{strcpy(emoj1, "無奈 ╮( ̄▽  ̄)╭");printf("\t\t\t%s 給大家發了一個表情:%s\n", RecvBuf.fromname, emoj1);break;}case '3':{strcpy(emoj1, "哭泣 T_T");printf("\t\t\t%s 給大家發了一個表情:%s\n", RecvBuf.fromname, emoj1);break;}case '4':{strcpy(emoj1, "驚訝 ⊙?⊙");printf("\t\t\t%s 給大家發了一個表情:%s\n", RecvBuf.fromname, emoj1);break;}case '5':{strcpy(emoj1, "喵 (= ̄ω ̄=)");printf("\t\t\t%s 給大家發了一個表情:%s\n", RecvBuf.fromname, emoj1);break;}case '6':{strcpy(emoj1, "害羞 (# ̄▽ ̄#)");printf("\t\t\t%s 給大家發了一個表情:%s\n", RecvBuf.fromname, emoj1);break;}}break;}case(face_failure) :{system("clear");printf("發送失敗,沒有該表情!\n");sleep(2);memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));break;}case (send_useful) :{char ue[50];switch (RecvBuf.p_u){case '1':strcpy(ue, "I see. 我明白了.");printf("\t\t\t%s給你發送了一句常用語:%s\n", RecvBuf.fromname, ue);break;case '2':strcpy(ue, "My god! 天哪!");printf("\t\t\t%s給你發送了一句常用語:%s\n", RecvBuf.fromname, ue);break;case '3':strcpy(ue, "3 No way! 不行!");printf("\t\t\t%s給你發送了一句常用語:%s\n", RecvBuf.fromname, ue);break;case '4':strcpy(ue, "Cheer up! 振作起來!");printf("\t\t\t%s給你發送了一句常用語:%s\n", RecvBuf.fromname, ue);break;case '5':strcpy(ue, "Good job! 做得好!");printf("\t\t\t%s給你發送了一句常用語:%s\n", RecvBuf.fromname, ue);break;case '6':strcpy(ue, "Bless you! 祝福你!");printf("\t\t\t%s給你發送了一句常用語:%s\n", RecvBuf.fromname, ue);break;case '7':strcpy(ue, "Thank you! 謝謝!");printf("\t\t\t%s給你發送了一句常用語:%s\n", RecvBuf.fromname, ue);break;}break;}case(vip_success) :{printf("\t\t\t恭喜您成功開通會員\n");sleep(2);break;}case(shutup) :{flag = 23;printf("\t\t\t%s已經把您禁言了!\n", RecvBuf.fromname);break;}case(shutup_success) :{printf("\t\t\t禁言成功!\n");sleep(2);break;}case(shutup_failure) :{printf("\t\t\t對方不在線,禁言失敗!\n");break;}case(kick) :{out = 1;printf("\t\t\t您已經被%s踢出了聊天室,請重新登錄!\n", RecvBuf.fromname);printf("\t\t\t輸入q返回!\n");break;}case(kick_success) :{printf("\t\t\t踢人成功!\n");sleep(2);break;}case(kick_failure) :{printf("\t\t\t對方不在線,踢人失敗!\n");break;}case(quit) :{system("clear");printf("您已經成功下線!\n");sleep(2);break;}}} }int main() {int length = sizeof(server_addr);char choice[10] = { 0 };pthread_t tid;sockfd = socket(PF_INET, SOCK_DGRAM, 0); //創建套接字if (-1 == sockfd){perror("sockt");exit(1);}bzero(&server_addr, sizeof(server_addr));server_addr.sin_family = PF_INET;server_addr.sin_port = PORT;server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");welcome();while (1){show();scanf("%s", choice);switch (atoi(&choice[0])){case 1: //注冊 {if (Register() == -12){break;}else{ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));if (ret < 0){perror("sendto_register");exit(1);}bzero(&SendBuf, sizeof(SendBuf));ret = recvfrom(sockfd, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&server_addr, &length);if (ret < 0){perror("recvfrom_register");exit(1);}if (RecvBuf.result == reg_success){printf("\n\n\t\t\t恭喜您注冊成功!\n");}else if (RecvBuf.result == existing){printf("\n\n\t\t\t該賬戶已被注冊!請重新注冊!\n");}sleep(2);break;}}case 2: //登錄{if (Login() == -14){break;}else{ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));if (ret < 0){perror("sendto_login");exit(1);}bzero(&SendBuf, sizeof(SendBuf));ret = recvfrom(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, &length);if (ret < 0){perror("recvfrom_login");exit(1);}if (SendBuf.result == log_success){printf("\n\n\t\t\t恭喜你登錄成功!\n");strcpy(name, SendBuf.username);sleep(2);ret = pthread_create(&tid, NULL, (void *)Recv_Server, (void *)&sockfd); //起一個線程專門用來接收服務器發送給客戶端的結果反饋if (ret < 0){perror("pthread_create");exit(1);}pthread_detach(tid);ret = deal_login();if (ret == Exit){break;}}else if (SendBuf.result == logged){printf("\n\n\t\t\t賬號已登錄!\n");}else if (SendBuf.result == log_error){printf("\n\n\t\t\t賬號或密碼錯誤,請重新登錄!\n");}}break;}case 3:{bye();system("clear");exit(1);break;}default:{system("clear");printf("\n\n\n\n");printf("\n\n\t\t請輸入1--3之間的選擇!\n");sleep(2);break;}}}return 0; }server_function.h
#ifndef _SERVER_H_ #define _SERVER_H_#include "chat.h"struct info {char username[20]; //用戶名 char password[20]; //密碼 int cmd; //提取操作類型 int result; //返回標記int port; //端口號char message[50]; //保存信息char toname[20]; //發送給誰char fromname[20]; //從誰那里接收char online_name[20][20]; //在線人員名單int num;int p_f;char emoj[20]; //表情int p_u;char useful[20];int vip;char question[50];char answer[50];char file_name[50];char file_content[2048]; };struct node {struct sockaddr_in client_addr; //保存客戶地址char name[20]; //記錄客戶姓名struct node *next; //指向下一個用戶 }; /*sockaddr_in 是internet環境下套接字的地址形式;;sockaddr_in在頭文件#include<netinet/in.h>或#include <arpa/inet.h>中定義*/typedef struct node Node; //起別名 簡化結構體 取名為 Node 用Node創建新結構體 存儲客戶信息 typedef Node *Lnode; //同樣 結構體取指針別名 對應的函數返回值是結構體類型//注冊函數 void register1();//登錄函數 void login(struct sockaddr_in tmp_addr);//處理私聊 int deal_private(struct sockaddr_in tmp_addr);//處理群聊 同上 int deal_group(struct sockaddr_in tmp_addr);//顯示在線人數 int deal_online();//處理群發表情 同上 int deal_face(struct sockaddr_in tmp_addr);//處理發送常用語 同上 int deal_useful(struct sockaddr_in tmp_addr);//處理vip int deal_vip(struct sockaddr_in tmp_addr);//處理禁言 同上 int deal_shutup(struct sockaddr_in tmp_addr);//處理踢人 同上 int deal_kick(struct sockaddr_in tmp_addr);//處理下線 int deal_quit();#endifserver_main.c
#include "serverfunction.h" #include "chat.h"struct info RecvBuf; //接收方 的信息保存 struct info SendBuf; //發送方 的信息保存sqlite3 *ppdb = NULL; //打開一個數據庫實例 int ret; int sockfd; Lnode head = NULL; //創建第一個節點//注冊函數 void register1() {char sql[100] = { 0 };sprintf(sql, "insert into chat(username,password,vip) values('%s','%s','%d')", RecvBuf.username, RecvBuf.password, RecvBuf.vip);/*將數據插入到 sql數據庫中,上述語句在執行完sprintf語句后,sql中保存的是INSERT語句字符串,可實現正確的插入。*/char *errmsg = NULL; //保存 錯誤的原因int ret;ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg); /*如果沒有成功創建數據庫實例則報錯(參考https://www.cnblogs.com/zfyouxi/p/5258589.html*/if (ret != SQLITE_OK){perror("sqlite3_exec2");SendBuf.result = existing; //賬號已存在printf("%s is insert failure:%s\n\n", RecvBuf.username, errmsg); //輸出錯因return;}//沒有報錯即成功printf("user insert success!yohoo~\n\n");SendBuf.result = reg_success; }//登錄函數 void login(struct sockaddr_in tmp_addr) {char sql[100] = { 0 };char **Result = NULL; //返回記錄,二維數組int nrow; //查找出的 行數int ncolumn; //查找出的 列數int ret;int i;sprintf(sql, "select username, password ,vip from chat where username = '%s' and password = '%s'", RecvBuf.username, RecvBuf.password);//查詢語句 查看登錄的用戶信息ret = sqlite3_get_table(ppdb, sql, &Result, &nrow, &ncolumn, NULL);/* char **dbResult; 字符型的二重指針,將數據庫里sqlite3_get_table()出來的數據以字符的方式給dbResult。*/if (ret != SQLITE_OK) //未查詢到表單數據{perror("sqlite3_get_table_login");return;}if (1 == nrow) //如果chat表中已經有一個數據 同時數據的用戶名和現在準備登錄的用戶名相同 則不允許登錄{Lnode tmp = head->next;Lnode p = (Lnode)malloc(sizeof(Node)); //創建一個節點存儲用戶信息if (p == NULL){printf("FAILURE!\n\n");return;}while (tmp != head){if (!strcmp(tmp->name, Result[3])){printf("您的賬號已登錄!\n\n");SendBuf.result = logged;return;}tmp = tmp->next;}SendBuf.result = log_success;strcpy(p->name, Result[3]); //存儲用戶名字strcpy(SendBuf.username, Result[3]);SendBuf.vip = *(Result[5]) - 48;p->client_addr.sin_family = tmp_addr.sin_family;p->client_addr.sin_port = tmp_addr.sin_port;p->client_addr.sin_addr.s_addr = tmp_addr.sin_addr.s_addr;printf("記錄到 %s 的端口號是 : %d\n", p->name, p->client_addr.sin_port);p->next = head->next;head->next = p;printf("%s 處于登錄狀態!\n\n", Result[3]);}else{SendBuf.result = log_error;printf("您的賬號或密碼錯誤,請重新登錄!\n\n");} }//處理私聊 int deal_private(struct sockaddr_in tmp_addr) {int postion = 0; //創建一個標志位Lnode tmp = head->next;while (tmp != head){if (strcmp(tmp->name, RecvBuf.toname) == 0) //查詢 找到 用戶名和接收名 相同 發送信息過去{postion = 1;strcpy(SendBuf.message, RecvBuf.message);strcpy(SendBuf.fromname, RecvBuf.username);SendBuf.result = private_chat;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));if (ret == -1){perror("sendto_chat");exit(1);}break;}tmp = tmp->next;}if (postion){SendBuf.result = Send_success;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));if (ret == -1){perror("sendto_success");exit(1);}}else{SendBuf.result = Pchat_failure;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));if (ret == -1){perror("sendto_failure");exit(1);}} }//處理群聊 同上 int deal_group(struct sockaddr_in tmp_addr) {int postion = 0;Lnode tmp = head->next;while (tmp != head){if (tmp->client_addr.sin_port != tmp_addr.sin_port){postion = 1;SendBuf.result = group_chat;strcpy(SendBuf.fromname, RecvBuf.username);printf("%s\n", SendBuf.fromname);strcpy(SendBuf.message, RecvBuf.message);ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));if (ret < 0){perror("sendto_group_chat");exit(1);}}tmp = tmp->next;}if (1 == postion){SendBuf.result = Send_success;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));if (ret < 0){perror("sendto_group_chat_success");exit(1);}}else{SendBuf.result = Gchat_failure;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));if (ret < 0){perror("sendto_group_chat_failure");exit(1);}} }//顯示在線人數 int deal_online() {int i = 0;SendBuf.num = 0;Lnode tmp = head->next;while (tmp != head){SendBuf.num++;strcpy(SendBuf.online_name[i], tmp->name);i++;tmp = tmp->next;}SendBuf.result = online; }//處理群發表情 同上 int deal_face(struct sockaddr_in tmp_addr) {int postion = 0;Lnode tmp = head->next;while (tmp != head){if (tmp->client_addr.sin_port != tmp_addr.sin_port){postion = 1;SendBuf.result = face;strcpy(SendBuf.fromname, RecvBuf.username);SendBuf.p_f = RecvBuf.p_f;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));if (ret < 0){perror("sendto_face");exit(1);}}tmp = tmp->next;}if (1 == postion){SendBuf.result = Send_success;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));if (ret < 0){perror("sendto_face_success");exit(1);}}else{SendBuf.result = face_failure;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));if (ret < 0){perror("sendto_face_failure");exit(1);}} }//處理發送常用語 同上 int deal_useful(struct sockaddr_in tmp_addr) {int postion = 0;Lnode tmp = head->next;while (tmp != head){if (strcmp(tmp->name, RecvBuf.toname) == 0){postion = 1;SendBuf.result = send_useful;SendBuf.p_u = RecvBuf.p_u;strcpy(SendBuf.fromname, RecvBuf.username);ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));if (ret == -1){perror("sendto_useful");exit(1);}break;}tmp = tmp->next;}if (postion){SendBuf.result = Send_success;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));if (ret == -1){perror("sendto_success");exit(1);}}else{SendBuf.result = Send_failure;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));if (ret == -1){perror("sendto_failure");exit(1);}} }//處理vip int deal_vip(struct sockaddr_in tmp_addr) {char sql[100] = { 0 };sprintf(sql, "update chat set vip= %d where username = '%s';", RecvBuf.vip, RecvBuf.username);//更新數據庫 信息即可ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);if (ret != SQLITE_OK){perror("sqlite3_exec");return;}SendBuf.vip = 1; //VIP 標志位 置一SendBuf.result = vip_success;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));if (ret == -1){perror("sendto_vip_failure");exit(1);}printf("%s 恭喜您成為了會員 ...\n", SendBuf.username);return 0;}//處理禁言 同上 int deal_shutup(struct sockaddr_in tmp_addr) {Lnode tmp = head->next;int postion = 0;while (tmp != head){if (strcmp(tmp->name, RecvBuf.toname) == 0){postion = 1;SendBuf.result = shutup;strcpy(SendBuf.fromname, RecvBuf.username);ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));if (ret < 0){perror("sendto_shutup");return;}}tmp = tmp->next;}if (postion){SendBuf.result = shutup_success;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));if (ret < 0){perror("sendto_shutup_success");return;}}else{SendBuf.result = shutup_failure;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));if (ret < 0){perror("sendto_shutup_failure");return;}} }//處理踢人 同上 int deal_kick(struct sockaddr_in tmp_addr) {int postion = 0;Lnode tmp = head->next;while (tmp != head){if (strcmp(tmp->name, RecvBuf.toname) == 0){postion = 1;SendBuf.result = kick;strcpy(SendBuf.fromname, RecvBuf.username);ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));if (ret < 0){perror("sendto_kick");return;}Lnode p = tmp->next; //借用指針將該處的人員刪除 將后面的人員連接上來 代替此處人員tmp->next = p->next;free(p);printf("%s logged out...\n", RecvBuf.username);break;}tmp = tmp->next;}if (postion == 1){SendBuf.result = kick_success;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));if (ret < 0){perror("sendto_kick_success");exit(1);}}else{SendBuf.result = kick_failure;ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));if (ret < 0){perror("sendto_shutup_failure");exit(1);}} }//處理下線 int deal_quit() {Lnode tmp = head;//1.如果是頭結點if (tmp->next->next == head){if (strcmp(tmp->next->name, RecvBuf.username) == 0){Lnode p = tmp->next; //借用指針將該處的人員刪除 將后面的人員連接上來 代替此處人員tmp->next = p->next;free(p);printf("%s logged out...\n", RecvBuf.username);return;}tmp = tmp->next;}//2.不是頭結點while (tmp->next != head){if (strcmp(tmp->next->name, RecvBuf.username) == 0){SendBuf.result = quit;Lnode l = tmp->next;tmp->next = l->next;free(l);printf("%s logged out...\n", RecvBuf.username);break;}tmp = tmp->next;}return 0; }int main() {struct sockaddr_in server_addr; //創建服務器 地址struct sockaddr_in client_addr; //創建客戶端 地址int length;int position;char sql[100] = { 0 };head = (Lnode)malloc(sizeof(Node));if (NULL == head){printf("Malloc Failure!\n");return;}head->next = head;sockfd = socket(PF_INET, SOCK_DGRAM, 0); //創建服務平臺if (-1 == sockfd){perror("socket");exit(1);}bzero(&server_addr, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = PORT;server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //地址確定為 127.0.0.1ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); //服務器地址綁定if (ret < 0){perror("bind");exit(1);}ret = sqlite3_open("chat.db", &ppdb); //如果存在 chat數據庫 打開(可能是第二次執行程序的時候if (ret != SQLITE_OK){perror("sqlite3_open");exit(1);}sprintf(sql, "create table if not exists chat (username text primary key, password text,vip integer);");/* 如果不存在chat數據庫 就創建一個chat */ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);if (ret != SQLITE_OK){perror("sqlite3_exec1");exit(1);}while (1){length = sizeof(client_addr);ret = recvfrom(sockfd, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&client_addr, &length); //循環處理 接收信息if (ret < 0){perror("recvfrom");exit(1);}printf("Recv From Client %d\n", client_addr.sin_port); //輸出(地址) 接收自哪個客戶端printf("username is : %s\tpassword is : %s\n", RecvBuf.username, RecvBuf.password);switch (RecvBuf.cmd) //根據接收到的 信息類型 執行相應的函數{case (reg) : //注冊 {register1();ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&client_addr, sizeof(client_addr)); //打包信息if (ret < 0){perror("sendto_server_register");exit(1);}break;}case (log_in) : //登錄{login(client_addr);ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&client_addr, sizeof(client_addr));if (ret < 0){perror("sendto_server_log_in");exit(1);}break;}case (private_chat) : //私聊{deal_private(client_addr);break;}case(group_chat) : //群聊{deal_group(client_addr);break;}case(online) : //查看在線人數{deal_online();ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&client_addr, sizeof(client_addr));if (ret == -1){perror("sendto_online");}break;}case(face) : //群發表情{deal_face(client_addr);break;}case(send_useful) : //發送常用語{deal_useful(client_addr);break;}case(Vip) : //開通會員{deal_vip(client_addr);break;}case(shutup) : //禁言{deal_shutup(client_addr);break;}case(kick) : //踢人{deal_kick(client_addr);break;}case(quit) : //下線{deal_quit();ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&client_addr, sizeof(client_addr));if (ret == -1){perror("sendto_quit");}break;}}}sqlite3_close(ppdb); //最后關閉數據庫return 0; }?
總結
以上是生活随笔為你收集整理的方案二、三SELECT、UDP完成聊天室的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win10安装Navicat 12 fo
- 下一篇: 8-13 刷题 复习 知识点集合