基于C语言的聊天室项目

分为服务器和客户端两个部分

客户端发送相关操作指令,服务器接收到指令调用相关函数完成操作再将结果返回客户端;

以下为服务器端.c

#include <stdio.h>

#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>
#include <sqlite3.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<sys/types.h>

char IP[15];
short PORT = 3333;


static sqlite3 *db = NULL;
static char *errmsg = NULL;
static char **result=NULL;




typedef struct sockaddr NN;


typedef struct data
{
char mss[1024]; //消息
char account[30]; //随机账号登入使用
char name[30]; //名称
char pass[30]; //密码
char online[30]; //在线情况
int root;
int flag;
int jinyan;
char toname[30];
char fromname[30];
char filename[30];
int work; //放操作指令
char question[1024]; //密保问题
char answer[1024]; //密保答案
}msgdata;


typedef struct mylink //聊用
{
char name[30];
int cpyfd;
int onoffall; //在群聊否1在0不在
int jinyan; //没用到;
struct mylink *next;
}mylink;


mylink *pH;


int checkpass(int fdd,msgdata *msg);
int checkname(int fdd,msgdata *msg);
mylink * initlink();
void taillink(int fdd,msgdata *msg);
void detele_link(int tempfd);
void display_link(mylink *pH);
int init();
int myaccept(int sockfd);
void creat_table();
int display();
void insert(int fdd,msgdata *msg);
void enter(int fdd,msgdata *msg);
void offlink(int fdd,msgdata *msg);
void chatall(int fdd,msgdata *msg);
void chatone(int fdd,msgdata *msg);
void checkone(int fdd,msgdata *msg);
void lookonline(int fdd,msgdata *msg);
void jinyanchat(int fdd,msgdata *msg);
void jinyancaozuo(int fdd,msgdata *msg);
void jiechujinyancaozuo(int fdd,msgdata *msg);
void updatepass(int fdd,msgdata *msg);
void updatename(int fdd,msgdata *msg);
void sendfile(int fdd,msgdata *msg);
void* service_thread(void* p);
void setroot(int fdd,msgdata *msg);
void removeroot(int fdd,msgdata *msg);
void findcheck(int fdd,msgdata *msg);
void findpass(int fdd,msgdata *msg);
void outpeople(int fdd,msgdata *msg);
void justout(int fdd,msgdata *msg);


mylink * initlink()
{
mylink *p = (mylink *)malloc(sizeof(mylink));
p->next = NULL;
return p;
}


void taillink(int fdd,msgdata *msg)
{
mylink *pP = pH;
while(pP->next !=NULL)     //防止A强制退出后链表中还有,所以再次登入则覆盖fdd
{
if(strcmp(msg->name,pP->name) == 0)
{
pP->cpyfd = fdd;
return;
}
pP = pP->next;
}

mylink *p = pH; //之前一个小错误p = pH->next,这样p空了;下面就会段错误
mylink *new = (mylink *)malloc(sizeof(mylink)/sizeof(char));//******
while(p->next != NULL)
{
p = p->next;
}

strcpy(new->name,msg->name);


new->cpyfd = fdd;
new->onoffall = 0;
new->jinyan = 1; //1为不禁言
p->next = new;


new->next = NULL;
}


void detele_link(int tempfd)
{
int flog = 0;
mylink *p = pH;
mylink *pR = NULL;
while(p->next!=NULL)
{
pR = p;
p = p->next;
if(p->cpyfd == tempfd)
{
pR->next = p->next;
printf("%s已下线!\n",p->name);
flog = 1;
free(p);
}
}
if(flog == 0)
{
printf("查无此人\n");
}


}


void display_link(mylink *pH)         //服务器端自检在link中的人
{
mylink *p = pH;
while(p->next != NULL)
{
p = p->next;
printf("fdd = %d,onoffall = %d,name = %s\n",p->cpyfd,p->onoffall,p->name);
}
}


int init()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if (sockfd == -1)
{
        perror("创建socket失败");
        exit(-1);
    }
    struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = inet_addr(IP);
//addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    if (bind(sockfd,(NN*)&addr,sizeof(addr)) == -1)
{
printf("IP = %s\n",IP);
        perror("绑定失败");
        exit(-1);
    }
    if (listen(sockfd,100) == -1)
{
        perror("设置监听失败");
        exit(-1);
    }
printf("连接ing\n");
return sockfd;
}


int myaccept(int sockfd) //返回链接上的套接字
{
struct sockaddr_in client_addr; // 用来保存客户端的ip和端口信息
    int len = sizeof(client_addr);
    int client_socket = accept(sockfd,(NN *)&client_addr,  &len);
    if (client_socket == -1)
    {
        perror ("accept");
    }


    printf ("成功接收一个客户端: %s\n", inet_ntoa(client_addr.sin_addr));


    return client_socket;
}


void creat_table()
{
char *sql; //禁言为1,不禁言为0
sql = "create table if not exists names (id integer primary key,account text,name text,password text,root text,jinyan text,question text,answer text);";  
    if(SQLITE_OK != sqlite3_exec(db,sql,NULL,NULL,&errmsg))//判断是否成功成功返回SQLITE_OK  
    {  
        printf("fail:%s\n");  
        printf("\n");  
        exit(-1);  
    } 
}


