基於LINUX的多功能聊天室

samuel.wang的部落格發表於2015-02-03

基於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 一下,感謝!

相關文章