目录
1.基本功能以及使用注意事项
基本功能
1.注册 2.登录 3.群聊 4私聊 5.快捷短语 6.注销用户 7.修改密码
8.保存聊天记录 9.查看聊天记录 10.查看在线用户 11.文件传输
12.管理员申请 13.管理员踢人 14.管理员专属头像 15.禁言用户
16.解除禁言 17.撤销管理员身份
1.1基本介绍
服务器采用tcp 多线程并发服务器
客户端采用两个线程 接受和发送线程 接受线程主要负责接受服务器发送过来的信号
写线程主要负责给服务器发送各种信号用于实现对应的功能,以及实现客户端与客户端之间的群聊或者私聊
注意事项:管理员不能踢出(禁言)管理员 只能对普通用户进行管理员操作
申请成为管理员必须先注册为普通用户
登录之前必须注册 不能重复登录(注册)
2.服务器端
chatroom.c
2.1服务器初始化函数
#include "chatroom.h"
int j; //用于线程号数组
int flag2 = 1; //用于管理员禁言
//服务器初始化
void Init()
{
unsigned char ip_str[] = "192.168.91.151";
unsigned char port_str[] = "8787";
struct sockaddr_in serveraddr;
socklen_t addrlen = sizeof(serveraddr);
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
ERRLOG("socket");
}
//第二部:填充网络信息结构体
serveraddr.sin_addr.s_addr = inet_addr(ip_str);
serveraddr.sin_port = htons(atoi(port_str));
serveraddr.sin_family = AF_INET;
int opt = 1;//设置端口复用
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
//第三步
if((bind(sockfd,(struct sockaddr *)&serveraddr,addrlen)) == -1)
{
ERRLOG("bind");
}
//第四步
if((listen(sockfd,100)) == -1)
{
ERRLOG("listen");
}
}
2.2接受处理客户端请求连接
//接受处理客户端
void server(online_userlist *head)
{
thread_node node;//结构体新增变量
node.head = head;
clientlist c_client;
struct sockaddr_in clientaddr;
while(1)
{
socklen_t addrlen = sizeof(clientaddr);
if((node.cfd = accept(sockfd,(struct sockaddr *)&clientaddr,&addrlen)) == -1)
{
ERRLOG("accept");
}
printf("客户端连接成功\n");
if(pthread_create(&pti1[j],NULL,myfun,(void*)&node) != 0)
{
ERRLOG("pthread_create");
}
printf("服务线程测试\n");
pthread_detach(pti1[j]);
//为客户端进行服务
j++;
}
close(sockfd);
}
2.3线程函数
void *myfun(void *arg)
{
thread_node node;
node = *((struct thread_node *)arg);
while(1)
{
messagehand(&node);
}
close(node.cfd);
return NULL;
}
2.4线程函数内部处理客户端想执行的功能
//线程函数内部处理客户端想执行的功能
void messagehand(thread_node *node)
{
clientlist c_client;//创建一个和客户端一样的结构体
int bytes = recv(node->cfd,&c_client,sizeof(c_client),0); //0阻塞接受
if(c_client.flag == 3 || c_client.flag == 5)
{
insert_uprecord(node,&c_client);
}
if(bytes == -1)
{
ERRLOG("recv\n");
}
else if(bytes == 0)
{
exituser(node,&c_client);
//printf("正在运行群聊函数\n");
online_userlist *p = node->head;
p=p->next;
while(p!=NULL)//如果用p->next!=NULL 当p在最后一个结点是 p->next=NULL 无法进入循环
{
if(p->c_fd != 0)
{
char buf[50] = "\0";
sprintf(buf,"[%s]:退出了",c_client.name);
if(send(p->c_fd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
memset(buf,0,sizeof(buf));
}
p=p->next;
}
printf("%s:退出了\n",c_client.name);
pthread_exit(NULL);
}
printf("接受的结构体名字:%s 功能标志:%d 密码:%s 私聊对象:%s 管理员标志: %d\n",c_client.name,c_client.flag,c_client.password,c_client.to_name,c_client.root);
switch(c_client.flag)
{
case 1:
Register(node,&c_client);//注册用户
printf("注册用户\n");
break;
case 2:
login(node,&c_client);//登录
printf("用户登录功能\n");
break;
case 3:
privatechat(node,&c_client); //私聊
printf("私聊功能\n");
break;
case 4:
changepassword(node,&c_client); //修改密码
printf("修改密码\n");
break;
case 5:
groupchat(node,&c_client);//进行群聊
break;
case 6: //查看所有在线用户
viewonline_user(node,&c_client);
break;
case 7://注销用户
loguser(node,&c_client);
break;
case 8:
Checkrecord(node);//查看聊天记录
break;
case 9:
filetransfer(node,&c_client); //文件传输
break;
case 10:
applyroot(node,&c_client); //申请管理员用户
break;
case 11:
rootlogin(node,&c_client); //管理员登录
break;
case 12:
rootkick(node,&c_client); //管理员踢人
break;
case 13:
silent(node,&c_client); //管理员禁言
break;
case 14:
remsilent(node,&c_client); //管理员解除用户禁言
break;
case 15:
cancelroot(node,&c_client); //取消管理员身份
break;
}
}
2.5注册
//注册
void Register(thread_node *node,clientlist *c)
{
printf("判断:%s 是否在数据库\n",c->name);
int ret = searchtable(c->name); //在数据库中查找是否已经注册过
printf("%d",ret);
if(1 == ret)
{
char arr[128] = {"账号已经存在,请重新注册"};
if(send(node->cfd,arr,sizeof(arr),0) == -1)
{
ERRLOG("send error");
}
return;
}
else
{
insert_updata(node,c); //向数据库中插入数据
}
}
2.6 数据库中插入函数
//向数据库中插入
void insert_updata(thread_node *node,clientlist *c)
{
printf("注册的名字%s\n",c->name);
char *errmsg;
sqlite3 *db =NULL;
char sql[200] = "\0";
memset(sql,0,sizeof(sql));//清空sql
sprintf(sql,"insert into user(name,password) values('%s','%s')",c->name,c->password);
printf("数据库sql语句测试\n");
execstate(sql);
printf("\033[0;34m插入成功\033\n");
char buf[100] = {"[系统日志]:注册成功...\n"};
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
2.7创建在线用户链表
//在线用户链表
online_userlist* online_userlistcreate()
{
online_userlist *head = (online_userlist *)malloc(sizeof(online_userlist));
head->next = NULL;
return head;
}
2.8 登录
void login(thread_node *node,clientlist *c)
{
//判断是否注册
if(0 == (searchtable(c->name)))
{
char buf[32] = "该用户不存在,请注册...";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
else if( 0 == (veridandpassword(c)))//密码错误
{
char buf[20] = "密码输入错误..";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
else if(1 == (veridandpassword(c)))//返回值为1账号密码正确
{
if(1 ==Repeatlogin(node,c))//判断重复登录
{
online_insertion(node,c);
char buf[32] = "登录成功..";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
online_userlist *p = node->head;
p=p->next;
while(p!=NULL)//如果用p->next!=NULL 当p在最后一个结点是 p->next=NULL 无法进入循环
{
if(p->c_fd != 0)
{
char buf[50] = "\0";
sprintf(buf,"[%s]:上线了",c->name);
if(send(p->c_fd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
memset(buf,0,sizeof(buf));
}
p=p->next;
}
}
else
{
return;
}
}
}
2.9登录将用户插入链表
void online_insertion(thread_node *node,clientlist *c)
{
online_userlist *tmp=(online_userlist *)malloc(sizeof(online_userlist));
tmp->next=NULL;
online_userlist *p =node->head;//定义一个指针为表头
strcpy(tmp->name,c->name);
tmp->c_fd = node->cfd;
printf("判断:%s,%d是否进行插入链表\n",tmp->name,tmp->c_fd);
if(1==onlineempty(p))
{
tmp->next=p->next;//令新插入的结点指针指向下一个结点
p->next=tmp;
}
else
{
while(p->next!=NULL&&strncmp(p->next->name , tmp->name,1)<0)//当目的name小于源name
{
p=p->next;
}
//当p->next指向的数据大于或者等于需要插入的数据是跳出循环
//此事p->next 向的是第一个大于value的值
tmp->next=p->next;
p->next=tmp; //然后将其插入大于value的值之前
putchar(10);
}
printf("链表插入完成\n");
}
2.10 登录在数据库验证账户与密码
//验证账户与密码 正确返回1 错误返回0;
int veridandpassword(clientlist *p)
{
printf("已进入密码效验工作\n");
int flag;
sqlite3 *db = NULL; //数据库的名字记得更换
int ret = sqlite3_open("user.db",&db);
if(SQLITE_OK != ret)
{
perror("sqlite3_open");
exit(1);
}
printf("已打开数据库\n");
char sql[200] = "\0";
sprintf(sql,"select *from user;");
char *errmsg;//定义指着指向错误信息
char **result;//相当于二维数组 保存查询到的信息
int nrow,ncolumn;//分别代表行和列
ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg);
int j,i;
int Index = ncolumn;
int ret1,ret2;
printf("已进行遍历数据库\n");
for(i = 0 ; i < nrow+1;i++)
{
ret1 = (strcmp(result[i*ncolumn + 0],p->name));
ret2 = (strcmp(result[i*ncolumn + 1],p->password));
printf("正在进行账户密码效验\n");
printf("账户:%s\n",result[i*ncolumn + 0]);
printf("密码:%s\n",result[i*ncolumn + 1]);
printf("密码:%s\n",p->password);
if(0 == ret1 && 0 == ret2)
{
flag = 1;
break;
}//0行就是第一行 第i行第j列
}
if(flag == 1)
{ printf("核对返回值为%d\n",flag);
sqlite3_free_table(result);//释放数据库
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite3_close:");
exit(1);
}
return flag;
}
else{
flag = 0;
sqlite3_free_table(result);//释放数据库
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite3_close:");
exit(1);
}
return flag;
}
}
2.11在数据库中查找用户是否存在
//在数据库查询用户 c存在返回1 不存在返回0
int searchtable(char *tablename)
{
int flag;
sqlite3 *db = NULL;
int ret = sqlite3_open("user.db",&db);
if(SQLITE_OK != ret)
{
perror("sqlite3_open");
exit(1);
}
char sql[200] = "\0";
sprintf(sql,"select *from user;");
char *errmsg;//定义指着指向错误信息
char **result;//相当于二维数组 保存查询到的信息
int nrow,ncolumn;//分别代表行和列
ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg);
int j,i;
int Index = ncolumn;
for(i = 1 ; i < nrow+1;i++)
{
int ret = strcmp(result[i*ncolumn + 0],tablename);
if(ret == 0)
{
flag = 1;
}//0行就是第一行 第i行第j列
}
if(flag == 1)
{ printf("数据库是否存在该用户%d存在\n",flag);
sqlite3_free_table(result);//释放数据库
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite3_close:");
exit(1);
}
return flag;
}
else
{
flag = 0;
printf("%d\n",flag);
sqlite3_free_table(result);//释放数据库
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite3_close:");
exit(1);
}
return flag;
}
}
2.12 私聊功能
//私聊功能
void privatechat(thread_node *node,clientlist *c)
{
int flag = 0;
printf("正在运行私聊函数\n");
int to_cfd = Find_person(node,c); //在线返回对方的文件描述符
printf("私聊对象的文件描述符为%d\n",to_cfd);
if(0 == to_cfd)
{
char buf[32] = "对方不在线...";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
else
{
if(0 == flag)
{
char buf1[128] = "\0";
sprintf(buf1,"[系统日志]:正在与%s进行私聊",c->to_name);
if(send(node->cfd,buf1,sizeof(buf1),0) == -1)
{
ERRLOG("send error");
}
flag++;
}
printf("正在进行消息:%s转发\n",c->msg);
char buf[128] = "\0";
sprintf(buf,"[%s悄悄对你说了一句]:%s",c->name,c->msg);
if(send(to_cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
}
2.13判断用户是否在线
//判断是否在线 在线返回对方文件描述符 不在线返回0
int Find_person(thread_node *node,clientlist *c)
{
char s1[32]={0};
strcpy(s1,c->to_name);//想跟s1进行私聊
printf("正在判断%s是否在线\n",c->to_name);
online_userlist *p = node->head;
while(p!=NULL)
{
if(strcmp(s1,p->name) == 0 )
{ printf("%s在线\n",p->name);
return p->c_fd;//私聊对象的文件描述符
}
p=p->next;
}
return 0;
}
2.14 修改密码
//修改密码
void changepassword(thread_node *node,clientlist *c)
{
printf("用户%s将吧密码修改为%s",c->name,c->msg);
Insert_updated_data(c->name,c->msg);
char buf1[600] = "\0";
sprintf(buf1,"[系统日志]:密码修改成功");
if(send(node->cfd,buf1,sizeof(buf1),0) == -1)
{
ERRLOG("send error");
}
printf("用户%s已成功修改密码",c->name);
exituser(node,c);
}
2.15 进行群聊
//功能标志5 进行群聊
void groupchat(thread_node *node,clientlist *c)
{
printf("正在运行管理员群聊函数\n");
online_userlist *p = node->head;
int ret;
ret = onlineempty1(p);
if(1 == ret)
{
char buf1[128] = "\0";
strcpy(buf1,"[系统日志]:当前没有别的用户在线");
if(send(node->cfd,buf1,sizeof(buf1),0) == -1)
{
ERRLOG("send error");
}
return;
}
printf("正在遍历链表给每个用户发送消息\n");
printf("打印管路员标志%d\n",c->root);
if(c->root == 1)
{
getheadflag(c);//获取管理员头像
printf("打印管理员头像%s\n",c->emojio);
p=p->next;
while(p!=NULL)//如果用p->next!=NULL 当p在最后一个结点是 p->next=NULL 无法进入循环
{
if(p->c_fd != 0)
{ printf("打印文件描述符%d \n",p->c_fd);
char buf[128] = "\0";
sprintf(buf,"%s[%s]:%s",c->emojio,c->name,c->msg);
if(send(p->c_fd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
memset(buf,0,sizeof(buf));
}
p=p->next;
}
}
else
{
p=p->next;
while(p!=NULL)//如果用p->next!=NULL 当p在最后一个结点是 p->next=NULL 无法进入循环
{
if(p->c_fd != 0)
{ printf("打印文件描述符%d \n",p->c_fd);
char buf[100] = "\0";
sprintf(buf,"[%s]:%s",c->name,c->msg);
if(send(p->c_fd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
memset(buf,0,sizeof(buf));
}
p=p->next;
}
}
}
2.16退出群聊 将链表节点删除
//退出群聊 删除链表内的用户结点
void exituser(thread_node *node,clientlist *c)
{
online_userlist *p = node->head;
online_userlist *q;
while(p->next!=NULL)
{
if(strcmp(c->name,p->next->name)==0)
{
q=p->next;
p->next=p->next->next;
free(q);
q=NULL;
printf("将%s踢出链表成功\n",c->name);
return;
}
p=p->next;
}
}
2.17 查看在线用户
//查看所有在线用户
void viewonline_user(thread_node *node,clientlist *c)
{
online_userlist *p = node->head->next;
int ret;
ret = onlineempty(p);
if(1 == ret)
{
char buf1[128] = "\0";
strcpy(buf1,"[系统日志]:当前没有别的用户在线");
if(send(node->cfd,buf1,sizeof(buf1),0) == -1)
{
ERRLOG("send error");
}
return;
}
while(p!=NULL)//如果用p->next!=NULL 当p在最后一个结点是 p->next=NULL 无法进入循环
{
if(p->c_fd != 0)
{
char buf[70] = {0};
memset(buf,0,sizeof(buf));
printf("%s当前在线3\n",p->name);
sprintf(buf,"[%s]:当前在线",p->name);
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
sleep(1);
}
p=p->next;
}
}
2.19 注销用户
//注销用户
void loguser(thread_node *node,clientlist *c)
{
deleteuser(c);
if(c->root == 1)
{
deleteroot(c);
}
printf("注销用户删除数据库成功\n");
char buf[32] = "注销成功..";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
exituser(node,c);
printf("注销用户删除链表结点成功\n");
}
2.20保存聊天记录
//将聊天记录插入记录表(保存聊天记录)
void insert_uprecord(thread_node *node,clientlist *c)
{
printf("正在进行聊天记录存储\n");
printf("聊天方式标志位:%d",c->flag);
printf("聊天内容:%s",c->msg);
time_t timep;
struct tm *p;
time (&timep);
p=gmtime(&timep);
char newtime[32] = {0};
sprintf(newtime,"%d-%d-%d:%d:%d\n",1+p->tm_mon,p->tm_mday,8+p->tm_hour,p->tm_min,p->tm_sec);
printf("获取时间%s\n",newtime);
int cc=1;
char *errmsg;
sqlite3 *db =NULL;
char sql[200] = "\0";
memset(sql,0,sizeof(sql));//清空sql
pthread_mutex_lock(&mutex);
sprintf(sql,"insert into record(time,name,record) values('%s','%s','%s')",newtime,c->name,c->msg);
printf("数据库sql语句测试\n");
execstate(sql);
pthread_mutex_unlock(&mutex);
printf("\033[0;34m聊天记录保存成功\033\n");
}
2.21 重复登录判断
//重复登录判断
int Repeatlogin(thread_node *node,clientlist *c)
{
printf("正在判断是否重复登录\n");
char s1[32]={0};
strcpy(s1,c->name);//判断自己是否登录
printf("正在判断%s是否在线\n",c->to_name);
online_userlist *p = node->head;
while(p!=NULL)
{
if(strcmp(s1,p->name) == 0 )
{ printf("%s在线,重复登录\n",p->name);
char buf[32] = "您已在线,请勿重复登录";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
return 0;
}
p=p->next;
}
printf("未遍历到该用户,可以进行登录\n");
return 1;
}
2.22查看聊天记录
//查看聊天记录
void Checkrecord(thread_node *node)
{
printf("已进入聊天记录返回客户端工作\n");
int flag;
sqlite3 *db = NULL;
int ret = sqlite3_open("user.db",&db);
if(SQLITE_OK != ret)
{
perror("sqlite3_open");
exit(1);
}
printf("已打开数据库\n");
char sql[200] = "\0";
sprintf(sql,"select *from record;");
char *errmsg;//定义指着指向错误信息
char **result;//相当于二维数组 保存查询到的信息
int nrow,ncolumn;//分别代表行和列
ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg);
int j,i;
int Index = ncolumn;
int ret1,ret2;
printf("已进行遍历数据库\n");
char buf[256] = {0};
for(i = 1 ; i < nrow+1;i++)
{
printf("正在将聊天记录发送给客户端\n");
sprintf(buf,"%s\n[%s]:%s",result[i*ncolumn + 0],result[i*ncolumn + 1],result[i*ncolumn + 2]);
printf("时间:%s\n",result[i*ncolumn + 0]);
printf("用户:%s\n",result[i*ncolumn + 1]);
printf("消息内容:%s\n",result[i*ncolumn + 2]);
printf("%s",buf);
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
}
2.23 文件传输
//文件传输
void filetransfer(thread_node *node,clientlist *c)
{
MSG msg;
printf("正在运行文件传输函数\n");
int to_cfd = Find_person(node,c); //在线返回对方的文件描述符
printf("私聊对象的文件描述符为%d\n",to_cfd);
char buf[256] = "\0";
printf("***********11111\n");
printf("%s",c->buf);
printf("***********22222\n");
strcpy(msg.text,c->buf);
msg.num = c->num;
if(0 == to_cfd)
{
char buf1[32] = "对方不在线...";
if(send(node->cfd,buf1,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
else
{
while(flag2)
{
printf("正在向对方发送文件传输信号\n");
if(send(to_cfd,"文件存在进行文件传输",N,0) == -1)
{
ERRLOG("send error");
}
flag2 = 0;
}
if(strcmp(buf,"0") == 0)
{
printf("文件内容全部发送完成\n");
flag2 = 1;
}
sleep(1);
printf("本次向对方送的内容%s\n",msg.text);
if(send(to_cfd,&msg,sizeof(msg),0) == -1)
{
ERRLOG("send error");
}
printf("单次发送内容完成\n");
memset(&msg,0,sizeof(msg));
}
2.24管理员用户申请
//管理员用户的申请
void applyroot(thread_node *node,clientlist *c)
{
printf("正在判断:%s 是否已经是管理员\n",c->name);
int ret = searchtableroot(c->name);
printf("%d",ret);
if(1 == ret)
{
char arr[128] = {"您已是管理员.."};
if(send(node->cfd,arr,sizeof(arr),0) == -1)
{
ERRLOG("send error");
}
return;
}
else
{
insert_updataroot(node,c);
}
}
2.25 在数据库中管理员表中查看是否存在该管理员
//在数据库中管理员表中查看是否存在该管理员
int searchtableroot(char *tablename)
{
int flag;
sqlite3 *db = NULL;
int ret = sqlite3_open("user.db",&db);
if(SQLITE_OK != ret)
{
perror("sqlite3_open");
exit(1);
}
char sql[200] = "\0";
sprintf(sql,"select *from root;");
char *errmsg;//定义指着指向错误信息
char **result;//相当于二维数组 保存查询到的信息
int nrow,ncolumn;//分别代表行和列
ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg);
int j,i;
int Index = ncolumn;
for(i = 1 ; i < nrow+1;i++)
{
int ret = strcmp(result[i*ncolumn + 1],tablename);
if(ret == 0)
{
flag = 1;
}//0行就是第一行 第i行第j列
}
if(flag == 1)
{ printf("root表中该用户%d存在\n",flag);
sqlite3_free_table(result);//释放数据库
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite3_close:");
exit(1);
}
return flag;
}
else
{
printf("root表中该用户%d不存在\n",flag);
flag = 0;
printf("%d\n",flag);
sqlite3_free_table(result);//释放数据库
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite3_close:");
exit(1);
}
return flag;
}
}
2.26//向管理员表中插入数据
//向root表中插入数据
void insert_updataroot(thread_node *node,clientlist *c)
{
printf("申请管理员的用户%s\n",c->name);
char *errmsg;
sqlite3 *db =NULL;
char sql[200] = "\0";
memset(sql,0,sizeof(sql));//清空sql
pthread_mutex_lock(&mutex);
sprintf(sql,"insert into root(head,name,password) values('%s','%s','%s');",c->emojio,c->name,c->password);
printf("将 头像:%s,名字;%s,密码:%s 插入表中\n",c->emojio,c->name,c->password);
execstate(sql);
pthread_mutex_unlock(&mutex);
printf("\033[0;34m插入成功\033\n");
char buf[100] = {"管理员申请成功"};
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
exituser(node,c);//注册完将其踢出链表让其进入初始界面从新登录
return;
}
2.28 管理员登录
//管理员登录
void rootlogin(thread_node *node,clientlist *c)
{
if(0 == (rootsearch(c->name)))
{
char buf[32] = "该用户非管理员";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
else if( 0 == (rootveridandpassword(c)))//密码错误
{
char buf[20] = "密码输入错误";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
else if(1 == (rootveridandpassword(c)))//返回值为1账号密码正确
{
if(rootRepeatlogin(node,c))
{
online_insertion(node,c);
char buf[32] = "管理员登录成功..";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
online_userlist *p = node->head;
p=p->next;
while(p!=NULL)//如果用p->next!=NULL 当p在最后一个结点是 p->next=NULL 无法进入循环
{
if(p->c_fd != 0)
{
char buf[70] = "\0";
sprintf(buf,"%s[%s]:上线了",c->emojio,c->name);
if(send(p->c_fd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
memset(buf,0,sizeof(buf));
}
p=p->next;
}
}
else
{
return;
}
}
}
2.29//在root表中查看该用户是否为管理员
//在root表中查看该用户是否为管理员
int rootsearch(char *tablename)
{
int flag;
sqlite3 *db = NULL;
int ret = sqlite3_open("user.db",&db);
if(SQLITE_OK != ret)
{
perror("sqlite3_open");
exit(1);
}
char sql[200] = "\0";
sprintf(sql,"select *from root;");
char *errmsg;//定义指着指向错误信息
char **result;//相当于二维数组 保存查询到的信息
int nrow,ncolumn;//分别代表行和列
ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg);
int j,i;
int Index = ncolumn;
for(i = 1 ; i < nrow+1;i++)
{
int ret = strcmp(result[i*ncolumn + 1],tablename);
if(ret == 0)
{
flag = 1;
}//0行就是第一行 第i行第j列
}
if(flag == 1)
{ printf("数据库是否存在该用户%d存在\n",flag);
sqlite3_free_table(result);//释放数据库
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite3_close:");
exit(1);
}
return flag;
}
else
{
flag = 0;
printf("%d\n",flag);
sqlite3_free_table(result);//释放数据库
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite3_close:");
exit(1);
}
return flag;
}
}
2.30/判断管理员用户与密码是否正确
//判断管理员用户与密码
int rootveridandpassword(clientlist *c)
{
printf("已进入管理员的密码效验工作\n");
int flag;
sqlite3 *db = NULL; //数据库的名字记得更换
int ret = sqlite3_open("user.db",&db);
if(SQLITE_OK != ret)
{
perror("sqlite3_open");
exit(1);
}
printf("已打开数据库\n");
char sql[200] = "\0";
sprintf(sql,"select *from root;");
char *errmsg;//定义指着指向错误信息
char **result;//相当于二维数组 保存查询到的信息
int nrow,ncolumn;//分别代表行和列
ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg);
int j,i;
int Index = ncolumn;
int ret1,ret2;
printf("已进行遍历数据库\n");
for(i = 0 ; i < nrow+1;i++)
{
ret1 = (strcmp(result[i*ncolumn + 1],c->name));
ret2 = (strcmp(result[i*ncolumn + 2],c->password));
printf("正在进行账户密码效验\n");
printf("账户:%s\n",result[i*ncolumn + 1]);
printf("密码:%s\n",result[i*ncolumn + 2]);
printf("密码:%s\n",c->password);
if(0 == ret1 && 0 == ret2)
{
strcpy(c->emojio,result[i*ncolumn + 0]);
printf("打印管理员存在数据库中的头像%s",result[i*ncolumn + 0]);
printf("打印被赋值后的当前结构体头像%s",c->emojio);
flag = 1;
break;
}//0行就是第一行 第i行第j列
}
if(flag == 1)
{ printf("核对返回值为%d\n",flag);
sqlite3_free_table(result);//释放数据库
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite3_close:");
exit(1);
}
return flag;
}
else{
flag = 0;
sqlite3_free_table(result);//释放数据库
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite3_close:");
exit(1);
}
return flag;
}
}
2.31//管理员重复登录判断
//管理员重复登录判断
int rootRepeatlogin(thread_node *node,clientlist *c)
{
printf("正在判断是否重复登录\n");
char s1[32]={0};
strcpy(s1,c->name);//判断自己是否登录
printf("正在判断%s是否在线\n",c->to_name);
online_userlist *p = node->head;
while(p!=NULL)
{
if(strcmp(s1,p->name) == 0 )
{ printf("%s在线,重复登录\n",p->name);
char buf[32] = "您已在线,请勿重复登录";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
return 0;
}
p=p->next;
}
printf("未遍历到该用户,可以进行登录\n");
return 1;
}
2.32管理员踢人
//管理员踢人
void rootkick(thread_node *node,clientlist *c)
{
int to_cfd = Find_person(node,c); //在线返回对方的文件描述符
printf("踢出对象的文件描述符为%d\n",to_cfd);
if(0 == to_cfd)
{
char buf[32] = "对方不在线...";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
else
{
if(searchtableroot(c->to_name) == 1)
{
char buf[128] = "对方是管理员,无法进行操作";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
return;
}
else
{
char buf[128] = "管理员已将你踢出聊天室";
if(send(to_cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
}
}
2.33管理员禁言
//管理员禁言
void silent(thread_node *node,clientlist *c)
{
int to_cfd = Find_person(node,c); //在线返回对方的文件描述符
printf("禁言对象的文件描述符为%d\n",to_cfd);
if(0 == to_cfd)
{
char buf[32] = "对方不在线...";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
else
{
if(searchtableroot(c->to_name) == 1)
{
char buf[128] = "对方是管理员,无法进行操作";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
return;
}
else
{
char buf[128] = "管理员已将你禁言";
if(send(to_cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
}
}
2.34解除禁言
//管理员解除禁言
void remsilent(thread_node *node,clientlist *c)
{
int to_cfd = Find_person(node,c); //在线返回对方的文件描述符
printf("解除禁言对象的文件描述符为%d\n",to_cfd);
if(0 == to_cfd)
{
char buf[32] = "对方不在线...";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
else
{
char buf[128] = "管理员已将你解除禁言";
if(send(to_cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
}
}
2.35 //获取管理员头像
//获取管理员头像
void getheadflag(clientlist *c)
{
int flag;
sqlite3 *db = NULL;
int ret = sqlite3_open("user.db",&db);
if(SQLITE_OK != ret)
{
perror("sqlite3_open");
exit(1);
}
char sql[200] = "\0";
sprintf(sql,"select *from root;");
char *errmsg;//定义指着指向错误信息
char **result;//相当于二维数组 保存查询到的信息
int nrow,ncolumn;//分别代表行和列
ret = sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg);
int j,i;
int Index = ncolumn;
for(i = 1 ; i < nrow+1;i++)
{
int ret = strcmp(result[i*ncolumn + 1],c->name);
if(ret == 0)
{ strcpy(c->emojio,result[i*ncolumn + 0]);
flag = 1;
printf("当前管理员头像%s\n",result[i*ncolumn + 0]);
printf("c->emojio=%s\n",c->emojio);
}//0行就是第一行 第i行第j列
}
if(flag == 1)
{ printf("管理员头像获取成功%s存在\n",c->emojio);
sqlite3_free_table(result);//释放数据库
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite3_close:");
exit(1);
}
return;
}
else
{
printf("管理员头像获取失败%d不存在\n",flag);
flag = 0;
printf("%d\n",flag);
sqlite3_free_table(result);//释放数据库
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite3_close:");
exit(1);
}
return;
}
}
2.36创建表
//创建表 注意更换数据库
void createtable()
{
sqlite3 *db = NULL; //目标数据库
int ret = sqlite3_open("user.db",&db);
if(SQLITE_OK != ret)
{
perror("sqlite3_open");
exit(1);
}
char *errmsg;
char sql[500] = "\0";
strcpy(sql,"create table user (name text,password text);");
ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
if(SQLITE_OK != ret)
{
perror("sqlite3_exec:");
printf("errmsg:%s\n",errmsg);
exit(1);
}
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite3_close:");
exit(1);
}
return;
}
2.37执行sql语句函数
//执行sql语句函数
void execstate(char *sql)//执行SQL语句
{
sqlite3 *db =NULL;
int ret = sqlite3_open("user.db",&db);
if(SQLITE_OK != ret)
{
ERRLOG("sqlite3_open");
}
char *errmsg;
ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
if(SQLITE_OK != ret)
{
ERRLOG("sqlite3_exec");
}
ret = sqlite3_close(db);
if(SQLITE_OK != ret)
{
perror("sqlite_close:");
exit(1);
}
}
2.38//根据名字修改密码
//根据名字修改密码
void Insert_updated_data(char *name,char *password)
{
char sql[500] = "\0";
sprintf(sql,"update user set password = '%s' where name = '%s';",password,name);
execstate(sql);
}
2.39指定删除普通用户的中数据
//指定删除数据库里面的用户
void deleteuser(clientlist *c)
{
char sql[200] = "\0";
memset(sql,0,sizeof(sql));//清空sql
sprintf(sql,"delete from user where name = '%s';",c->name);
execstate(sql);
printf("删除数据库内容成功\n");
}
2.40指定删除管理员表中的数据
//指定删除数据库里面的用户
void deleteroot(clientlist *c)
{
char sql[200] = "\0";
memset(sql,0,sizeof(sql));//清空sql
sprintf(sql,"delete from root where name = '%s';",c->name);
execstate(sql);
printf("删除root内容成功\n");
}
2.41撤销管理员身份
//功能标志15 撤销管理员身份
void cancelroot(thread_node *node,clientlist *c)// 功能标志15 撤销管理员身份
{
char buf[128] = "撤销成功";
if(send(node->cfd,buf,sizeof(buf),0) == -1)
{
ERRLOG("send error");
}
deleteroot(c);
exituser(node,c);
return;
}
2.42判断链表是否为空
//判断链表是否为空
int onlineempty(online_userlist *head)
{
if (head->next==NULL)
{
return 1 ;
}
else
{
return 0;
}
}
//判断除自己是否还有别人在线
int onlineempty1(online_userlist *head)
{
if (head->next->next==NULL)
{
return 1 ;
}
else
{
return 0;
}
}
chatroom.h
#ifndef _CHATROOM_H
#define _CAHTROOM_H
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <sqlite3.h>
#include <time.h>
#define N 256
#define ERRLOG(errmsg) do{\
perror(errmsg);\
printf("%s - %s - %d\n",__FILE__,__func__,__LINE__);\
exit(1);\
}while(0)
#define MAXLINE 8192
pthread_mutex_t mutex;
typedef struct client
{
int flag; //功能标志 注册标志1 登录2 私聊3 修改密码4 群聊界面5 查看在线用户6 注销用户7 查看聊天记录8 下载文件9
char emojio[20];//头像保存
char name[32];//姓名
int root; //管理员标志
char msg[50];//聊天内容
char password[32];//密码
char to_name[50];//聊天对象
char buf[256];//文件内容
int num;
}clientlist;
typedef struct file
{
char text[N];
int num;
}MSG;
typedef struct online_user
{
char name[32];//姓名
int c_fd;
struct online_user*next; //指针域
}online_userlist;
typedef struct thread_node
{
int cfd;
online_userlist *head;
}thread_node;
//在线用户链表
online_userlist* online_userlistcreate();
int sockfd;
pthread_t pti1[500];//线程号数组用于保存accept线程号
void Init();//初始化 创建套接字等
void server();//accept接受创建线程
void *myfun(void *arg);//进入线程函数
void messagehand(thread_node *node);//接受消息 判断功能标志位
void insert_updata(thread_node *node,clientlist *c);//向数据库中插入
int searchtable(char *tablename);//在数据库查询用户 存在返回1 不存在返回0
void execstate(char *sql);//执行sql语句
int veridandpassword(clientlist *p);//判断账户密码是否正确 正确返回1错误返回0
void Register(thread_node *node,clientlist *c); //注册 判断是否已经存在 不存在进行插入数据库
int onlineempty(online_userlist *head);//判断链表是否为空
void login(thread_node *node,clientlist *c);//用户登录
//将登录用户添加至链表
void online_insertion(thread_node *node,clientlist *c);//登录用户插入链表
int Find_person(thread_node *node,clientlist *c);判断是否在线 在线返回对方文件描述符
void privatechat(thread_node *node,clientlist *c);//私聊
void changepassword(thread_node *node,clientlist *c);
void Insert_updated_data(char *name,char *password);//在数据库中按照名字修改密码
void groupchat(thread_node *node,clientlist *c);//进行群聊
int onlineempty1(online_userlist *head);//判断除了自己之外是否还要有别人在线
void exituser(thread_node *node,clientlist *c);//将退出聊天室的用户删除结点
void viewonline_user(thread_node *node,clientlist *c);//功能 标志查看所有在线用户
void deleteuser(clientlist *c);//指定删除数据库内用
void loguser(thread_node *node,clientlist *c);//注销用户
void insert_uprecord(thread_node *node,clientlist *c);//将聊天记录保存至数据库
int Repeatlogin(thread_node *node,clientlist *c);//判断是否重复登录
void Checkrecord(thread_node *node);//查看聊天记录
void filetransfer(thread_node *node,clientlist *c);//文件传输
void applyroot(thread_node *node,clientlist *c);//申请管理员用户
int searchtableroot(char *tablename);//判断该用户是否是已经是管理员
void insert_updataroot(thread_node *node,clientlist *c);//向管理员表中插入管理员资料
void rootlogin(thread_node *node,clientlist *c);//管理员登录
int rootsearch(char *tablename);//在root表中查看该用户是否为管理员
int rootveridandpassword(clientlist *p);//判断管理员密码
void rootkick(thread_node *node,clientlist *c);//管理员踢人
void silent(thread_node *node,clientlist *c);//管理员禁言
void remsilent(thread_node *node,clientlist *c);//管理员解除禁言
void getheadflag(clientlist *c);//获取管理员头像
int rootRepeatlogin(thread_node *node,clientlist *c);//管理员重复登录
void deleteroot(clientlist *c);//指定删除root表中的用户
void cancelroot(thread_node *node,clientlist *c);//取消管理员身份
#endif
2.客户端
client.c
#include "clientaddr.h"
unsigned char ip_str[] = "192.168.91.151";
unsigned char port_str[] = "8787";
int flag1 = 0;
int flag2 = 1;
void n_init()//客户端初始化框架
{
clientfd2 = socket(AF_INET,SOCK_STREAM,0);
if(clientfd2 == -1)
{
perror("socket");
return;
}
struct sockaddr_in clientaddr;
clientaddr.sin_family = AF_INET;//协议族 IPV4
clientaddr.sin_addr.s_addr = inet_addr(ip_str);
/*in_addr_t inet_addr(const char *cp);将点分十进制字符串ip地址转化为网络序的无符号4字节
整数ip地址*/
int addrlen = sizeof(clientaddr);
clientaddr.sin_port = htons(atoi(port_str));
if(connect(clientfd2,(struct sockaddr *)&clientaddr,addrlen)==-1)
{
perror("\033[0;31m无法连接到服务器\033[0m\n");
ERRLOG("connect");
}
return;
}
void selectfun()//进入页面选着功能
{
usleep(500*1000);
system("clear");
printf("\033[0;46m*===================================================================*\033[0m\n");
printf("\033[0;46m| |\033[0m\n");
printf("\033[0;46m|*********************\033[0;33m欢迎来到防脱发研究中心\033[0;46m************************|\033[0m\n");
printf("\033[0;46m| 作者:爱码士 |\033[0m\n");
printf("\033[0;46m|-------------------------------------------------------------------|\033[0m\n");
printf("\033[0;46m| |\033[0m\n");
printf("\033[0;46m| \033[0;35m1.用户登录💩\033[0;46m |\033[0m\n");
printf("\033[0;46m| |\033[0m\n");
printf("\033[0;46m| \033[0;32m2.帐号注册👾\033[0;46m |\033[0m\n");
printf("\033[0;46m| |\033[0m\n");
printf("\033[0;46m| \033[0;33m3.管理员登录🐯\033[0;46m |\033[0m\n");
printf("\033[0;46m| |\033[0m\n");
printf("\033[0;46m| \033[0;31m 0:退出聊天室🐴\033[0;46m |\033[0m\n");
printf("\033[0;46m| |\033[0m\n");
printf("\033[0;46m*===================================================================*\033[0m\n");
printf("\n");
int num;
scanf("%d",&num);
getchar();
switch (num)
{
case 0:
exit_room();//退出聊天室
break;
case 1:
system("clear");
printf("\033[0;31m正在进行用户登录..\033[0m\n");
system("./zjn");
user_login();//登录
break;
case 2:
system("clear");
printf("\033[0;31m正在进行账号注册\033[0m\n");
user_register();//返回注册页面
selectfun();
break;
case 3:
system("clear");
printf("\033[0;31m正在进行管理员登录\033[0m\n");
rootlogin();
putchar(10);
break;
case 4:
system("clear");
printf("\033[0;31m正在退出聊天室\033[0m\n");
exit_room();
putchar(10);
break;
default:
system("clear");
printf("\033[0;31m对不起输入错误请从新输入..\033[0m\n");
selectfun();
return;
}
}
void funcinto()//第二阶段选择进入
{
system("clear");
printf("\033[34m \033[0;36m<1:私聊功能>🐱\033[0;34m \033[0m\n");
putchar(10);
printf("\033[34m \033[0;36m🐒<2:进入群聊>\033[0;34m \033[0m\n");
putchar(10);
printf("\033[34m \033[0;36m<3:修改密码>🐶\033[0;34m \033[0m\n");
putchar(10);
printf("\033[0;31m \033[0;36m🐩<4:查看当前在看用户>\033[0;34m \033[0m\n");
putchar(10);
printf("\033[34m \033[0;31m<5:注销用户>🦒\033[0;34m \033[0m\n");
putchar(10);
printf("\033[33m \033[0;33m🐴<6:申请称为管理员>\033[0;34m \033[0m\n");
putchar(10);
printf("\033[34m \033[0;33m🐆<0:退出聊天室>\033[0;34m \033[0m\n");
int num;
scanf("%d",&num);
getchar();
switch (num)
{
case 0:
printf("\033[0;31m正在退出聊天室..\033[0m\n");
exit_room();
putchar(10);
break;
case 1:
system("clear");
printf("\033[0;31m正在进入私聊功能..\033[0m\n");
privatechat();
funcinto();
break;
case 2:
system("clear");
printf("\033[0;31m正在入群聊功能\033[0m\n");
groupchat();
funcinto();
break;
case 3:
system("clear");
printf("\033[0;31m正在进行修改密码\033[0m\n");
changpassword();
selectfun();
putchar(10);
break;
case 4:
system("clear");
printf("\033[0;31m正在查看在线用户\033[0m\n");
viewonline_user();
sleep(3);
funcinto();
break;
case 5:
system("clear");
printf("\033[0;31m正在进行注销用户\033[0m\n");
deleteuser();
sleep(1);
selectfun();
putchar(10);
break;
case 6:
system("clear");
printf("\033[0;31m正在申请成为管理员\033[0m\n");
applyroot();
putchar(10);
break;
default:
system("clear");
printf("\033[0;31m对不起输入错误请从新输入..\033[0m\n");
funcinto();
return;
}
}
void user_register()//功能标志1 用户注册
{
ssize_t ret;
char password[50];
system("clear");
printf("\033[0;31m请输入你的名字..\033[0m\n");
scanf("%s",ts.name);
system("clear");
printf("\033[0;31m请输入你的密码\033[0m\n");
system("stty -echo");
scanf("%s",password);
system("stty echo");
system("clear");
printf("\033[0;31m请再次确认你的密码\033[0m\n");
system("stty -echo");
scanf("%s",ts.password);
system("stty echo");
if(strcmp(password,ts.password) == 0)
{
system("./zjn");
ts.flag = 1;
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
return;
}
else
{
printf("\033[0;31m输入密码不一致请从新输入...\033[0m\n");
sleep(1);
user_register(ts);
}
}
void user_login()//功能标志 2用户登录
{
ssize_t ret;
system("clear");
printf("\033[0;31m请输入你的名字..\033[0m\n");
scanf("%s",ts.name);
system("clear");
printf("\033[0;31m请输入你的密码\033[0m\n");
system("stty -echo");
scanf("%s",ts.password);
sleep(1);
system("stty echo");
ts.flag = 2; //用户登录标志位
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
sleep(1);
if(1==flag1)
{
flag1 = 0;
selectfun();
}
if(0 == flag1)
{
funcinto();
}
return;
}
void privatechat()// 功能标志3 用户私聊
{
ssize_t ret;
char to_name[50];
system("clear");
printf("\033[0;31m请输入你想私聊的对象..\033[0m\n");
scanf("%s",ts.to_name);
sleep(1);
system("clear");
ts.flag = 3; //私聊标志为3
char buf[200] = "\0";
char *buf2;
system("clear");
printf("\033[0;31m请输入聊天内容..\033[0m\n"); //循环聊天记得加循环
printf("\033[0;31m <输入Q!退出私聊>\033[0m\n");
printf("\033[0;31m <输入W!查看快捷短语>\033[0m\n");
printf("\033[0;31m [当前用户]:%s\033[0m\n",ts.name);
while(1)
{
scanf("%s",buf);
if(strcmp(buf,"Q!") == 0)
{
system("clear");
return;
}
if(strcmp(buf,"W!") == 0)
{
phrase();
continue;
}
if(flag2)
{
if((buf2 = selectphrase(buf)) == NULL)
{
strcpy(ts.msg,buf);
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
}
else
{
strcpy(ts.msg,buf2);
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
}
}
}
return;
}
void changpassword()//功能标志4 修改密码
{
ssize_t ret;
char newpassword[50];
char password[50];
system("clear");
printf("\033[0;31m请输入你的新密码\033[0m\n");
system("stty -echo");
scanf("%s",newpassword);
system("stty echo");
system("clear");
printf("\033[0;31m请再次确认你的密码\033[0m\n");
system("stty -echo");
scanf("%s",password);
system("stty echo");
if(strcmp(password,newpassword) == 0)
{ strcpy(ts.msg,newpassword);
system("./zjn");
ts.flag = 4;
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
return;
}
else
{
printf("\033[0;31m输入密码不一致请从新输入...\033[0m\n");
sleep(1);
changpassword();
}
}
void groupchat() //功能标志5 群聊 显示群聊界面
{
int num = 0;
ssize_t ret;
system("./zjn");
ts.flag = 5; //私聊标志为5
char buf[200] = "\0";
char *buf2;
system("clear");
printf("\033[0;31m请输入聊天内容..\033[0m\n"); //循环聊天记得加循环
printf("\033[0;31m <输入Q!退出群聊>\033[0m\n");
printf("\033[0;36m <输入W!查看快捷短语>\033[0m\n");
printf("\033[0;36m <输入C!查看聊天记录>\033[0m\n");
printf("\033[0;36m <输入T!进行文件传输>\033[0m\n");
printf("\033[0;31m [当前用户]:%s\033[0m\n",ts.name);
while(1)
{
scanf("%s",buf);
if(strcmp(buf,"Q!") == 0)
{
system("clear");
return;
}
if(strcmp(buf,"W!") == 0)
{
phrase();
printf("\033[0;32m请输入1继续群聊..\033[0m\n");
scanf("%d",&num);
if(1 == num)
{
break;
}
else
{
printf("\033[0;32m输入错误\033[0m\n");
}
}
if(strcmp(buf,"C!") == 0)
{
checkrecord();
printf("\033[0;32m请输入1继续群聊..\033[0m\n");
scanf("%d",&num);
if(1 == num)
{
break;
}
else
{
printf("\033[0;32m输入错误\033[0m\n");
}
}
if(strcmp(buf,"T!") == 0)
{
filetransfer();
sleep(1);
break;
}
if(flag2)
{
if((buf2 = selectphrase(buf)) == NULL)
{
strcpy(ts.msg,buf);
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
}
else
{
strcpy(ts.msg,buf2);
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
}
}
}
groupchat();
}
void viewonline_user()//功能标志6 查看所有在线用户
{
ts.flag = 6;
int ret;
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
return;
}
void deleteuser() //功能标志 7 注销用户
{
char password[30] = {0};
char name[30] = {0};
printf("\033[0;31m 请认真确认你的用户信息\033[0m\n");
printf("\033[0;31m<输入姓名>\033[0m\n");
scanf("%s",name);
system("clear");
printf("\033[0;31m<输入密码>\033[0m\n");
scanf("%s",password);
int ret1,ret2;
ret1 = strcmp(name,ts.name);
ret2 = strcmp(password,ts.password);
if(0 == ret1 && 0 == ret2)
{
ts.flag = 7;
int ret;
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
}
}
void phrase()//快捷短语打印
{
printf("\033[34m \033[0;36m🐒<快捷短语大全>\033[0;34m \033[0m\n");
putchar(10);
printf("\033[34m \033[0;36m1.<听说jsetc给分配对象?😍>\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m2.<😅>\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m3.<😘>\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m4.<🤨>\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m5.<😁>\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m6.<真男人从不食💩,只食💨>\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m7.<👾>\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m8.< 嘟嘟嘟!! 🚋 The car is coming>\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m9.<就这么点👌?>\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m10.< 来🍇🍈🍊🍋多吃点,别让人看扁 >\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m11.<顺便给你分配个👩🍳>\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m12.< Other people's money is my belongings😛 >\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m13.<Are you a dog?🐶>\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m14.<你是个什么🐮🐎>\033[0;34m \033[0m\n");
printf("\033[34m \033[0;36m15.<一个巴掌拍不响但是加上一个🍑可以>\033[0;34m \033[0m\n");
}
char *selectphrase(char *num)//快捷短语选择
{
char *buf;
buf = (char *)malloc(32);
if(strcmp(num,"1.")==0)
{
strcpy(buf,"听说jsetc给分配对象?😍");
return buf;
}
if(strcmp(num,"2.")==0)
{
strcpy(buf,"😅");
return buf;
}
if(strcmp(num,"3.")==0)
{
strcpy(buf,"😘");
return buf;
}
if(strcmp(num,"4.")==0)
{
strcpy(buf,"🤨");
return buf;
}
if(strcmp(num,"5.")==0)
{
strcpy(buf,"😁");
return buf;
}
if(strcmp(num,"6.")==0)
{
strcpy(buf,"真男人从不食💩,只食💨");
return buf;
}
if(strcmp(num,"7.")==0)
{
strcpy(buf,"嘟嘟嘟!! 🚋 The car is coming");
return buf;
}
if(strcmp(num,"8.")==0)
{
strcpy(buf,"就这么点👌?");
return buf;
}
if(strcmp(num,"9.")==0)
{
strcpy(buf,"来🍇🍈🍊🍋多吃点,别让人看扁");
return buf;
}
if(strcmp(num,"10.")==0)
{
strcpy(buf,"顺便给你分配个👩🍳");
return buf;
}
if(strcmp(num,"11.")==0)
{
strcpy(buf,"Other people's money is my belongings😛");
return buf;
}
if(strcmp(num,"12.")==0)
{
strcpy(buf,"Are you a dog?🐶");
return buf;
}
if(strcmp(num,"13.")==0)
{
strcpy(buf,"你是个什么🐮🐎");
return buf;
}
if(strcmp(num,"14.")==0)
{
strcpy(buf,"一个巴掌拍不响但是加上一个🍑可以");
return buf;
}
if(strcmp(num,"15.")==0)
{
strcpy(buf,"👾");
return buf;
}
return NULL;
}
void checkrecord()//功能标志8 查看聊天记录
{
ts.flag = 8;
int ret;
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
}
void filetransfer()//功能标志9 文件传输
{
clientlist ts1;
strcpy(ts1.name,ts.name);
ts1.flag = 9;
char filename[128];
printf("\033[0;31m <请输入要传输的文件名>\033[0m\n");
scanf("%s",filename);
printf("\033[0;31m <请输入要传输的对象>\033[0m\n");
scanf("%s",ts1.to_name);
int bytes;
int fd;
if((fd = open(filename,O_RDONLY)) == -1)
{
perror("open error!\n");
printf("未找到此文件");
return;
}
printf("打开文件成功\n");
while(1)
{
memset(ts1.buf,0,sizeof(ts1.buf));
bytes = read(fd,ts1.buf,256);
if(bytes == -1)
{
perror("read");
return;
}
ts1.num = bytes;
sleep(1);
send(clientfd2,&ts1,sizeof(ts1),0);
if(bytes == 0)
{
strcpy(ts1.buf,"0");
send(clientfd2,&ts1,sizeof(ts1),0);
break;
}
}
close(fd);
return;
}
void applyroot()//功能标志 10 管理员申请
{ int num;
putchar(10);
printf("\033[5;;35m尊敬的管理员请选择您的专属头像\033[0m\n");
putchar(10);
printf("\033[33m\033[0;33m 1.👽 2.👹 3.👻 4.🐉 5.😈 6.🐸 7.🐱 8.👺 \033[0;34m \033[0m\n");
putchar(10);
printf("\033[33m\033[0;33m 9.🐯 10.🐆 11.🐴 12.🐋 13.😹 14.🐮 15.🙀\033[0;34m \033[0m\n");
scanf("%d",&num);
if(1 == num)
{
strcpy(ts.emojio,"👽");
}
if(2 == num)
{
strcpy(ts.emojio,"👹");
}
if(3 == num)
{
strcpy(ts.emojio,"👻");
}
if(4 == num)
{
strcpy(ts.emojio,"🐉");
}
if(5 == num)
{
strcpy(ts.emojio,"😈");
}
if(6 == num)
{
strcpy(ts.emojio,"🐸");
}
if(7 == num)
{
strcpy(ts.emojio,"🐱");
}
if(8 == num)
{
strcpy(ts.emojio,"👺");
}
if(9 == num)
{
strcpy(ts.emojio,"🐯");
}
if(10 == num)
{
strcpy(ts.emojio,"🐆");
}
if(11 == num)
{
strcpy(ts.emojio,"🐴");
}
if(12 == num)
{
strcpy(ts.emojio,"🐋");
}
if(13 == num)
{
strcpy(ts.emojio,"😹");
}
if(14 == num)
{
strcpy(ts.emojio,"🐮");
}
if(15 == num)
{
strcpy(ts.emojio,"🙀");
}
ts.flag = 10;
ts.root = 1;
int ret;
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
sleep(1);
system("clear");
if(flag1 == 2)
{ flag1 = 0;
selectfun();
}
else
{
printf("\033[33m \033[0;33m申请管理员失败\033[0;34m \033[0m\n");
sleep(1);
//system("clear");
funcinto();
}
}
void rootlogin()//功能标志11 管理员登录 登录成功直接进入管理员聊天界面
{
ssize_t ret;
system("clear");
printf("\033[0;31m请输入你的名字..\033[0m\n");
scanf("%s",ts.name);
system("clear");
printf("\033[0;31m请输入你的密码\033[0m\n");
system("stty -echo");
scanf("%s",ts.password);
sleep(1);
system("stty echo");
ts.flag = 11; //用户登录标志位
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
sleep(1);
if(3 == flag1)
{
flag1 = 0;
selectfun();
}
if(0 == flag1)
{
rootgroupchat();
}
return;
}
void rootgroupchat() //管理员群聊界面 显示群聊界面
{
usleep(500*1000);
int num = 0;
ts.root = 1;
ssize_t ret;
system("./zjn");
ts.flag = 5;
char buf[200] = "\0";
char *buf2;
system("clear");
printf("\033[0;31m请输入聊天内容..\033[0m\n"); //循环聊天记得加循环
printf("\033[0;31m <输入Q!退出聊天室>\033[0m\n");
printf("\033[0;36m <输入W!查看快捷短语>\033[0m\n");
printf("\033[0;36m <输入C!查看聊天记录>\033[0m\n");
printf("\033[0;36m <输入T!进行文件传输>\033[0m\n");
printf("\033[0;36m <输入L!查看当前在线人数>\033[0m\n");
printf("\033[0;36m <输入K!踢人>\033[0m\n");
printf("\033[0;36m <输入F!禁言>\033[0m\n");
printf("\033[0;36m <输入U!解除禁言>\033[0m\n");
printf("\033[0;36m <输入E!撤销管理员身份>\033[0m\n");
printf("\033[0;33m [管理员]😇:%s\033[0m\n",ts.name);
while(1)
{
scanf("%s",buf);
if(strcmp(buf,"Q!") == 0)//退出群聊
{
system("clear");
exit_room();
return;
}
if(strcmp(buf,"E!") == 0)//取消管理员身份
{
system("clear");
cancelroot();
return;
}
if(strcmp(buf,"W!") == 0)//查看快捷短语
{
phrase();
continue;
}
if(strcmp(buf,"C!") == 0)//查看聊天记录
{
checkrecord();
printf("\033[0;32m请输入1继续群聊..\033[0m\n");
scanf("%d",&num);
if(1 == num)
{
break;
}
else
{
printf("\033[0;32m输入错误\033[0m\n");
}
}
if(strcmp(buf,"T!") == 0)//文件传输
{
filetransfer();
break;
}
if(strcmp(buf,"L!") == 0)//查看在线用户
{
rootviewonline_user();
printf("\033[0;32m请输入1继续群聊..\033[0m\n");
scanf("%d",&num);
if(1 == num)
{
break;
}
else
{
printf("\033[0;32m输入错误\033[0m\n");
}
}
if(strcmp(buf,"K!") == 0)//踢人
{
rootkick();
break;
}
if(strcmp(buf,"F!") == 0)//禁言
{
silent();
break;
}
if(strcmp(buf,"U!") == 0)//解除禁言
{
remsilent();
break;
}
if((buf2 = selectphrase(buf)) == NULL)
{
strcpy(ts.msg,buf);
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
continue;
}
else
{
strcpy(ts.msg,buf2);
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
}
}
rootgroupchat();
}
void rootviewonline_user()//管理员标志6 查看所有在线用户
{
ts.flag = 6;
int ret;
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
ts.flag = 5;
return;
}
void rootkick()//功能标志12 踢出群聊
{
ts.root = 1;
ssize_t ret;
system("clear");
ts.flag = 12;
printf("\033[0;31m请输入你想踢出群聊的对象..\033[0m\n");
scanf("%s",ts.to_name);
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
sleep(1);
rootgroupchat();
return;
}
void silent()//功能标志13 禁言
{
ts.root = 1;
ssize_t ret;
system("clear");
ts.flag = 13;
printf("\033[0;31m请输入你想禁言的对象..\033[0m\n");
scanf("%s",ts.to_name);
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
sleep(1);
rootgroupchat();
return;
}
void remsilent()//功能标志14 解除禁言
{
ts.root = 1;
ssize_t ret;
system("clear");
ts.flag = 14;
printf("\033[0;31m请输入你想解除禁言的对象..\033[0m\n");
scanf("%s",ts.to_name);
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
rootgroupchat();
return;
}
void cancelroot()//功能标志15 取消管理员身份
{
char password[30] = {0};
char name[30] = {0};
printf("\033[0;31m 请认真确认你的用户信息\033[0m\n");
printf("\033[0;31m<输入姓名>\033[0m\n");
scanf("%s",name);
system("clear");
printf("\033[0;31m<输入密码>\033[0m\n");
scanf("%s",password);
int ret1,ret2;
ret1 = strcmp(name,ts.name);
ret2 = strcmp(password,ts.password);
if(0 == ret1 && 0 == ret2)
{
ts.flag = 15;
int ret;
ret =send(clientfd2,&ts,sizeof(clientlist),0);
if(ret == -1)
{
ERRLOG("send");
}
}
sleep(1);
selectfun();
return;
}
void *recv_thread(void *arg)//接受线程函数
{
// int ret = 1;
int fd;
MSG msg;
//int num;
char buf[256] = {0};
int length;
clientfd2 = *((int *)arg);
while(1)
{
memset(buf,0,sizeof(buf));
length = recv(clientfd2,buf,sizeof(buf),0);
if (length == 0)
{
pthread_exit(NULL);
exit(1);
}
buf[length] = '\0';
printf("\033[5;;36m%s\033[0m\n",buf);
if(strcmp(buf,"该用户不存在,请注册...") == 0)
{
flag1 = 1;
}
if(strcmp(buf,"密码输入错误..") == 0)
{
flag1 = 1;
}
if(strcmp(buf,"您已在线,请勿重复登录") == 0)
{
flag1 = 1;
}
if(strcmp(buf,"管理员申请成功") == 0)
{
flag1 = 2;
}
if(strcmp(buf,"该用户非管理员") == 0)
{
flag1 = 3;
}
if(strcmp(buf,"密码输入错误") == 0)
{
flag1 = 3;
}
if(strcmp(buf,"管理员已将你踢出聊天室") == 0)
{
exit(1);
}
if(strcmp(buf,"管理员已将你禁言") == 0)
{
flag2 = 0;
}
if(strcmp(buf,"管理员已将你解除禁言") == 0)
{
flag2 = 1;
}
if(strcmp(buf,"文件存在进行文件传输") == 0)
{
printf("正在接受文件\n");
if((fd = open("1.txt",O_WRONLY | O_CREAT | O_TRUNC,0664)) == -1)
{
ERRLOG("open error");
}
int ret;
while((ret = recv(clientfd2,&msg,sizeof(msg),0)) != -1)
{
//printf("ret= %d\n",ret);
if(strcmp(msg.text,"0") == 0)
{
printf("\033[0;36m文件接受完成\033[0m\n");
//sleep(1);
close(fd);
break;
}
else
{
write(fd,msg.text,msg.num);
}
memset(&msg,0,sizeof(msg));
}
}
putchar(10);
}
//pthread_exit(NULL);
}
void *send_thread(void *arg)//发送线程函数
{
selectfun();
}
void exit_room()//退出聊天室
{
exit(0);
}
void recvmessage()
client.h
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <sqlite3.h>
#define N 256
#define ERRLOG(errmsg) do{\
perror(errmsg);\
printf("%s - %s - %d\n",__FILE__,__func__,__LINE__);\
exit(1);\
}while(0)
int clientfd2;//客户端sockfd
typedef struct file //文件传输结构体
{
char text[N];
int num;
}MSG;
typedef struct client
{
int flag; //功能标志 注册标志reg
char emojio[20];//保存头像
char name[32];//姓名
int root; //管理员标志
char msg[50];//聊天内容
char password[32];//密码
char to_name[50];//聊天对象
char buf[256];//文件内容
int num;
}clientlist;
clientlist ts;
void funcinto();//第二阶段选择进入
void recvmessage();//消息接受
void n_init();//初始化客户端
void selectfun();//进入目录选择功能
void user_login();//用户登录
void user_register();//用户注册
void privatechat();//私聊
void *recv_thread(void *arg);//客户端接受消息线程函数
void *send_thread(void *arg);//客户端发送消息函数
void changpassword(); //修改密码
void groupchat(); //群聊
void viewonline_user();//查看所有在线用户
void deleteuser();//注销用户
void phrase();//快捷短语
char *selectphrase(char *num);//快捷短语的选择
void checkrecord();//查看聊天记录
void filetransfer();//文件传输
void applyroot();//申请成为管理员
void rootlogin();//管理员登录
void rootgroupchat();//管理员群聊界面
void rootkick();//踢出群聊
void silent();//管理员禁言
void remsilent();//解除禁言
void rootviewonline_user();//管理员查看在线用户
void cancelroot();//取消管理员身份
void root_login();//管理员登录
void exit_room();//退出聊天室
void sendmessage();//发送字符串