int display() //数据库校验display
{  
    char *sql;    
    int i;  
    int nrow;  
    int ncol;  
int rc = sqlite3_open("test.db", &db);
if(rc)
{
printf("can't open database!\n");
}
else
{
printf("open database success!\n");
}

    sql = "select * from names;";  
  
    if(SQLITE_OK != sqlite3_get_table(db,sql,&result,&nrow,&ncol,&errmsg))//判断sqlite3_get_table是否运用成功,成功返回SQLITE_OK  
    {  
        printf("fail:%s\n",errmsg);  
        printf("\n");  
        exit(-1);  
    }  
  
    for(i = 0; i < (nrow + 1) * ncol; i++)//将表中的数据打印出来  
    {  
        printf("%-12s",result[i]);  
  
        if((i + 1) % ncol == 0)  
        {  
            printf("\n");  
        }  
    }  
  
    sqlite3_free_table(result);//释放result  

sqlite3_close(db);



void insert(int fdd,msgdata *msg) //注册插入数据库
{
char buf[200];
int nrow;
int ncol;
char _name[30];
int i = 0;
int j = 0;

int rc = sqlite3_open("test.db", &db);
if(rc)
{
printf("can't open data!\n");
}
else
{
printf("open data success!\n");
}
creat_table();
//检查昵称重复注册
sprintf(buf,"select name from names where name = '%s'",msg->name);
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
return;
}
for(i = 0; i < (nrow + 1)*ncol; i++)//检验 
{  
j = i;


strcpy(_name,result[j]);

if(strcmp(_name,msg->name) == 0)
{
msg->flag = 3;
sqlite3_free_table(result);
sqlite3_close(db);
send(fdd,msg,sizeof(msgdata),0);
return;
}
sqlite3_free_table(result);
memset(buf,0,sizeof(buf));
sprintf (buf, "insert into names (account,name,password,root,jinyan,question,answer) values ('%s','%s','%s','%d','%d','%s','%s');", msg->account,msg->name,msg->pass,msg->root,0,msg->question,msg->answer);
    int ret = sqlite3_exec(db, buf, NULL, NULL, &errmsg);
    if (ret != SQLITE_OK)
{
msg->flag = 0;
}
else
{
msg->flag = 1;
}
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
display();
}


void enter(int fdd,msgdata *msg)    //2登入
{
int rc = sqlite3_open("test.db", &db);
char buf[200];
char _pass[30];
char _name[30];
int nrow;  
    int ncol;
int i = 0;
int j = 0;

if(rc)
{
printf("can't open db!\n");
}
else
{
printf("open db success!\n");
}
//重复登入检查
if(checkname(fdd,msg) == 0)
{
msg->flag = 2;
send(fdd,msg,sizeof(msgdata),0);
return;
}
//密码检验函数
if(checkpass(fdd,msg) == 1)
{
msg->flag = 1;
sprintf(buf,"select name from names where account = '%s'",msg->account);
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
return;
}
strcpy(msg->name,result[1]);
sqlite3_free_table(result); 
taillink(fdd,msg);
printf("插入成功\n");
}
//sleep(1);
send(fdd,msg,sizeof(msgdata),0);


sqlite3_close(db);

}


void offlink(int fdd,msgdata *msg) //下线或退出群聊的处理
{
mylink *p = pH->next;
while(p != NULL)
{
if(p->cpyfd == fdd)
{
p->onoffall = 0;
}
p = p->next;
}
}


void chatall(int fdd,msgdata *msg)   //群聊操作
{
mylink *p = pH->next;
mylink *pP = pH->next;
mylink *pJ = pH->next;

if(strcmp(msg->mss,"bye") == 0)
{
offlink(fdd,msg);
return;
}
else
{
while(pP != NULL)
{
if(pP->cpyfd == fdd)
{
pP->onoffall = 1;
}
pP = pP->next;
}
}

//基于数据库的禁言
int nrow;
int ncol;
int rc = sqlite3_open("test.db", &db);
if(rc)
{
printf("can't open db!\n");
}
char buf[200];
sprintf(buf,"select jinyan from names where name = '%s'",msg->name);
if(SQLITE_OK != sqlite3_get_table(db,buf,&result,&nrow,&ncol,&errmsg))
{
printf("view error\n");
msg->work = -1;
send(fdd,msg,sizeof(msgdata),0);
return;
}
int temp = atoi(result[1]);
if(temp == 1)
{
msgdata mssg;
mssg.work = 8; //8禁言
send(fdd,&mssg,sizeof(msgdata),0);
return;
}
sqlite3_free_table(result);

//群聊操作
while(p != NULL)
{
if(p->onoffall == 1)
{
send(p->cpyfd,msg,sizeof(msgdata),0); //发送给所以在群聊的人;
printf("在聊天室的人 %s\n",p->name);
}
p = p->next;
}
printf("\n");
}


void chatone(int fdd,msgdata *msg) //私聊
{
mylink *p = pH;
int flag = 0;
display_link(pH);

while(p->next != NULL)
{
p = p->next;
if((strcmp(p->name,msg->toname) == 0) && (strcmp(p->name,msg->fromname) != 0 ))
{
send(p->cpyfd,msg,sizeof(msgdata),0);
break;
}
}


}


void checkone(int fdd,msgdata *msg) //私聊检验
{
mylink *p = pH;
int flag = 0;

while(p->next != NULL)
{
p = p->next;
printf("checkname = %s\n",p->name);
if((strcmp(p->name,msg->toname) == 0) && (strcmp(p->name,msg->fromname) != 0 ))
{
flag = 1;
break;
}
}
if(flag == 0)
{
msg->work = 4;
send(fdd,msg,sizeof(msgdata),0);
}
}


void lookonline(int fdd,msgdata *msg)
{
mylink *p = pH;
while(p->next != NULL)
{
p = p->next;
if(p->onoffall == 1)
{
strcpy(msg->name,p->name);
send(fdd,msg,sizeof(msgdata),0);
}
}
}


void jinyanchat(int fdd,msgdata *msg) //root权限判断
{
int nrow;
int ncol;
int rc = sqlite3_open("test.db", &db);
if(rc)
{
printf("can't open db!\n");
}
char buf[200];
sprintf(buf,"select root from names where name = '%s'",msg->name);
if(SQLITE_OK != sqlite3_get_table(db,buf,&result,&nrow,&ncol,&errmsg))
{
printf("view error\n");
return;
}
printf("result[1] = %s\n",result[1]);
int temp = atoi(result[1]);
if(temp == 1)
{
msg->flag = 1; //1是root
}
else
{
msg->flag = 0; //0不是root
}
send(fdd,msg,sizeof(msgdata),0);
sqlite3_free_table(result);
}


