原文:基于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 一下,感谢!

基于LINUX的多功能聊天室的更多相关文章

  1. 基于Linux的TCP网络聊天室

    1.实验项目名称:基于Linux的TCP网络聊天室 2.实验目的:通过TCP完成多用户群聊和私聊功能. 3.实验过程: 通过socket建立用户连接并传送用户输入的信息,分别来写客户端和服务器端,利用 ...

  2. 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。

    基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...

  3. 基于EPOLL模型的局域网聊天室和Echo服务器

    一.EPOLL的优点 在Linux中,select/poll/epoll是I/O多路复用的三种方式,epoll是Linux系统上独有的高效率I/O多路复用方式,区别于select/poll.先说sel ...

  4. 基于 OpenResty 实现一个 WS 聊天室

    基于 OpenResty 实现一个 WS 聊天室 WebSocket WebSocket 协议分析 WebSocket 协议解决了浏览器和服务器之间的全双工通信问题.在WebSocket出现之前,浏览 ...

  5. JAVA基础知识之网络编程——-基于TCP通信的简单聊天室

    下面将基于TCP协议用JAVA写一个非常简单的聊天室程序, 聊天室具有以下功能, 在服务器端,可以接受客户端注册(用户名),可以显示注册成功的账户 在客户端,可以注册一个账号,并用这个账号发送信息 发 ...

  6. 《基于Node.js实现简易聊天室系列之详细设计》

    一个完整的项目基本分为三个部分:前端.后台和数据库.依照软件工程的理论知识,应该依次按照以下几个步骤:需求分析.概要设计.详细设计.编码.测试等.由于缺乏相关知识的储备,导致这个Demo系列的文章层次 ...

  7. 《基于Node.js实现简易聊天室系列之引言》

    简述:这个聊天室是基于Node.js实现的,完成了基本的实时通信功能.在此之前,对node.js和mongodb一无所知,但是通过翻阅博客,自己动手基本达到了预期的效果.技术,不应该是闭门造车,而是学 ...

  8. 通信——基于Xmpp协议实现的聊天室

    前段时间写了个自定义通信协议的聊天室(即用\r\n标记字符串,作为一句话),总感觉自己弄的那个协议实现虽然简单,但是拓展性就太差了,只适合于发送聊天的内容,难以包含更多的信息.基于上述几点,于是就开始 ...

  9. 基于WebSocket实现网页版聊天室

    WebSocket ,HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议,其使用简单,应用场景也广泛,不同开发语言都用种类繁多的实现,仅Java体系中,Tomcat,Jetty,Sp ...

随机推荐

  1. 【LeetCode】【Python解决问题的方法】Best Time to Buy and Sell Stock II

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  2. mysql table is marked as crashed and last (automatic?) repair failed

    1.同事的服务器在mysqldump备份的时候报错了 这个原因是myisam的表数据太多,在某个时刻, 存放数据的这个MyISAM表数据急速长大. 比如一些log表, 当硬盘写满了.这个时候还在继续写 ...

  3. VS2010中使用CL快速 生成DLL的方法

    方案一: 1.命令行中输入cl example.cpp,生成example.obj和example.lib文件.有可能还会提示“没有入口点”的错误.这是因为我们的CPP中是要生成dll文件的,并没有m ...

  4. MongoDB学习笔记-命令

    连接数据库: mongodb://账号:密码@IP/库名 更多方式参考:http://www.runoob.com/mongodb/mongodb-connections.html 命令整理: 名称 ...

  5. mongodb 学习笔记05 --用户管理

    csdn的markdown编辑器真有够烂的,这篇文章又给弄丢了 启用认证 mongod 启动默认没有开启权限,你须要指定 –auth 启动.或者在配置文件里设置security.authorizati ...

  6. 先学习Oracle 11g的Automatic Diagnostic Repository新功能

    Oracle 11g之前.当数据库出现故障,通常情况下,第一次需要看alert刊物.什么,看看哪些记录错误,您可以给我们的提示.alert文件名 是alert_<ORACLE_SID>.l ...

  7. NodeJS常用模块介绍

    收集了NodeJS开发中常用的一些模块. MVC框架 - Express Express 是轻量灵活的Nodejs Web应用框架,它可以快速地搭建网站.Express框架建立在Nodejs内置的Ht ...

  8. Web API Test Client 1.2.0

    使用方法 1 安装 matthewcv.WebApiTestClient 到你的Web API 项目 PM> Install-Package matthewcv.WebApiTestClient ...

  9. 有人实践过 Phabricator 以及 Arcanist 作为 code review 的工具么?(转)

    作者:覃超链接:http://www.zhihu.com/question/19977889/answer/13539702来源:知乎 平时就经常实践. 整个公司的code review就是使用这个. ...

  10. OpenStack路: OpenStack建筑设计指南 - 概要(摘录和翻译)

    OpenStack它是在云技术领先的黄金工艺,作为一个组织,使各类企业,具有较大的灵活性和速度被发现,向市场推出自助服务云计算和基础架构即服务(IaaS)积.然,为了能够真正享受到这些好处,云计算必须 ...