基於LINUX的多功能聊天室
基於LINUX的多功能聊天室
其實這個專案在我電腦已經躺了多時,最初寫完專案規劃後,我就認認真真地去實現了它,後來拿著這個專案區參加了面試,同樣面試官也拿這個專案來問我,當然我是做過一遍了,而且為了面試,我將什麼strcpy,strlen等最常用的函式都自己實現了一遍,說著,我感覺自己有點挺用功的樣子呢!
後來,工作也定下來了,等三方,然後繼續幫助我的導師做專案,經過老師的威逼利誘下,我屈服了,又把智慧家居系統作為專案,同時也是我的畢業設計,而且功能還要十分完善的說,好吧,別人的簡單,但我也無所謂,因為看到技術二字,我必然是兩眼放光的那種,特別喜歡那種突然我想到咋麼解決了,然後就幫功能實現了那種感覺,像是上癮了一樣,(果然是當程式設計師的料)
專案回想與思考
嗯,我的專案基本上的功能和專案規劃裡面基本上是一致的,而且功能也是非常完善了,基本上能夠實現了我所需要的功能,但是我也要思考我在整個專案過程中的得失,我在專案的思考中,其實把他定義錯了,因為是一個非常小的聊天室的功能,其實我無需使用資料庫來作為登陸與否的查詢方法,其實完全可以使用連結串列的方法來做客戶端的登入,這樣才是不會造成資源的浪費
專案程式碼
我將分兩篇來講述我的專案,第一篇(也就是這篇為伺服器篇);第二篇為客戶端篇,當然裡面的程式碼基本上全是我個人所寫,也參考過一部分別的程式碼!
Makefile
基本上我也忘得差不多了,對這個專案,我感覺淡淡的陌生感,但是重拾還是非常容易的嘛!看一個專案咋麼形成,Makefile不容錯過!
main = insert.o chatroom.o sql.o passwd.o string.o cmd.o socket.o chatroom:$(main) @gcc $(main) -o chatroom -lsqlite3 passwd.o: passwd.c @gcc passwd.c -c insert.o: insert.c @gcc insert.c -c sql.o:sql.c @gcc sql.c -c string.o:string.c @gcc string.c -c cmd.o:cmd.c @gcc cmd.c -c socket.o:socket.c @gcc socket.c -c .PHONY: clean cleanall clean: @rm *.o cleanall: @rm *.o chatroom
通過這個我們不難發現這個專案調動了什麼,和哪些檔案!
passwd.c檔案分析
先不說我們把程式碼貼出來先!
#include"data.h" void reg_db(sqlite3 *db,char **errmsg,char *name,char *passwd)//註冊插入 { char sql[1024]; int rc; sprintf(sql,"insert into user(name,passwd)values('%s','%s')",name,passwd); rc = sqlite3_exec(db,sql,NULL,NULL,errmsg); is_sqlite(rc); } void log_db(sqlite3 *db,char **errmsg,char *name,int sockfd)//登陸插入 { char sql[1024]; int rc; sprintf(sql,"insert into online(name,socket,flag)values('%s',%d,1)",name,sockfd); rc = sqlite3_exec(db,sql,NULL,NULL,errmsg); is_sqlite(rc); } void delete_online_db(sqlite3 *db,char **errmsg,int sockfd)//刪除登陸 { char sql[1024]; int rc; sprintf(sql,"delete from online where socket = %d",sockfd); rc = sqlite3_exec(db,sql,NULL,NULL,errmsg); is_sqlite(rc); } int read_user(sqlite3 *db,char **errmsg,char *user)//詢問有無此使用者 { int rc; int i; sqlite3_stmt *stmt = NULL; rc = sqlite3_prepare(db,"select * from user",-1,&stmt,0); is_sqlite_ok(rc); rc = sqlite3_step(stmt); int userflag = 1; while(rc == SQLITE_ROW) { userflag = my_strcmp(user,sqlite3_column_text(stmt,1)); if(userflag == 0 ) { return USERIN; } rc = sqlite3_step(stmt); } return USEROUT; } int read_id(sqlite3 *db,char **errmsg,char *user)//詢問有無此使用者 { int rc; int i; sqlite3_stmt *stmt = NULL; rc = sqlite3_prepare(db,"select * from user",-1,&stmt,0); is_sqlite_ok(rc); rc = sqlite3_step(stmt); int userflag = 1; while(rc == SQLITE_ROW) { userflag = my_strcmp(user,sqlite3_column_text(stmt,1)); if(userflag == 0 ) { return atoi(sqlite3_column_text(stmt,0)); } rc = sqlite3_step(stmt); } return USEROUT; } void read_id_name(sqlite3 *db,char **errmsg,vpChat temp)//詢問有無此使用者 { int rc; int i; sqlite3_stmt *stmt = NULL; rc = sqlite3_prepare(db,"select * from user",-1,&stmt,0); is_sqlite_ok(rc); rc = sqlite3_step(stmt); int userflag = 1; while(rc == SQLITE_ROW) { userflag = my_atoi(sqlite3_column_text(stmt,0)); if(userflag == temp->flag ) { my_strcpy(temp->name,sqlite3_column_text(stmt,1)); } rc = sqlite3_step(stmt); } } int read_pass(sqlite3 *db,char **errmsg,char *user,char *passwd)//用於使用者驗證 { int rc; int i; sqlite3_stmt *stmt = NULL; rc = sqlite3_prepare(db,"select * from user",-1,&stmt,0); is_sqlite_ok(rc); rc = sqlite3_step(stmt); int userflag = 1; int passwdflag = 1; while(rc == SQLITE_ROW) { userflag = my_strcmp(user,sqlite3_column_text(stmt,1)); passwdflag = my_strcmp(passwd,sqlite3_column_text(stmt,2)); if(userflag == 0 && passwdflag == 0) { return PASSWDOK; } rc = sqlite3_step(stmt); } return PASSWDNO; } int read_online_ok(sqlite3 *db,char **errmsg,char *user)//用於驗證線上使用者 { int rc; int i; sqlite3_stmt *stmt = NULL; rc = sqlite3_prepare(db,"select * from online",-1,&stmt,0); is_sqlite_ok(rc); rc = sqlite3_step(stmt); int userflag = 1; while(rc == SQLITE_ROW) { userflag = my_strcmp(user,sqlite3_column_text(stmt,1)); if(userflag == 0) { return ONLINEIN; } rc = sqlite3_step(stmt); } return ONLINEOUT; }
哦,這個原來是用來登入註冊用的呀!
那麼我在來看看passwd.h呢!
void reg_db(sqlite3 *db,char **errmsg,char *name,char *passwd); int read_user(sqlite3 *db,char **errmsg,char *user); int read_pass(sqlite3 *db,char **errmsg,char *user,char *passwd);//用於使用者驗證 int read_online_ok(sqlite3 *db,char **errmsg,char *user); void delete_online_db(sqlite3 *db,char **errmsg,int sockfd); int read_id(sqlite3 *db,char **errmsg,char *user);//詢問有無此使用者 void read_id_name(sqlite3 *db,char **errmsg,vpChat temp);//詢問有無此使用者
原來是對函式進行申明啊!
但是#include”data.h” 這個檔案又是幹什麼的呢?
那麼data.h按照猜測肯定是各類標頭檔案的引用嘍!
#ifndef __DATA__ #define __DATA__ #define MAXSIZE 100 #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<netdb.h> #include<netinet/in.h> #include<sys/socket.h> #include<arpa/inet.h> #include<ctype.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<sqlite3.h> #include<unistd.h> #include<signal.h> #include<time.h> #include<termios.h> #include<assert.h> #define portnumber 8000 //巨集定義埠號 struct chat { char name[20];//使用者名稱 char passwd[20];//密碼 int cmd;//命令 int revert;//返回值 char toname[20];//目標客戶名 char msg[800];//傳送資訊 int flag; int sockfd; char time[40]; char filename[40]; }; typedef struct chat stChat; typedef struct chat* vpChat; enum cmd { LOGID = 0, REG = 1, LOG = 2, USERHELP = 3, USEREXIT = 4, CHAT = 3, ALL = 4, SMILE = 5, WELCOME = 6, EXIT = 7, HELP = 8, PASSWD = 9, BOOT = 10, STEP = 11, BAN = 12, SET = 13, SEE = 14, DATA = 15, SEND = 16, CHANGE = 17 }; enum revert { USERIN = 1, USEROUT = -1, PASSWDOK = 2, PASSWDNO = -2, ONLINEIN = 3, ONLINEOUT = -3, REGNO = -4, REGOK = 4, MYFLAGOK = -5, MYFLAGNO = -6, TOFLAGOK = -7, TOFLAGNO = -8, CHATOK = 1, ALLOK = 6, SMILEOK = 6, WELCOMEOK = 6, SEEOK = 7, BOOTOK = 1, DATAOK = 8, SENDOK = 2 }; #endif
果然與我們的猜想差不多啊!
insert.c檔案分析
#include"data.h" void insert_server()//伺服器執行提示 { system("reset"); printf("\t\t\t\t\t**********************************\n"); printf("\t\t\t\t\t* 歡迎使用 *\n"); printf("\t\t\t\t\t* 聊天室伺服器 *\n"); printf("\t\t\t\t\t**********************************\n"); }
sogo,這檔案原來是給我們看伺服器啟動時的介面的呀!
sql.c檔案分析
看這名字,肯定跟資料庫有關!
#include"data.h" void is_malloc_ok(vpChat *list) { *list = (vpChat)malloc(sizeof(stChat)); if(*list == NULL) { exit(1); } } void is_sqlite(int rc) //測試資料庫 { if(rc == SQLITE_OK) { printf("sqlite %d succse \n",__LINE__); } else { printf("資料庫發生錯誤,請使用SQLITE3 看資料庫!\n"); printf("sqlite %d error\n",__LINE__); exit(1); } } void is_sqlite_ok(int rc) { if(rc == SQLITE_OK) { printf("sqlite %d succse \n",__LINE__); } else { printf("sqlite %d error\n",__LINE__); } } void open_db(sqlite3 **db)//開啟資料庫 { int rc; rc = sqlite3_open("server.db",db); is_sqlite(rc); } void creat_user_db(sqlite3 *db,char **errmsg)//建立user資料表 { int rc; rc = sqlite3_exec(db,"create table user(id integer primary key autoincrement,name text,passwd text)",NULL,NULL,errmsg); is_sqlite_ok(rc); } void creat_data_db(sqlite3 *db,char **errmsg)//建立data資料表 { int rc; rc = sqlite3_exec(db,"create table data(id integer primary key autoincrement,time text,name text,toname text,msg text)",NULL,NULL,errmsg); is_sqlite_ok(rc); } void creat_online_db(sqlite3 *db,char **errmsg)//建立online資料表 { int rc; rc = sqlite3_exec(db,"create table online(id integer primary key autoincrement,name text,socket integer,flag integer)",NULL,NULL,errmsg); is_sqlite_ok(rc); } void creat_server_db(sqlite3 *db,char **errmsg)//建立server資料表 { int rc; rc = sqlite3_exec(db,"create table server(id integer primary key autoincrement,time text)",NULL,NULL,errmsg); is_sqlite_ok(rc); } void insert_server_db(sqlite3 *db,char *time,char **errmsg)//向server資料庫插入資料 { int rc; char sql[1024]; sprintf(sql,"insert into server(time) values('%s')",time); rc = sqlite3_exec(db,sql,NULL,NULL,errmsg); is_sqlite(rc); printf("資料庫已經錄入完畢\n"); } void insert_data_db(sqlite3 *db,char **errmsg,char *time,vpChat temp)//插入聊天記錄 { int rc; char sql[1024]; sprintf(sql,"insert into data(time,name,toname,msg) values('%s','%s','%s','%s')",time,temp->name,temp->toname,temp->msg); rc = sqlite3_exec(db,sql,NULL,NULL,errmsg); is_sqlite(rc); printf("聊天記錄已經錄入完畢\n"); } void delete_clean_db(sqlite3 *db,char *tablename,char **errmsg)//清空資料庫 { char sql[1024]; int rc; sprintf(sql,"delete from %s where name !='root'",tablename); rc = sqlite3_exec(db,"delete from student",NULL,NULL,errmsg); is_sqlite(rc); } void read_db_ok(sqlite3 *db,char *errmsg,char*tablename)//用於檢測資料庫 { int rc; int i; char sql[1024]; sqlite3_stmt *stmt = NULL; sprintf(sql,"select * from %s ",tablename); rc = sqlite3_prepare(db,sql,-1,&stmt,0); is_sqlite_ok(rc); rc = sqlite3_step(stmt); int ncolumn; ncolumn = sqlite3_column_count(stmt); while(rc == SQLITE_ROW) { for(i = 0; i < ncolumn; i++) { printf("%s|",sqlite3_column_text(stmt,i)); } printf("\n"); rc = sqlite3_step(stmt); } } int read_online_fd(sqlite3 *db,char **errmsg,char *user)//獲取FD { int rc; int i; char fd[100]; sqlite3_stmt *stmt = NULL; rc = sqlite3_prepare(db,"select * from online",-1,&stmt,0); is_sqlite_ok(rc); rc = sqlite3_step(stmt); int userflag = 1; while(rc == SQLITE_ROW) { userflag = my_strcmp(user,sqlite3_column_text(stmt,1)); if(userflag == 0) { my_strcpy(fd,sqlite3_column_text(stmt,2)); return my_atoi(fd); } rc = sqlite3_step(stmt); } return ONLINEOUT; } int read_online_flag(sqlite3 *db,char **errmsg,char *user)//用於驗證是否禁言 { int rc; int i; char flag[10]; sqlite3_stmt *stmt = NULL; rc = sqlite3_prepare(db,"select * from online",-1,&stmt,0); is_sqlite_ok(rc); rc = sqlite3_step(stmt); int userflag = 1; while(rc == SQLITE_ROW) { userflag = my_strcmp(user,sqlite3_column_text(stmt,1)); if(userflag == 0) { my_strcpy(flag,sqlite3_column_text(stmt,3)); return my_atoi(flag); } rc = sqlite3_step(stmt); } return -10; } void write_online_all(sqlite3 *db,char **errmsg,vpChat temp)//向線上使用者傳送資訊 { int rc; int flag; char fd[100]; sqlite3_stmt *stmt = NULL; rc = sqlite3_prepare(db,"select * from online",-1,&stmt,0); is_sqlite_ok(rc); rc = sqlite3_step(stmt); int userflag = 1; while(rc == SQLITE_ROW) { flag = my_strcmp(temp->name,sqlite3_column_text(stmt,1)); my_strcpy(fd,sqlite3_column_text(stmt,2)); if(flag != 0) { write( my_atoi(fd),temp,sizeof(stChat)); } sleep(1); rc = sqlite3_step(stmt); } } int update_passwd(sqlite3 *db,char **errmsg,char *name,char *passwd)//修改密碼 { int rc; char sql[1024]; sprintf(sql,"update user set passwd = '%s'where name = '%s'",passwd,name); rc = sqlite3_exec(db,sql,NULL,NULL,errmsg); if(rc == SQLITE_OK) { return 1; } else { return 0; } } int update_user(sqlite3 *db,char **errmsg,char *name,char *toname)//修改密碼 { int rc; char sql[1024]; sprintf(sql,"update user set name = '%s'where name = '%s'",toname,name); rc = sqlite3_exec(db,sql,NULL,NULL,errmsg); if(rc == SQLITE_OK) { return 1; } else { return 0; } } int update_db_data(sqlite3 *db,char **errmsg,char *name,char *toname)//修改密碼 { int rc1; int rc2; char sql[1024]; sprintf(sql,"update data set name = '%s'where name = '%s'",toname,name); rc1 = sqlite3_exec(db,sql,NULL,NULL,errmsg); memset(sql,0,1024); sprintf(sql,"update data set toname = '%s'where toname = '%s'",toname,name); rc2 = sqlite3_exec(db,sql,NULL,NULL,errmsg); if(rc1 == SQLITE_OK && rc2 == SQLITE_OK) { return 1; } else { return 0; } } int update_flag(sqlite3 *db,char **errmsg,char *name,int flag)//禁言解禁操作 { int rc; char sql[1024]; sprintf(sql,"update online set flag = %d where name = '%s'",flag,name); rc = sqlite3_exec(db,sql,NULL,NULL,errmsg); if(rc == SQLITE_OK) { return 1; } else { return 0; } } int delete_user(sqlite3 *db,char **errmsg,char *name)//登出使用者 { int rc; char sql[1024]; sprintf(sql,"delete from user where name = '%s'",name); rc = sqlite3_exec(db,sql,NULL,NULL,errmsg); if(rc == SQLITE_OK) { return 1; } else { return 0; } } void read_online_all(sqlite3 *db,char **errmsg,vpChat temp)//向線上使用者傳送資訊 { int rc; sqlite3_stmt *stmt = NULL; rc = sqlite3_prepare(db,"select * from online",-1,&stmt,0); is_sqlite_ok(rc); rc = sqlite3_step(stmt); int userflag = 1; while(rc == SQLITE_ROW) { my_strcpy(temp->msg,sqlite3_column_text(stmt,1)); mywrite(temp); sleep(1); rc = sqlite3_step(stmt); } } void read_data(sqlite3 *db,char **errmsg,vpChat temp)//向線上使用者傳送資訊 { int rc; char name[80]; char toname[80]; sqlite3_stmt *stmt = NULL; rc = sqlite3_prepare(db,"select * from data",-1,&stmt,0); is_sqlite_ok(rc); rc = sqlite3_step(stmt); int userflag = 1; while(rc == SQLITE_ROW) { my_strcpy(name,sqlite3_column_text(stmt,2)); my_strcpy(toname,sqlite3_column_text(stmt,3)); if( my_strcmp(temp->name,name) == 0) { strcat(temp->msg,"你"); strcat(temp->msg,"給"); strcat(temp->msg,toname); strcat(temp->msg,"發了"); strcat(temp->msg,sqlite3_column_text(stmt,4)); strcat(temp->msg,"\n"); my_strcpy(temp->time,sqlite3_column_text(stmt,1)); mywrite(temp); memset(temp->msg,0,sizeof(temp->msg)); sleep(1); } if(my_strcmp(temp->name,toname) == 0) { strcat(temp->msg,toname); strcat(temp->msg,"給你發了"); strcat(temp->msg,sqlite3_column_text(stmt,4)); strcat(temp->msg,"\n"); my_strcpy(temp->time,sqlite3_column_text(stmt,1)); mywrite(temp); memset(temp->msg,0,sizeof(temp->msg)); sleep(1); } rc = sqlite3_step(stmt); } }
這個是資料庫的各類操作呢!
那麼它的標頭檔案估計也是函式申明
void is_sqlite(int rc); //測試資料庫 void is_malloc_ok(vpChat *list); void is_sqlite_ok(int rc); void open_db(sqlite3 **db);//開啟資料庫 void creat_user_db(sqlite3 *db,char **errmsg);//建立user資料表 void creat_data_db(sqlite3 *db,char **errmsg);//建立data資料表 void creat_online_db(sqlite3 *db,char **errmsg);//建立online資料表 void creat_server_db(sqlite3 *db,char **errmsg);//建立server資料表 void insert_server_db(sqlite3 *db,char *time,char **errmsg); void read_db_ok(sqlite3 *db,char *errmsg,char*tablename); void delete_clean_db(sqlite3 *db,char *tablename,char **errmsg); int read_online_fd(sqlite3 *db,char **errmsg,char *user); int read_online_flag(sqlite3 *db,char **errmsg,char *user); void write_online_all(sqlite3 *db,char **errmsg,vpChat temp); int update_passwd(sqlite3 *db,char **errmsg,char *name,char *passwd); void insert_data_db(sqlite3 *db,char **errmsg,char *time,vpChat temp); int update_flag(sqlite3 *db,char **errmsg,char *name,int flag); int delete_user(sqlite3 *db,char **errmsg,char *name); void read_online_all(sqlite3 *db,char **errmsg,vpChat temp); void read_data(sqlite3 *db,char **errmsg,vpChat temp); int update_user(sqlite3 *db,char **errmsg,char *name,char *toname); int update_db_data(sqlite3 *db,char **errmsg,char *name,char *toname);
乾貨來了,string.c
很明顯是我為了面試準備所寫的函式!經測是有效的!
#include"data.h" int my_strlen(const char *str) { int len; while(*str++ != '\0') { len++; } return len; } int my_strcmp(const char *str1,const char *str2) { if(str1 != NULL && str2 != NULL) { } else { return -2; } int i; while((*str1)!='\0' && (*str2) != '\0') { if((*str1) == (*str2)) { str1++; str2++; } else { break; } } if((*str1) == '\0' && (*str2) == '\0') { return 0; } else { return (*str1) > (*str2)? 1 : -1; } } char *my_strcpy( char *dest,const char *src) { if(dest != NULL && src != NULL) { } else { return NULL; } char *adress = dest; while(((*dest++) = (*src++)) != '\0'); return adress; } int my_atoi(const char *str) { if(str != NULL) { } else { return -1; } const char* p = str; int minus = 0; long result = 0; if(*p == '-') { minus = 1; p++; } else if(*p == '+') { p++; } while(*p != '\0') { if(*p < '0' || *p >'9') { return -1; } result = result*10 + ((*p) - '0'); p++; } minus = 1 ? -result:result; return result; } char * my_strcat(char *dest,const char *src) { if(dest != NULL && src != NULL) { } else { return NULL; } char *address = dest; while((*dest) != '\0') { dest++; } while(((*dest++) = (*src++)) != '\0'); return address; }
CMD.c 命令解析
#include"data.h" int cmd_user(sqlite3 *db,char **errmsg,vpChat temp,int sockfd)//用語判別使用者資訊 { int flag; int sayflag; printf("cmd = %d\n",temp->cmd); switch(temp->cmd ) { case REG: { flag = read_user(db,errmsg,temp->name); if(flag == USERIN) { return REGNO;//註冊重名 } else { reg_db(db,errmsg,temp->name,temp->passwd); temp->flag = read_id(db,errmsg,temp->name); return REGOK; } break; } case LOG: { int flagpasswd; flag = read_online_ok(db,errmsg,temp->name); if(flag == ONLINEIN) { return ONLINEIN; } else { flagpasswd = read_pass(db,errmsg,temp->name,temp->passwd); if(flagpasswd == PASSWDOK) { log_db(db,errmsg,temp->name,sockfd); return PASSWDOK; } else { return PASSWDNO; } } break; } case LOGID: { int flagpasswd; read_id_name(db,errmsg,temp);//詢問有無此使用者 flag = read_online_ok(db,errmsg,temp->name); if(flag == ONLINEIN) { return ONLINEIN; } else { flagpasswd = read_pass(db,errmsg,temp->name,temp->passwd); if(flagpasswd == PASSWDOK) { log_db(db,errmsg,temp->name,sockfd); return PASSWDOK; } else { return PASSWDNO; } } break; } case CHAT: { int tempfd; tempfd = read_online_fd(db,errmsg,temp->toname); if(tempfd == ONLINEOUT) { return ONLINEOUT; } else { sayflag = read_online_flag(db,errmsg,temp->name); if(sayflag == 0) { return MYFLAGNO; } else { temp->flag = flag; temp->sockfd = tempfd; insert_data_db(db,errmsg,temp->time,temp); return CHATOK; } } break; } case ALL: { sayflag = read_online_flag(db,errmsg,temp->name); if(sayflag == 0) { return MYFLAGNO; } else { insert_data_db(db,errmsg,temp->time,temp); return ALLOK; } break; } case SMILE: { sayflag = read_online_flag(db,errmsg,temp->name); if(sayflag == 0) { return MYFLAGNO; } else { insert_data_db(db,errmsg,temp->time,temp); return SMILEOK; } break; } case WELCOME: { sayflag = read_online_flag(db,errmsg,temp->name); if(sayflag == 0) { return MYFLAGNO; } else { insert_data_db(db,errmsg,temp->time,temp); return WELCOMEOK; } break; } case PASSWD: { flag = update_passwd(db,errmsg,temp->name,temp->passwd); return flag; break; } case BOOT: { int tempfd; tempfd = read_online_fd(db,errmsg,temp->toname); if(tempfd == ONLINEOUT) { return ONLINEOUT; } else { temp->sockfd = tempfd; return BOOTOK; } break; } case STEP: { int tempfd; tempfd = read_online_fd(db,errmsg,temp->toname); if(tempfd == ONLINEOUT) { return ONLINEOUT; } else { flag = update_flag(db,errmsg,temp->toname,0); if(flag == 1) { temp->sockfd = tempfd; } return flag; } break; } case BAN: { int tempfd; tempfd = read_online_fd(db,errmsg,temp->toname); if(tempfd == ONLINEOUT) { return ONLINEOUT; } else { sayflag = read_online_flag(db,errmsg,temp->toname); if(sayflag == 1) { return TOFLAGOK; } else { flag = update_flag(db,errmsg,temp->toname,1); if(flag == 1) { temp->sockfd = tempfd; } return flag; } } break; } case SET: { int tempfd; tempfd = read_online_fd(db,errmsg,temp->toname); if(tempfd == ONLINEOUT) { flag = delete_user(db,errmsg,temp->toname); return flag; } else { return ONLINEIN; } break; } case SEE: { return SEEOK; break; } case DATA: { return DATAOK; break; } case SEND: { int tempfd; tempfd = read_online_fd(db,errmsg,temp->toname); if(tempfd == ONLINEOUT) { return ONLINEOUT; } else { temp->sockfd = tempfd; return SENDOK; } break; } case CHANGE: { flag = read_user(db,errmsg,temp->toname); if(flag == USERIN) { return REGNO;//註冊重名 } else { flag = update_user(db,errmsg,temp->name,temp->toname);//¿¿¿¿ if(flag == 1) { sayflag = update_db_data(db,errmsg,temp->name,temp->toname);//修改密碼 return sayflag; } else { return 0; } } break; } } }
那麼它的標頭檔案是估計也是用於申明函式的!
int cmd_user(sqlite3 *db,char **errmsg,vpChat temp,int sockfd);
socket.c檔案分析
#include"data.h" void mybzero(struct sockaddr_in *sin)//對server_addr_in 結構進行賦值 { bzero(sin,sizeof(struct sockaddr_in)); /* 先清零 */ sin->sin_family=AF_INET; // sin->sin_addr.s_addr=htonl(INADDR_ANY); //表示接受任何ip地址 將ip地址轉換成網路位元組序 sin->sin_port=htons(portnumber); //將埠號轉換成網路位元組序 } int mysocket()//呼叫socket函式建立一個TCP協議套介面 { int lfd; if((lfd = socket(AF_INET,SOCK_STREAM,0)) == -1) // AF_INET:IPV4;SOCK_STREAM:TCP { fprintf(stderr,"Socket error:%s\n\a",strerror(errno)); exit(1); } return lfd; } void mybind(int lfd,struct sockaddr_in *sin) // 呼叫bind函式 將serer_addr結構繫結到sockfd上 { if(bind(lfd,(struct sockaddr *)(sin),sizeof(struct sockaddr))==-1) { fprintf(stderr,"Bind error:%s\n\a",strerror(errno)); exit(1); } } void mylisten(int lfd)// 開始監聽埠 等待客戶的請求 { if(listen(lfd,20)==-1) { fprintf(stderr,"Listen error:%s\n\a",strerror(errno)); exit(1); } } int myaccept(int lfd,struct sockaddr_in *cin,socklen_t * addr_len)// 接受客戶端的請求 { int cfd; if((cfd=accept(lfd,(struct sockaddr *)cin,addr_len))==-1) { fprintf(stderr,"Accept error:%s\n\a",strerror(errno)); exit(1); } return cfd; } void mywrite(vpChat temp) { int num; if((num = write(temp->sockfd,temp,sizeof(stChat))) == -1) { printf("send error!\n"); } }
伺服器主程式
朱程式裡面主要是開啟資料庫,初始化資料庫,及用於顯示資料庫的命令,下面為程式碼部分
#include"data.h" #include"package.h" void display(stChat temp)//用於顯示傳送命令 { printf("name = %s\n",temp.name); printf("passwd = %s\n",temp.passwd); printf("cmd = %d\n",temp.cmd); printf("revert = %d\n",temp.revert); printf("toname = %s\n",temp.toname); printf("msg = %s\n",temp.msg); printf("flag = %d\n",temp.flag); printf("sockfd = %d\n",temp.sockfd); printf("time = %s\n",temp.time); printf("filename = %s\n",temp.filename); } int main() { time_t timep; time(&timep); char *timedata = ctime(&timep); sqlite3 *db = NULL; char *errmsg; open_db(&db);//開啟資料庫 creat_user_db(db,&errmsg); creat_data_db(db,&errmsg); creat_online_db(db,&errmsg); creat_server_db(db,&errmsg); insert_server_db(db,timedata,&errmsg);//向server資料庫插入資料 insert_server(); int lfd; int cfd; int sfd; int rdy; stChat temp; struct sockaddr_in sin; struct sockaddr_in cin; int client[FD_SETSIZE]; /* 客戶端連線的套接字描述符陣列 */ int maxi; int maxfd; /* 最大連線數 */ fd_set rset; fd_set allset; socklen_t addr_len; /* 地址結構長度 */ int i; int n; int len; int opt = 1; /* 套接字選項 */ char addr_p[20]; mybzero(&sin); lfd = mysocket(); /*設定套接字選項 使用預設選項*/ setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); mybind(lfd,&sin); // 呼叫bind函式 將serer_addr結構繫結到sockfd上 mylisten(lfd);// 開始監聽埠 等待客戶的請求 printf("\t\t\t伺服器開始等待客戶端連結\n"); maxfd = lfd; /*對最大檔案描述符進行初始化*/ maxi = -1; /*初始化客戶端連線描述符集合*/ for(i = 0;i < FD_SETSIZE;i++) { client[i] = -1; } FD_ZERO(&allset); /* 清空檔案描述符集合 */ FD_SET(lfd,&allset); /* 將監聽字設定在集合內 */ /* 開始服務程式的死迴圈 */ while(1) { rset = allset; /*得到當前可以讀的檔案描述符數*/ rdy = select(maxfd + 1, &rset, NULL, NULL, NULL); if(FD_ISSET(lfd, &rset)) { addr_len = sizeof(sin); cfd = myaccept(lfd,&cin,&addr_len);// 接受客戶端的請求 /*查詢一個空閒位置*/ for(i = 0; i<FD_SETSIZE; i++) { //printf("%d\t",client[i]); if(client[i] <= 0) { client[i] = cfd; /* 將處理該客戶端的連線套接字設定到該位置 */ break; } } /* 太多的客戶端連線 伺服器拒絕俄請求 跳出迴圈 */ if(i == FD_SETSIZE) { printf("too many clients"); exit(1); } FD_SET(cfd, &allset); /* 設定連線集合 */ if(cfd > maxfd) /* 新的連線描述符 */ { maxfd = cfd; } if(i > maxi) { maxi = i; } if(--rdy <= 0) /* 減少一個連線描述符 */ { continue; } } /* 對每一個連線描述符做處理 */ for(i = 0;i< FD_SETSIZE;i++) { if((sfd = client[i]) < 0) { continue; } if(FD_ISSET(sfd, &rset)) { printf("客戶端sfd = %d已經成功連結\n",sfd); n = read(sfd,&temp,sizeof(stChat)); if(n == 0) { printf("客戶端sfd = %d已經離開本伺服器. \n",sfd); delete_online_db(db,&errmsg,sfd); fflush(stdout); /* 重新整理 輸出終端 */ close(sfd); FD_CLR(sfd, &allset); /*清空連線描述符陣列*/ client[i] = -1; } else { temp.sockfd = sfd; /* 將客戶端地址轉換成字串 */ inet_ntop(AF_INET, &cin.sin_addr, addr_p, sizeof(addr_p)); addr_p[strlen(addr_p)] = '\0'; /*列印客戶端地址 和 埠號*/ printf("客戶端的Ip是%s, 埠是 %d\n",addr_p,ntohs(cin.sin_port)); int revert ; revert = cmd_user(db,&errmsg,&temp,sfd); temp.revert = revert; printf("開始向客戶端傳送命令!\n"); // printf("以下為命令結構體!\n"); // display(temp); if(revert < 5) { mywrite(&temp); } else if(revert == DATAOK) { read_data(db,&errmsg,&temp);//向線上使用者傳送資訊 } else if(revert == SEEOK) { read_online_all(db,&errmsg,&temp);//向線上使用者傳送資訊 } else if(revert == ALLOK || revert == SMILEOK || revert == WELCOMEOK) { write_online_all(db,&errmsg,&temp); } printf("傳送完畢!\n"); memset(&temp,0,sizeof(stChat));//清空傳送資料結構體 /* 諧函式出錯 */ if(n == 1) { exit(1); } } /*如果沒有可以讀的套接字 退出迴圈*/ if(--rdy <= 0) { break; } } } } close(lfd); /* 關閉連結套接字 */ return 0; }
專案地址
其實它就在我的github裡面。你可憐點選連結進入,當然希望您在看的過程中能夠followe me 一下,感謝!
相關文章
- 基於golang的聊天室Golang
- 基於netty的聊天室Netty
- 基於webapi的websocket聊天室(四)WebAPI
- 基於 golang + vue + websocket 開發的聊天室GolangVueWeb
- C++ 實現基於TCP的聊天室C++TCP
- 基於webapi的websocket聊天室(番外一)WebAPI
- 基於webapi的websocket聊天室(番外二)WebAPI
- 一個基於 Ubuntu16.04 的多功能映象Ubuntu
- 多功能聊天室-專案規劃實現圖
- 基於 flask 結合 Redis 的簡單聊天室FlaskRedis
- 15.基於UDP協議的聊天室程式UDP協議
- 聊天室應用開發實踐(二):實現基於 Web 的聊天室Web
- 基於websocket與nodejs-websocket的簡單聊天室WebNodeJS
- Android基於XMPP Smack openfire 開發的聊天室(一)【會議服務、聊天室列表、加入】AndroidMac
- 基於express和socket.io的超簡易版聊天室Express
- Python基於Socket實現簡易多人聊天室Python
- Java進階:基於TCP通訊的網路實時聊天室JavaTCP
- Android平臺下基於XMPP的IM研究(二 MultiUserChat 聊天室)Android
- 一款開源免費的多功能聊天室:Riot.im安裝教程
- 基於SpringBoot+STOMP協議實現的web聊天室Spring Boot協議Web
- 基於 Flutter+Dart 聊天例項 | Flutter 仿微信介面聊天室FlutterDart
- Android基於XMPP Smack openfire 開發的聊天室(二) 【聊天資訊、成員】AndroidMac
- 基於 Taro+react 多端仿微信聊天室|taro 聊天例項分享React
- Android基於XMPP Smack openfire 開發的聊天室(三) 【新舊記錄、踢人】AndroidMac
- Android基於XMPP Smack openfire 開發的聊天室(五) 【邀請、被邀請】AndroidMac
- 基於Linux的mysql主從配置LinuxMySql
- 基於 Linux 的 Flutter 方法通道 ChannelsLinuxFlutter
- linux(基於ubuntu)的基本知識LinuxUbuntu
- 配置基於LINUX的NFS掛載LinuxNFS
- JAVA SE 實戰篇 C6 基於CSFramework的聊天室 (上) 伺服器APPJavaFramework伺服器APP
- 課設 - 基於微控制器的多功能密碼鎖設計(電路+流程+論文)密碼
- Socket.IO打造基礎聊天室
- 基於Thinkphp5.1的內容管理系統(自帶聊天室功能)NoneCms V1.3.0PHPNone
- Android基於XMPP Smack openfire 開發的聊天室(四) 【建立房間、表單;報文】AndroidMac
- Android基於XMPP Smack openfire 開發的聊天室(七) 【成員狀態、自身狀態】AndroidMac
- 多功能RNA分析,百度團隊基於Transformer的RNA語言模型登Nature子刊ORM模型
- 基於Linux的智慧家居的設計(5)Linux
- 基於Linux的docker mysql主從搭建LinuxDockerMySql