void jinyancaozuo(int fdd,msgdata *msg) //禁言操作,基于数据库
{
int nrow;
int ncol;
int i = 0;
int j = 0;
char _name[30];
int rc = sqlite3_open("test.db", &db);
if(rc)
{
printf("can't open db!\n");
}
char buf[200];
sprintf(buf,"select name from names where name = '%s'",msg->toname);
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
msg->work = -1;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
return;
}
for(i = 0; i < (nrow + 1)*ncol; i++)
{  
j = i;
}
strcpy(_name,result[j]);
printf("result[j] = %s\n",result[j]);
sqlite3_free_table(result);
if(strcmp(_name,msg->toname) != 0)
{
msg->work = 9;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
return;
}

memset(buf,0,sizeof(buf));
sprintf (buf, "update names set jinyan = '%d' where name = '%s'", 1, msg->toname);
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
msg->work = -1;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
return;
}
msg->work = 10;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_free_table(result);
sqlite3_close(db);
}


void jiechujinyancaozuo(int fdd,msgdata *msg) //基于数据库的解除禁言操作
{
int nrow;
int ncol;
int i = 0;
int j = 0;
char _name[30];
int rc = sqlite3_open("test.db", &db);
if(rc)
{
printf("can't open db!\n");
}
char buf[200];
sprintf(buf,"select name from names where name = '%s'",msg->toname);
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
msg->work = -1;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
return;
}
for(i = 0; i < (nrow + 1)*ncol; i++)
{  
j = i;
}
strcpy(_name,result[j]);
sqlite3_free_table(result);
if(strcmp(_name,msg->toname) != 0)
{
msg->work = 9;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
return;
}

memset(buf,0,sizeof(buf));
sprintf (buf, "update names set jinyan = '%d' where name = '%s'", 0, msg->toname);
if(SQLITE_OK != sqlite3_get_table(db,buf,&result,&nrow,&ncol,&errmsg))
{
printf("view error\n");
msg->work = -1;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
return;
}
msg->work = 11;
send(fdd,msg,sizeof(msgdata),0);
mylink *p = pH;
while(p->next != NULL)
{
p = p->next;
if(strcmp(p->name,msg->toname) == 0)
{
msg->work = 19;
send(p->cpyfd,msg,sizeof(msgdata),0);
break;
}
}
sqlite3_free_table(result);
sqlite3_close(db);
}




void updatepass(int fdd,msgdata *msg)
{
if(checkpass(fdd,msg) == 1)
{
msg->flag = 1;
}
else
{
msg->flag = 0;
}
send(fdd,msg,sizeof(msgdata),0);

recv(fdd,msg,sizeof(msgdata),0);

if(msg->flag == 3)
{
int rc = sqlite3_open("test.db", &db);
if(rc)
{
printf("can't open db!\n");
}
else
{
printf("open db success!\n");
}
char buf[200];
sprintf (buf, "update names set password = '%s' where account = '%s'", msg->pass, msg->account);
rc = sqlite3_exec(db, buf, NULL, NULL, &errmsg);
if (rc != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
sqlite3_close(db);
return;
}

}
else if(msg->flag == 2)
{
sqlite3_close(db);
return;
}

}
void updatename(int fdd,msgdata *msg)
{
if(checkpass(fdd,msg) == 1)
{
msg->flag = 1;
}
else
{
msg->flag = 0;
}
send(fdd,msg,sizeof(msgdata),0);

recv(fdd,msg,sizeof(msgdata),0);

if(msg->flag == 3)
{
int rc = sqlite3_open("test.db", &db);
if(rc)
{
printf("can't open db!\n");
}
else
{
printf("open db success!\n");
}
char buf[200];
sprintf (buf, "update names set name = '%s' where account = '%s'", msg->name, msg->account);
rc = sqlite3_exec(db, buf, NULL, NULL, &errmsg);
if (rc != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
sqlite3_close(db);
return;
}
}
else if(msg->flag == 2)
{
sqlite3_close(db);
return;
}
}


int checkpass(int fdd,msgdata *msg) //检验密码
{
char buf[200];
char _pass[30];
int nrow;  
    int ncol;
int i = 0;
int j = 0;
int rc = sqlite3_open("test.db", &db);
if(rc)
{
printf("can't open db!\n");
}
else
{
printf("open db success!\n");
}
//密码检查
sprintf(buf,"select password from names where account = '%s'",msg->account);
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
return;
}
for(i = 0; i < (nrow + 1)*ncol; i++)//检验 
{  
j = i;

strcpy(_pass,result[j]);
sqlite3_free_table(result); 
memset(buf,0,sizeof(buf));
if(strcmp(msg->pass,_pass) == 0)
{
return 1; //正确返回1
}
else
{
return 0;
}
sqlite3_close(db);

}


int checkname(int fdd,msgdata *msg) //重复登入检验
{
int rc = sqlite3_open("test.db", &db);
char buf[200];
char _name[30];
int nrow;  
    int ncol;
int i = 0;
int j = 0;

if(rc)
{
printf("can't open db!\n");
}
else
{
printf("open db success!\n");
}
sprintf(buf,"select name from names where account = '%s'",msg->account);
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
return;
}
for(i = 0; i < (nrow + 1)*ncol; i++)//检验 
{  
j = i;

strcpy(_name,result[j]);
sqlite3_free_table(result); 
mylink *p = pH; //检查链表
while(p->next != NULL)
{
p = p->next;
if(strcmp(p->name,_name) == 0)
{
return 0;
}
}
sqlite3_close(db);
return 1;
}


void sendfile(int fdd,msgdata *msg)
{
int flag = 0;

char buf[1024] = {0};


    strcpy(buf, msg->mss);

mylink *p = pH;
while(p->next != NULL) //找toname是否在群聊;
{
p = p->next;
if((strcmp(p->name,msg->toname) == 0) && (p->onoffall == 1))
{
flag = 1;
msg->work = 15;
send(p->cpyfd,msg,sizeof(msgdata),0);
}
}
if(flag == 1)
{
msg->work = 12;
send(fdd,msg,sizeof(msgdata),0);
}
else
{
msg->work = 13;
send(fdd,msg,sizeof(msgdata),0);
}
//close(pd);
}


void findcheck(int fdd,msgdata *msg)//查有无此人并把问题发送cli
{
int rc = sqlite3_open("test.db", &db);
char buf[200];
char _name[30];
int nrow;
int ncol;
int i = 0;
int j = 0;

if(rc)
{
printf("can't open db!\n");
}
else
{
printf("open db success!\n");
}
sprintf(buf,"select name from names where name = '%s'",msg->name);
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
return;
}
for(i = 0; i < (nrow + 1)*ncol; i++)//检验 
{  
j = i;

strcpy(_name,result[j]);
sqlite3_free_table(result); 
memset(buf,0,sizeof(buf));

if(strcmp(_name,msg->name) == 0)
{
msg->flag = 1;
sprintf(buf,"select question from names where name = '%s'",msg->name);
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
return;
}
for(i = 0; i < (nrow + 1)*ncol; i++)//检验 
{  
j = i;

strcpy(msg->question,result[j]);
sqlite3_free_table(result); 
memset(buf,0,sizeof(buf));
}
else
{
msg->flag = 0;
}
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
}


void findpass(int fdd,msgdata *msg) //查找账号密码
{
int rc = sqlite3_open("test.db", &db);
char buf[200];
char _answ[1024];
int nrow;
int ncol;
int i = 0;
int j = 0;

if(rc)
{
printf("can't open db!\n");
}
else
{
printf("open db success!\n");
}
sprintf(buf,"select answer from names where question = '%s'",msg->question);
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
return;
}
for(i = 0; i < (nrow + 1)*ncol; i++)
{  
j = i;

strcpy(_answ,result[j]);
sqlite3_free_table(result); 
memset(buf,0,sizeof(buf));
if(strcmp(_answ,msg->answer) == 0)
{
msg->flag = 1;
sprintf(buf,"select account from names where question = '%s'",msg->question);//账号
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
return;
}
for(i = 0; i < (nrow + 1)*ncol; i++)
{  
j = i;

strcpy(msg->account,result[j]);
sqlite3_free_table(result);
memset(buf,0,sizeof(buf));

sprintf(buf,"select password from names where question = '%s'",msg->question);//密码
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
return;
}
for(i = 0; i < (nrow + 1)*ncol; i++)
{  
j = i;

strcpy(msg->pass,result[j]);
sqlite3_free_table(result);
memset(buf,0,sizeof(buf));
}
else
{
msg->flag = 0;
}

send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
}


void justout(int fdd,msgdata *msg)
{
mylink *p = pH;
int flag = 0;
while(p->next != NULL)
{
p = p->next;
if(strcmp(p->name,msg->toname) == 0 && p->onoffall == 1)
{
flag = 1;

}
}
if(flag == 1)
{
msg->work = 18;
outpeople(fdd,msg);
}
else
{
msg->work = 21;
}
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
}


void outpeople(int fdd,msgdata *msg)
{
mylink *p = pH;
char _name[30];
char buf[200];
while(p->next != NULL)
{
p = p->next;
if(strcmp(p->name,msg->toname) == 0)
{
msg->work = 20;
strcpy(msg->mss,"你被管理员踢下线\n");
//p->onoffall = 0;
detele_link(p->cpyfd);
send(p->cpyfd,msg,sizeof(msgdata),0);
}
if(p->onoffall == 1)
{
msg->work = 3;
sprintf(buf,"%s被踢出群聊\n",msg->toname);
strcpy(msg->mss,buf);
send(p->cpyfd,msg,sizeof(msgdata),0);
}
}


}


void* service_thread(void* p)
{
    int fdd = (int)p;
msgdata msg;
    printf("pthread = %d\n",fdd);

    while(1)
{ //一次一次接收
        if (recv(fdd,&msg,sizeof(msgdata),0) <= 0) //send   recv cli中break了所以会接收失败;
{ //write  read
printf("%d已退出%s\n",fdd,msg.name);
offlink(fdd,&msg);
break;
        }
switch(msg.work)
{
case 1:insert(fdd,&msg);break; //注册插入数据库1
case 2:enter(fdd,&msg);break; //登入验证2
case 3:chatall(fdd,&msg);break; //进入群聊3
case 4:checkone(fdd,&msg);break; //检验私聊对象状态6
case 5:chatone(fdd,&msg);break; //进入私聊5
case 6:lookonline(fdd,&msg);break; //查看在线人数
case 7:jinyanchat(fdd,&msg);break; //禁言权限判断
case 8:jinyancaozuo(fdd,&msg);break;//禁言实际操作
case 10:jiechujinyancaozuo(fdd,&msg);break; //禁言实际操作
case 11:updatepass(fdd,&msg);break; //修改密码
case 12:updatename(fdd,&msg);break; //修改昵称
case 13:sendfile(fdd,&msg);break; //文件传输
case 15:detele_link(fdd);break; //下线
case 16:send(fdd,&msg,sizeof(msgdata),0);break;//返回主程序
case 17:setroot(fdd,&msg);break; //设置管理员
case 18:removeroot(fdd,&msg);break; //移除管理
case 19:findcheck(fdd,&msg);break; //检验昵称
case 20:findpass(fdd,&msg);break; //找回账号和密码
case 21:justout(fdd,&msg);break; //踢人
}
    }
close(fdd);
}


void setroot(int fdd,msgdata *msg) //设置管理员权限
{
int nrow;
int ncol;
int i = 0;
int j = 0;
char _name[30];
int rc = sqlite3_open("test.db", &db);
if(rc)
{
printf("can't open db!\n");
}
else
{
printf("open db success!\n");
}
char buf[200];
sprintf(buf,"select name from names where name = '%s'",msg->name);
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
msg->work = -1;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
return;
}
for(i = 0; i < (nrow + 1)*ncol; i++)
{  
j = i;
}
strcpy(_name,result[j]);
sqlite3_free_table(result);
if(strcmp(_name,msg->name) != 0)
{
msg->work = 9;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
return;
}

memset(buf,0,sizeof(buf));
sprintf (buf, "update names set root = '%d' where name = '%s'", 1 , msg->name);
rc = sqlite3_exec(db, buf, NULL, NULL, &errmsg);
if (rc != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
msg->work = -1;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
return;
}

msg->work = 18;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);

}


void removeroot(int fdd,msgdata *msg) //移除管理员
{
int nrow;
int ncol;
int i = 0;
int j = 0;
char _name[30];
int rc = sqlite3_open("test.db", &db);
if(rc)
{
printf("can't open db!\n");
}
else
{
printf("open db success!\n");
}
char buf[200];
sprintf(buf,"select name from names where name = '%s'",msg->name);
if(SQLITE_OK != sqlite3_get_table( db, buf , &result, &nrow, &ncol, &errmsg))
{
printf("view error\n");
msg->work = -1;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
return;
}
for(i = 0; i < (nrow + 1)*ncol; i++)
{  
j = i;
}
strcpy(_name,result[j]);
sqlite3_free_table(result);
if(strcmp(_name,msg->name) != 0)
{
msg->work = 9;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
return;
}

memset(buf,0,sizeof(buf));
sprintf (buf, "update names set root = '%d' where name = '%s'", 0 , msg->name);
rc = sqlite3_exec(db, buf, NULL, NULL, &errmsg);
if (rc != SQLITE_OK)
{
printf ("数据库操作失败:%s\n", errmsg);
msg->work = -1;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
return;
}

msg->work = 18;
send(fdd,msg,sizeof(msgdata),0);
sqlite3_close(db);
}


int main(int argc,char *argv[])
{
if(argc != 2)
{
printf("请仅在执行语句后加服务器IP地址\n");
exit(-1);
}
else
{
strcpy(IP,argv[1]);
}
pH = initlink();
int sockfd = init();
while(1)
{

int fd = myaccept(sockfd);
pthread_t id;
        pthread_create(&id, NULL, service_thread,  (void *)fd);


        pthread_detach(id); 

}

close (sockfd);

return 0;

}

以下为客户端.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sqlite3.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<sys/types.h>


int fd;
char IP[15];//服务器的IP
short PORT = 3333;//服务器服务端口


static sqlite3 *db = NULL;
static char *errmsg = NULL;
static char **result=NULL;


typedef struct sockaddr NN;
int chatoneflag;
int jinyanflag;//为了禁言后不保存本地聊天记录
int rootflag;//判断管理员flag
int bossflag;


char e_name[30];


typedef struct data
{
char mss[1024]; //消息
char account[30]; //随机账号登入使用
char name[30]; //名称
char pass[30]; //密码
char time[30]; //存时间
int root;
int flag;
int jinyan;
char toname[30];
char fromname[30];
char filename[30];
int work; //放操作指令
char question[1024]; //密保问题
char answer[1024]; //密保答案
}msgdata;


typedef struct Linknode //私聊用
{
char name[30];
int fd;
struct Linknode *next;
}mylink;




void menu();
void regist();
int enter();
void chatall();
void lookonline();
void creat_table();
void chatone();
char *my_times();
void localchat();
void jinyanchat();
void savechat(msgdata *msg,int flag);
void jinyancaozuo();
void create_root();
void jiechujinyancaozuo();
void sendfile();
void savefile(msgdata *msg);
void* recv_thread(void* p);
void menu2();
void updatepass();
void updatename();
void detele_link();
void rootcaozuo();
void removeroot();
void setroot();
void menu3();
void findpass();
void justout();


void regist() //注册
{
msgdata msg;
msg.work = 1;


int temp;

char name[30];
char account[30];
char pass[30];

srand((unsigned) time(NULL));
temp = rand()%10000;
sprintf(msg.account,"%d",temp); //整形转换字符串的一种方法


printf("输入你的昵称:");
gets(name);
printf("输入你的密码:");
gets(pass);
printf("请输入密保问题: ");
gets(msg.question);
printf("请输入密保答案: ");
gets(msg.answer);

strcpy(msg.name,name);
strcpy(msg.pass,pass);

if(strcmp(msg.name,"root") == 0)
{
msg.root = 1;
strcpy(msg.account,"111");
}
else
{
msg.root = 0;
}


send(fd,&msg,sizeof(msgdata),0); //发送给总控制台;

recv(fd,&msg,sizeof(msgdata),0); //接收serl中注册函数send回来的数据;

if(msg.flag == 1)
{
printf("注册成功\n");
printf("\n您的登入账号为:%s 请务必牢记\n",msg.account);
printf("\n您的登入账号为:%s 请务必牢记\n",msg.account);
printf("\n您的登入账号为:%s 请务必牢记\n",msg.account);
}
else if(msg.flag == 0)
{
printf("注册失败\n");
}
else if(msg.flag == 3)
{
printf("昵称重复请重新注册\n");
}



int enter() //登入
{
msgdata msg;

msg.work = 2;

char account[30];
char pass[30];


printf("输入你的账号:");
gets(account);
printf("输入你的密码:");
gets(pass);
strcpy(msg.account,account);
strcpy(msg.pass,pass);

send(fd,&msg,sizeof(msgdata),0);

recv(fd,&msg,sizeof(msgdata),0);
if(msg.flag == 1)
{
printf("\n");
printf("欢迎你%s\n",msg.name);
printf("\n");
strcpy(e_name,msg.name);
}
else if(msg.flag == 2)
{
printf("该账号已登入\n");
return 0;
}
else
{
printf("账号或密码错误\n");
return 0;
}

return 1;
}




void chatall() //群聊功能
{


msgdata msg;

char buf[1024];

msg.work = 3;

strcpy(msg.name,e_name);
system("clear");
printf("********************************************\n");
printf("\t群聊操作指南\n");
printf("q2:进入私聊模式(私聊模式下输back返回群聊)\n");
printf("q3:查看在线人员\n");
printf("q4:查看本地聊天记录\n");
printf("q5:进入管理员操作\n");
printf("q6:发送文件\n");
printf("群聊模式下输入bye退出群聊返回主程序\n");
printf("********************************************\n");
sprintf(msg.mss,"进入了群聊\n");

send(fd,&msg,sizeof(msgdata),0);

memset(msg.mss,0,strlen(msg.mss));

while(1)
{
gets(buf);

strcpy(msg.mss,buf);

strcpy(msg.time,my_times());

if (strcmp(msg.mss,"bye") == 0) //bye退出群聊操作;
{
memset(buf,0,sizeof(buf));
sprintf(msg.mss,"退出了群聊\n");
send(fd,&msg,sizeof(msgdata),0); //将退出的消息发给公频
memset(msg.mss,0,strlen(msg.mss));
strcpy(msg.mss,"bye"); //bye退出在公频的在线人数;
send(fd,&msg,sizeof(msgdata),0);
break;
}
else if(strcmp(msg.mss,"q2") == 0) //q2进入私聊模式;
{
chatone();
sleep(1);
printf("您已返回群聊\n");

}
else if(strcmp(msg.mss,"q3") == 0) //查看在线人员
{
lookonline();
sleep(1);
printf("\n您已返回群聊\n");
}
else if(strcmp(msg.mss,"q4") == 0) //查看聊天记录
{
localchat();
sleep(1);
printf("\n您已返回群聊\n");
}
else if(strcmp(msg.mss,"q5") == 0) //管理员操作
{
jinyanchat();//root权限判断
sleep(1);
if(rootflag == 1)//判断是否为root用户
{
rootcaozuo();
}
//sleep(1);
printf("您已返回群聊\n");
}
else if(strcmp(msg.mss,"q6") == 0) //发送文件
{
sendfile();
sleep(1);
printf("您已返回群聊\n");
}

else
{
send(fd,&msg,sizeof(msgdata),0);
sleep(1);
if(jinyanflag != 1)
{
savechat(&msg,1);
}
}
memset(msg.mss,0,strlen(msg.mss));
memset(msg.time,0,strlen(msg.time));
memset(buf,0,sizeof(buf));
}

}


void rootcaozuo()
{
char ch[5];
int i;
int flag = 0;
while(1)
{
menu3();
printf("输入操作:");
gets(ch);
i = atoi(ch);
switch(i)
{
case 1:jinyancaozuo();sleep(1);break;
case 2:jiechujinyancaozuo();sleep(1);break;
case 3:setroot();sleep(1);break;
case 4:removeroot();sleep(1);break;
case 5:justout();sleep(1);break;
case 6:flag = 1;printf("正在返回群聊\n");break;


}
if(flag == 1)
{
break;
}
}
}


void justout()
{
msgdata msg;
msg.work = 21;

printf("输入姓名:");
gets(msg.toname);
send(fd,&msg,sizeof(msgdata),0);

}


void setroot()//设置管理员权限 //在外面设置管理员
{
msgdata msg;
msg.work = 17;
printf("输入你想要设置管理的人的昵称:");
gets(msg.name);
send(fd,&msg,sizeof(msgdata),0);

}


void removeroot()
{
msgdata msg;
msg.work = 18;
printf("输入你想要移除管理的人的昵称:");
gets(msg.name);
send(fd,&msg,sizeof(msgdata),0);

}


void menu3()
{
printf("  root用户操作\n");
printf("\n");
printf("1,禁言 2,解除禁言\n");
printf("3,设置管理员 4,移除管理员\n");
printf("5,踢人 6,返回群聊\n");
printf("\n");
}


void sendfile()
{
msgdata msg;
msg.work = 13;
char buf[1024] = {0};
char name[30];
char txt[30];
printf("请输入要发送的对象昵称\n");
gets(name);
strcpy(msg.toname,name);
printf("输入要传的文件名(加后缀)\n");
gets(txt);
strcpy(msg.filename,txt);
sprintf(buf,"%s",txt);
int pd = open(buf, O_RDONLY|O_CREAT);
    if (pd == -1)
    {
        perror ("error");
        return;
    }

int ret = 0;

    memset(buf,0,sizeof(buf));

    ret = read(pd, buf, 1024);


    buf[ret] = '\0';


    strcpy(msg.mss,buf);

strcpy(msg.fromname,e_name);

send(fd,&msg,sizeof(msgdata),0);

close(pd);

}


void savefile(msgdata *msg)
{
char buf[1024] = {0};
sprintf(buf,"%s",msg->filename);
int pd = open(buf, O_WRONLY|O_CREAT); //后续加入如果改文件存在是否覆盖
if (pd == -1)
    {
        perror ("error");
        return;
    }
memset(buf,0,sizeof(buf));


    strcpy(buf, msg->mss);
    write(pd,buf,strlen(buf));
close(pd);

}


void jinyanchat() //root权限判断
{
msgdata msg;
msg.work = 7;
strcpy(msg.name,e_name);
send(fd,&msg,sizeof(msgdata),0);

}


void jinyancaozuo()
{
// sleep(1); //因为send交给线程处理后,这边会继续往下走;所以要sleep
msgdata msg; //等线程那儿处理完;
msg.work = 8;
char name[30];
printf("输入禁言姓名:");
gets(name);
strcpy(msg.toname,name);
send(fd ,&msg,sizeof(msgdata),0);
}


void jiechujinyancaozuo()
{
msgdata msg;
msg.work = 10;
char name[30];
printf("输入解禁姓名:");
gets(name);
strcpy(msg.toname,name);
send(fd ,&msg,sizeof(msgdata),0);
}


void lookonline() //查看在群聊中的人员
{
msgdata msg;
msg.work = 6;
printf("在线名单如下\n");
send(fd,&msg,sizeof(msgdata),0);

}


char *my_times() //获取时间函数
{
time_t rawtime;
    struct tm * timeinfo;
    time(&rawtime);
    timeinfo = localtime(&rawtime);
return asctime(timeinfo);
}


void creat_table()
{
char *sql; 
sql = "create table if not exists chat (time text,fromname text,toname text,mss text);";  
    if(SQLITE_OK != sqlite3_exec(db,sql,NULL,NULL,&errmsg))//判断是否成功成功返回SQLITE_OK  
    {  
        printf("fail:%s\n");  
        printf("\n");  
        exit(-1);  
    } 
}


void savechat(msgdata *msg,int flag) //保存聊天记录
{

char buf[200];
char *sql; 
int rc = sqlite3_open("localchatsave.db", &db);
if(rc)
{
printf("can't open database!\n");
exit(-1);
}


creat_table();

if(flag == 1)
{
sprintf (buf, "insert into chat (time,fromname,toname,mss) values ('%s','%s','%s','%s');",msg->time,msg->name,"all",msg->mss);
}
else if(flag == 0)
{
sprintf (buf, "insert into chat (time,fromname,toname,mss) values ('%s','%s','%s','%s');",msg->time,msg->fromname,msg->toname,msg->mss);
}
rc = sqlite3_exec(db, buf, NULL, NULL, &errmsg);
    if (rc != SQLITE_OK)
    {
        printf ("数据库操作失败:%s\n", errmsg);
        exit(-1);
    }
sqlite3_close(db);
}


void localchat() //本地聊天记录
{
char *sql;
msgdata msg;
int i = 0;
int j = 0;
int nrow;  
    int ncol;
msg.work = 7;
int rc = sqlite3_open("localchatsave.db", &db);
if(rc)
{
printf("can't open database!\n");
//exit(-1);
return ;
}

sql = "select * from chat;";  
  
    if(SQLITE_OK != sqlite3_get_table(db,sql,&result,&nrow,&ncol,&errmsg))//判断sqlite3_get_table是否运用成功,成功返回SQLITE_OK  
    {  
        printf("fail:%s\n",errmsg);  
        printf("\n");  
        exit(-1);  
    }  
  
    for(i = 0; i < (nrow + 1) * ncol; i++) //将表中的数据打印出来  
    {  
        printf("%-25s",result[i]);   //别人的私聊也打出来了,需要改进
  
        if((i + 1) % ncol == 0)  
        {  
            printf("\n");  
        }  
    }  
  
    sqlite3_free_table(result);//释放result  

sqlite3_close(db);

printf("\n查看完成,正在返回群聊\n");
}


void chatone() //私聊
{
msgdata msg;

char buf[1024];
char onename[30];
while(1)
{
chatoneflag = 0; //每次while将chatoneflag重置为0;
msg.work = 4;
printf("输入你想要私聊的人:(back退出私聊返群聊)\n");
gets(onename);
if(strcmp(onename,"back") == 0)
{
printf("正在返回群聊........\n");

return;
}
strcpy(msg.toname,onename);
strcpy(msg.fromname,e_name);
printf("检验中请等待........\n");
send(fd,&msg,sizeof(msgdata),0);
sleep(1);
if(chatoneflag == 0) //chatoneflag:若无此人就不开始私聊
{
printf("您可以开始私聊了\n");
break;
}
memset(onename,0,strlen(onename));
}
msg.work = 5;//私聊用5
while(1)
{
//printf("私聊:");
gets(buf);
strcpy(msg.mss,buf);
strcpy(msg.time,my_times());
if(strcmp(buf,"back") == 0)
{
printf("正在返回群聊........\n");

return;
}
else
{
printf("你对 %s 偷偷说了:%s\n",msg.toname,msg.mss);
savechat(&msg,0);
//sleep(1);
send(fd,&msg,sizeof(msgdata),0);
}
memset(buf,0,sizeof(buf));
}
}




void* recv_thread(void* p)  //一直在这里接收
{
fd = (int)p;
msgdata msg;
int rc;
    while(1)
{
rc = recv(fd,&msg,sizeof(msgdata),0);
if(rc <= 0)
{
printf("服务器断开链接\n");
exit(-1);
}
switch(msg.work)
{
case 3:printf("(群聊)%s : %s\n",msg.name,msg.mss);break;
case 4:chatoneflag = 1;printf("%s不在线\n或者不存在这个人\n或者你在对自己私聊\n",msg.toname);break;
case 5: if(chatoneflag != 1)
{
printf("(私聊)%s偷偷对你说:%s\n",msg.fromname,msg.mss);
}break;
case 6:printf("%s\n",msg.name);break;
case 7: if(msg.flag == 1)
{
rootflag = 1;
printf("您是root用户请稍后\n");
}
else
{
printf("您不是root用户\n正在返回群聊........\n");
}break;
case 8:jinyanflag = 1;printf("您已经被禁言了\n");break;
case 9:printf("操作失败(对方可能不存在)请重新选择操作\n");break;
case 10:printf("禁言 %s 成功\n",msg.toname);break;
case 11:printf("解除 %s 的禁言成功\n",msg.toname);break;
case 12:printf("文件发送成功\n正在返回群聊........\n");break;
case 13:printf("文件发送失败(此人不群聊中不能接收文件)\n正在返回群聊........\n");break;
case 15:savefile(&msg);printf("从%s处接收到一个文件\n",msg.fromname);break;
case 16:bossflag = 1;break;
case -1:printf("一些意想不到的错误发生了\n");break;
case 18:printf("设置成功\n");break;
case 19:jinyanflag = 0;printf("您已被解除禁言\n");break;
case 20:printf("%s\n",msg.mss);exit(0);break;
case 21:printf("对方不存在或不在线\n");break;
}
if(bossflag == 1)
{
break;
}

}


void detele_link()
{
msgdata msg;

msg.work = 15;

strcpy(msg.name,e_name);

send(fd,&msg,sizeof(msgdata),0);

}


void updatepass()
{
msgdata msg;

msg.work = 11;

char account[30];
char pass[30];
printf("验证账号和密码\n");
printf("输入你的账号:");
gets(account);
printf("输入你的密码:");
gets(pass);
strcpy(msg.account,account);
strcpy(msg.pass,pass);

send(fd,&msg,sizeof(msgdata),0);

recv(fd,&msg,sizeof(msgdata),0);

if(msg.flag == 0)
{
printf("账号或密码错误\n");
msg.flag = 2;
send(fd,&msg,sizeof(msgdata),0);
return;
}
else if(msg.flag = 1)
{
printf("账号密码正确\n");
printf("输入想要修改成的密码:");
gets(pass);
strcpy(msg.pass,pass);
msg.flag = 3;
send(fd,&msg,sizeof(msgdata),0);
printf("操作完成\n");
}
}


void updatename()
{
msgdata msg;

msg.work = 12;

char account[30];
char pass[30];
char name[30];
printf("验证账号和密码\n");
printf("输入你的账号:");
gets(account);
printf("输入你的密码:");
gets(pass);
strcpy(msg.account,account);
strcpy(msg.pass,pass);

send(fd,&msg,sizeof(msgdata),0);

recv(fd,&msg,sizeof(msgdata),0);

if(msg.flag == 0)
{
printf("账号或密码错误\n");
msg.flag = 2;
send(fd,&msg,sizeof(msgdata),0);
return;
}
else if(msg.flag = 1)
{
printf("账号密码正确\n");
printf("输入想要修改成的昵称:");
gets(name);
strcpy(msg.name,name);
msg.flag = 3;
send(fd,&msg,sizeof(msgdata),0);
printf("操作完成\n");
}
}


void findpass() //找回账号密码
{
msgdata msg;
msg.work = 19;
char _name[1024];

printf("输入昵称:");
gets(msg.name);
send(fd,&msg,sizeof(msgdata),0);

recv(fd,&msg,sizeof(msgdata),0);

if(msg.flag != 1)
{
printf("查无此人\n");
return;
}
msg.work = 20;
printf("密保问题:%s\n",msg.question);
printf("请输入答案:");
gets(msg.answer);

send(fd,&msg,sizeof(msgdata),0);
recv(fd,&msg,sizeof(msgdata),0);

if(msg.flag == 1)
{
printf("你的账号为%s\n",msg.account);
printf("你的密码为%s\n",msg.pass);
}
else
{
printf("答案错误\n");
}
}


void menu()
{
//system("clear");
printf("\n");
printf("\t聊天室demo\t\n");
printf("\t*****************\n");
printf("\t1.注册\n");
printf("\t2.登入\n");
printf("\t3.修改密码\n");
printf("\t4.修改昵称\n");
printf("\t5.找回密码\n");
printf("\t6.退出\n");
printf("\t群主需抢先注册昵称为root\n");
printf("\t*****************\n");
}


void menu2()
{
char ch[5];
int i;
int flag = 0;
while(1)
{
sleep(1);
printf("\t****************\n");
printf("\t3.进入群聊\n");
printf("\t5.退出到主程序\n");
printf("\t****************\n");
printf("输入操作:");
gets(ch);
i = atoi(ch);
switch(i)
{
case 3:chatall();break;
case 5:detele_link();flag = 1;break;
}
memset(ch,0,strlen(ch));
if(flag == 1)
{
bossflag = 1;
msgdata msg;
msg.work = 16;
send(fd,&msg,sizeof(msgdata),0);
break;
}
}


}


int main(int argc,char *argv[])
{
if(argc != 2)
{
printf("请仅在执行语句后加服务器IP地址\n");
exit(-1);
}
else
{
strcpy(IP,argv[1]);
}
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
    {
        perror ("socket");
        return -1;
    }
struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family  = AF_INET;     // 设置地址族
    addr.sin_port    = htons(PORT); // 端口号转换为网络字节序
    inet_aton(IP,&(addr.sin_addr));
//addr.sin_addr.s_addr = htonl(INADDR_ANY); 


int ret = connect(fd, (NN *)&addr, sizeof(addr));
if (ret == -1)
    {
        perror ("connect");
        return -1;
    }
printf ("成功连上服务器\n");

char ch[5];
int i;
while(1)
{
menu();
printf("输入操作:");
gets(ch);
i = atoi(ch);
switch(i)
{
case 1:regist();break; //注册
case 2:if(enter() == 1) //登入
{
bossflag = 0;
pthread_t id; //启用线程
pthread_create(&id,NULL,recv_thread,(void *)fd);
pthread_detach(id);
menu2();
}break;
case 3:updatepass();break; //修改密码
case 4:updatename();break; //修改密码
case 5:findpass();break;
case 6:detele_link();exit(0);break; //退出
}
memset(ch,0,strlen(ch));
}
    close(fd);
    return 0;

}

猜你喜欢

转载自blog.csdn.net/kuimzzs/article/details/79681025