Select 多路复用
服务器类型中
循环服务器:同一时刻只可以响应一个客户端的请求
并发服务器:同一时刻 可以响应 多个 客户端的请求
实现:
服务器:
1.创建socket
2.绑定 bind 记得创建server_address :( struct sockaddr_in server_addr)
3.设置监听队列 listen//(TCP这里和accept配合使用
一个while循环listen和accept(阻塞)搭配完成一次新socket创建)
//SELECT中 listen在while循环外面
/****** 上面同第一篇TCP实现原理相同 *******/
4.Select 用以监听fd(文件描述符 所有的~~)
(函数原型)
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
Nfds:(maxfd)代表目前已打开的 文件fd 数目 + 1
Readfds writefds exceptfds :
都是集合(是所有fd 的集合)
用以监听 fd 是否 可读 / 可写 / 有异常发生
作为服务器 我们只需要监听 是否可读 :客户端发起请求,服务器可以读到客户 的信息
Timeout: 是结构体 结构体内有两个值 一个秒 一个微秒
Timeout取值:
0 :不管有无 fd 可读 都直接返回
NULL: 阻塞状态 不断扫描所有的 fd 直到有 fd 发生变化 才返回
正整数:等待的最长时间t;t秒内如果没有 fd 可读 程序继续向下执行
(
fd_set ReadFd,TmpFd;//(是一个fd集合)用于select 参数
FD_ZERO(&ReadFd);//将两个参数初始化
FD_ZERO(&TmpFd);
FD_SET(sockfd,&ReadFd);//先将sockfd加入集合:监听是否有人发起连接
)
客户端不变
其余信息看代码解释
UDP:
UDP是最简单的
服务器:
- 创建socket
- 绑定 bind
- 接受信息 recvfrom
- 指定发送的对象 sendto
客户端:
- 创建Socket
- Sendto 发送信息
- Recvfrom 接受信息
服务器:
Socket 和 bind同TCP
3 . recvfrom()
(函数原型)ssize_t recvfrom(int s, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen);
S : 就是自己创建的sockfd
Buf: 自己想要发送的内容
Len : buf的大小
Flags: 默认为0
From: 就是自己本身啊 从自己发消息出去(看到这个前缀就知道 又要创建一个自己的 地址 别忘了 struct sockaddr *client_addr)
Fromlen: 是地址的长度 因为是指针所以回头 自己定义的length 记得取地址 &
客户端一样如此
4.sendto()
(函数原型)ssize_t sendto(int s, const void *buf, size_t len, int flags, const
struct sockaddr *to, socklen_t tolen);
S: 创建的sockfd
Buf: 接受发来的消息
Len : buf的大小
Flags: 默认为0
To: 发送给谁(服务器啊) (看到这个前缀就知道 又要创建一个地址 别忘了 struct sockaddr *server_addr)
Tolen: 是地址的长度 这里不是指针所以不用取地址
附上源码:感觉可以的点个赞再走
TCP:
client.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sqlite3.h>
struct user
{
char name[10];
//用户昵称
char ID[20];
//帐号
char password[20];
//密码
int type;
//消息种类
int state;
//1表示在线,0表示离线
char toname[10];
//私聊信息发送对象
char record[100];
//聊天记录
int level;
//用户权限:2表示管理员,1为普通用户,0表示被禁言,-1表示被踢出
struct user *next;
};
char NAME[20]={0};
//用于检测有无此用户名
char NAME2[20]={0};
//用于存放登录用户的用户名
char id[20]={0};
char PASSWORD[20]={0};
int SIGN=0;
int SIGN2=10;
int SIGN3=0;
int count=0;
//记录会员的数量(只能有一个)
int Tname(void *para,int columnCount,char **columnValue,char **columnName)
{
if(strcmp(columnValue[0],NAME) == 0)
{
SIGN=1;
}
return 0;
}
int Tid(void *para,int columnCount,char **columnValue,char **columnName)
{
if(strcmp(columnValue[0],id) == 0)
{
SIGN=1;
}
return 0;
}
void zhuce(int sockfd)
//注册
{
sqlite3 *pdb;
char sql[100]={0};
struct user User;
int ret;
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_open");
return;
}
printf("****************************************\n");
printf(" 请输入您想要的昵称:\n");
fflush(stdout);
while(1)
{
scanf("%s",User.name);
memset(NAME,0,sizeof(NAME));
strcpy(NAME,User.name);
sprintf(sql,"select name from user1 where name='%s';",User.name);
ret=sqlite3_exec(pdb,sql,Tname,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
if(SIGN == 0)
//昵称未被注册
{
break;
}
else
{
SIGN=0;
printf(" 该已用户昵称被注册!\n");
printf(" 请重新输入用户昵称:\n");
fflush(stdout);
}
}
SIGN=0;
//复位
printf("\n");
printf(" 清输入您的帐号:\n");
fflush(stdout);
while(1)
{
scanf("%s",User.ID);
memset(id,0,sizeof(id));
strcpy(id,User.ID);
sprintf(sql,"select ID from user1 where ID='%s';",User.ID);
ret=sqlite3_exec(pdb,sql,Tid,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
if(SIGN == 0)
//帐号未被注册
{
break;
}
else
{
SIGN=0;
printf(" 该帐号已被注册!\n");
printf(" 请重新输入帐号:\n");
fflush(stdout);
}
}
SIGN=0;
//复位
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
printf("\n");
printf(" 请输入您的密码:\n");
fflush(stdout);
scanf("%s",User.password);
while(strlen(User.password) <= 5)
{
printf(" 密码长度过短,请重新输入:\n");
fflush(stdout);
scanf("%s",User.password);
}
printf("\n");
printf(" 恭喜您用户注册成功!\n");
printf("****************************************\n");
sleep(2);
User.type=1;
//设置消息类型为注册(1)
User.state=0;
//表示不在线
User.level=1;
//表示为普通用户
ret=send(sockfd,&User,sizeof(User),0);
//打包发送给服务器
if(ret == -1)
{
perror("send");
return;
}
}
int Tid2(void *para,int columnCount,char **columnValue,char **columnName)
{
memset(NAME2,0,sizeof(NAME2));
strcpy(NAME2,columnValue[0]);
if(strcmp(columnValue[1],id) == 0)
{
SIGN=1;
}
if(strcmp(columnValue[3],"1") == 0)
{
SIGN=2;
}
return 0;
}
int Tpassword(void *para,int columnCount,char **columnValue,char **columnName)
{
if(strcmp(columnValue[0],PASSWORD) == 0)
{
SIGN=1;
}
return 0;
}
void login(int sockfd)//登录
{
int ret;
sqlite3 *pdb;
char sql[100]={0};
struct user User;
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_open");
return;
}
printf("********************************\n");
printf(" 清输入您的帐号:\n");
fflush(stdout);
while(1)
{
scanf("%s",User.ID);
memset(id,0,sizeof(id));
strcpy(id,User.ID);
sprintf(sql,"select * from user1 where ID='%s';",User.ID);
ret=sqlite3_exec(pdb,sql,Tid2,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
if(SIGN == 1)
{
break;
}
else if(SIGN == 2)
{
SIGN=0;
printf(" 该帐号已在别处登录!\n");
printf(" 请重新输入:\n");
fflush(stdout);
}
else
{
SIGN=0;
printf(" 该帐号不存在,请重新输入:\n");
fflush(stdout);
}
}
SIGN=0;
printf(" 清输入您的密码:\n");
fflush(stdout);
while(1)
{
scanf("%s",User.password);
memset(PASSWORD,0,sizeof(PASSWORD));
strcpy(PASSWORD,User.password);
sprintf(sql,"select password from user1 where ID='%s';",User.ID);
ret=sqlite3_exec(pdb,sql,Tpassword,NULL,NULL);
//取出user表中的帐号信息
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
if(SIGN == 1)
{
break;
}
else
{
SIGN=0;
printf(" 密码错误,请重新输入:\n");
fflush(stdout);
}
}
SIGN=0;
printf(" 登录成功!\n");
printf("********************************\n");
sleep(2);
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
strcpy(User.name,NAME2);
User.type=2;
//设置消息类型为登录(2)
User.state=1;
//设置用户在线
ret=send(sockfd,&User,sizeof(User),0);
//打包发送给服务器
if(ret == -1)
{
perror("send");
return;
}
}
int print(void *para,int columnCount,char **columnValue,char **columnName)
{
printf("%s:%s\n",columnName[0],columnValue[0]);
return 0;
}
void listonline()
//查看当前在线用户
{
sleep(1);
system("clear");
int ret;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_open");
return;
}
printf("❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥\n");
printf(" 当前在线用户为:\n");
sprintf(sql,"select name from user1 where state=1;");
ret=sqlite3_exec(pdb,sql,print,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
printf("❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥\n");
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
sleep(2);
}
int Tlevel(void *para,int columnCount,char **columnValue,char **columnName)
//检测用户是否被禁言
{
if(strcmp(columnValue[0],"1") == 0 || strcmp(columnValue[0],"2") == 0)
{
SIGN2=5;
}
if(strcmp(columnValue[0],"0") == 0)
{
SIGN2=0;
}
return 0;
}
int Tprivatechat(void *para,int columnCount,char **columnValue,char **columnName)
//检测用户是否存在
{
if(strcmp(columnValue[0],NAME) == 0)
{
SIGN=1;
}
if(strcmp(columnValue[0],NAME2) == 0)
{
SIGN=2;
}
return 0;
}
//检测该用户是否在线
int Tonline(void *para,int columnCount,char **columnValue,char **columnName)
{
if(strcmp(columnValue[0],"1") == 0)
{
SIGN3=1;
}
return 0;
}
void chatprivate(int sockfd)
//私聊
{
sleep(1);
system("clear");
printf("❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥\n");
int ret;
sqlite3 *pdb;
char sql[100]={0};
struct user User;
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_open");
return;
}
sprintf(sql,"select level from user1 where name='%s';",NAME2);
ret=sqlite3_exec(pdb,sql,Tlevel,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
if(SIGN2 == 0)
{
printf(" 您已被管理员禁言!\n");
sleep(1);
SIGN2=10;
return;
}
printf(" 请选择您想私聊的用户:\n");
fflush(stdout);
while(1)
{
SIGN=0;
SIGN3=0;
memset(NAME,0,sizeof(NAME));
scanf("%s",NAME);
sprintf(sql,"select name from user1 where name='%s';",NAME);
ret=sqlite3_exec(pdb,sql,Tprivatechat,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
sprintf(sql,"select state from user1 where name='%s';",NAME);
ret=sqlite3_exec(pdb,sql,Tonline,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
//表示存在该用户且该用户在线
if(SIGN == 1 && SIGN3 ==1)
{
break;
}
if(SIGN == 2)
{
printf(" 不能和自己聊天!\n");
printf(" 请重新输入您想私聊的用户:");
fflush(stdout);
}
if(SIGN3 == 0 && SIGN == 1)
{
printf(" 该用户不在线!\n");
printf(" 请重新输入您想私聊的用户:");
fflush(stdout);
}
if(SIGN == 0)
{
printf(" 该用户不存在!\n");
printf(" 请重新输入您想私聊的用户:");
fflush(stdout);
}
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
SIGN=0;
//复位
SIGN3=0;
printf("❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥\n");
printf("******聊天室******\n");
printf(" 常用表情\n");
printf("smile ( ^_^ ) cry T_T \n ");
printf("sweat -_-! angry >_< \n ");
printf("dizzy +_+ suprise (⊙ˍ⊙)\n");
while(1)
{
User.type=3;
//设置消息类型为私聊(3),最后哦发送给服务器;
strcpy(User.name,NAME2);
strcpy(User.toname,NAME);
scanf("%s",User.record);
if(strcmp(User.record,"end") == 0)
{
printf(" 再见!\n");
printf("******聊天室******\n");
sleep(1);
SIGN2=10;
break;
}
ret=send(sockfd,&User,sizeof(User),0);
if(ret == -1)
{
perror("send");
return;
}
memset(&User,0,sizeof(User));
}
}
void chatall(int sockfd)
//群聊
{
sleep(1);
system("clear");
int ret;
struct user User;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_open");
return;
}
sprintf(sql,"select level from user1 where name='%s';",NAME2);
ret=sqlite3_exec(pdb,sql,Tlevel,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
if(SIGN2 == 0)
{
printf(" 您已被管理员禁言!\n");
sleep(1);
SIGN2=10;
return;
}
printf("❥❥❥❥❥❥❥❥❥❥❥❥❥Chatting room❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥\n");
while(1)
{
User.type=4;
//设置消息类型为私聊(4),最后发送给发服务器;
scanf("%s",User.record);
if(strcmp(User.record,"end") == 0)
{
printf(" 通话结束!\n");
sleep(1);
SIGN2=10;
break;
}
strcpy(User.name,NAME2);
ret=send(sockfd,&User,sizeof(User),0);
if(ret == -1)
{
perror("send");
return;
}
memset(&User,0,sizeof(User));
}
}
int Tprivate(void *para,int columnCount,char **columnValue,char **columnName)
{
if(strcmp(columnValue[0],NAME) == 0)
{
SIGN=1;
}
if(strcmp(columnValue[0],NAME2) == 0)
{
SIGN=2;
}
return 0;
}
int printprivate(void *para,int columnCount,char **columnValue,char **columnName)
//打印私聊
{
printf("%s:%s\n",columnValue[0],columnValue[2]);
return 0;
}
void findprivate()
{
sleep(1);
system("clear");
int key=1;
int ret;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_open");
return;
}
printf(" 您想查询与谁的聊天记录:");
fflush(stdout);
while(1)
{
SIGN=0;
memset(NAME,0,sizeof(NAME));
scanf("%s",NAME);
sprintf(sql,"select name from user1 where name='%s';",NAME);
ret=sqlite3_exec(pdb,sql,Tprivate,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
//判断用户是否存在且不是自己
if(SIGN == 1)
{
break;
}
else if(SIGN == 2)
{
printf(" 您无法查询与自己的聊天记录!\n");
printf(" 请重新输入您想查询的用户:");
fflush(stdout);
}
else
{
printf(" 该用户不存在!\n");
printf(" 请重新输入您想查询的用户:");
fflush(stdout);
}
}
SIGN=0;
//复位
sprintf(sql,"select * from Privatechatrecord where name='%s' AND toname='%s' OR name='%s' AND toname='%s';",NAME,NAME2,NAME2,NAME);
ret=sqlite3_exec(pdb,sql,printprivate,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
}
int printall(void *para,int columnCount,char **columnValue,char **columnName)
//打印群聊
{
printf("%s:%s\n",columnValue[0],columnValue[1]);
return 0;
}
void findall()
{
sleep(1);
system("clear");
int key=1;
int ret;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_open");
return;
}
sprintf(sql,"select * from Groupchatrecord;");
ret=sqlite3_exec(pdb,sql,printall,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
}
int TVIP(void *para,int columnCount,char **columnValue,char **columnName)
//统计会员数,一开始作判断,管理数目只有一个;
{
if(strcmp(columnValue[0],"2") == 0)
{
count++;
}
return 0;
}
void VIP(int sockfd)//vip
{
sleep(1);
system("clear");
char key[2]={0};
int ret;
struct user User;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_open");
return;
}
sprintf(sql,"select level from user1;");
ret=sqlite3_exec(pdb,sql,TVIP,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
if(count >= 1)
{
printf(" 会员名额为0,请下次再来!\n");
count=0;
sleep(1);
return;
}
printf(" 确定要支付998成为会员吗?(y/n)\n");
scanf("%s",key);
if(key[0] == 'y')
{
User.type=5;
User.level=2;
strcpy(User.name,NAME2);
ret=send(sockfd,&User,sizeof(User),0);
if(ret == -1)
{
perror("send");
return;
}
printf(" 恭喜您成为会员,享受踢人禁言功能!\n");
}
if(key[1] == 'n')
{
printf(" sorry,开通失败!\n");
}
sleep(1);
}
int ifvip(void *para,int columnCount,char **columnValue,char **columnName)
//检验用户是否为vip
{
if(strcmp(columnValue[0],"2") == 0)
{
SIGN=1;
}
return 0;
}
int Tcunzai(void *para,int columnCount,char **columnValue,char **columnName)
//检验用户是否存在
{
if(strcmp(columnValue[0],NAME) == 0)
{
SIGN=1;
}
return 0;
}
void shutup(int sockfd)
{
sleep(1);
system("clear");
int ret;
sqlite3 *pdb;
char sql[100]={0};
struct user User;
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_open");
return;
}
sprintf(sql,"select level from user1 where name='%s';",NAME2);
ret=sqlite3_exec(pdb,sql,ifvip,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
if(SIGN == 0)
{
printf(" 对不起,您的权限不足!\n");
sleep(1);
return;
}
else
{
printf(" 请选择您想禁言的用户:");
fflush(stdout);
while(1)
{
SIGN=0;
SIGN3=0;
scanf("%s",User.name);
memset(NAME,0,sizeof(NAME));
strcpy(NAME,User.name);
sprintf(sql,"select name from user1 where name='%s';",User.name);
ret=sqlite3_exec(pdb,sql,Tcunzai,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
sprintf(sql,"select state from user1 where name='%s';",User.name);
ret=sqlite3_exec(pdb,sql,Tonline,NULL,NULL);
//判断用户是否存在且是否在线
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
if(SIGN == 1 && SIGN3 == 1)
{
break;
}
else if(SIGN == 1 && SIGN3 == 0)
{
printf(" 此用户不在线!\n");
printf(" 请重新输入:");
fflush(stdout);
}
else
{
printf(" 此用户不存在!\n");
printf(" 请重新输入:");
fflush(stdout);
}
}
SIGN=0;
User.type=6;
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
ret=send(sockfd,&User,sizeof(User),0);
if(ret == -1)
{
perror("send");
return;
}
printf(" %s用户已被禁言!\n",User.name);
sleep(1);
}
}
void jiejin(int sockfd)
{
sleep(1);
system("clear");
int ret;
sqlite3 *pdb;
char sql[100]={0};
struct user User;
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_open");
return;
}
sprintf(sql,"select level from user1 where name='%s';",NAME2);
ret=sqlite3_exec(pdb,sql,ifvip,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
if(SIGN == 0)
{
printf(" 对不起,您的权限不足!\n");
sleep(1);
return;
}
else
{
printf(" 请选择您想解禁的用户:");
fflush(stdout);
while(1)
{
SIGN=0;
SIGN3=0;
scanf("%s",User.name);
memset(NAME,0,sizeof(NAME));
strcpy(NAME,User.name);
sprintf(sql,"select name from user1 where name='%s';",User.name);
ret=sqlite3_exec(pdb,sql,Tcunzai,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
sprintf(sql,"select state from user1 where name='%s';",User.name);
ret=sqlite3_exec(pdb,sql,Tonline,NULL,NULL);
//判断用户是否存在且是否在线
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
if(SIGN == 1 && SIGN3 == 1)
{
break;
}
else if(SIGN == 1 && SIGN3 == 0)
{
printf(" 此用户不在线!\n");
printf(" 请重新输入:");
fflush(stdout);
}
else
{
printf(" 此用户不存在!\n");
printf(" 请重新输入:");
fflush(stdout);
}
}
SIGN=0;
User.type=9;
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
ret=send(sockfd,&User,sizeof(User),0);
if(ret == -1)
{
perror("send");
return;
}
printf(" %s用户已解除禁言!\n",User.name);
sleep(1);
}
}
void Kickout(int sockfd)
{
sleep(1);
system("clear");
int ret;
sqlite3 *pdb;
char sql[100]={0};
struct user User;
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_open");
return;
}
sprintf(sql,"select level from user1 where name='%s';",NAME2);
ret=sqlite3_exec(pdb,sql,ifvip,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
if(SIGN == 0)
{
printf(" 对不起,您的权限不足!\n");
sleep(1);
return;
}
else
{
printf(" 请选择您想踢出的用户:");
fflush(stdout);
while(1)
{
SIGN=0;
SIGN3=0;
scanf("%s",User.name);
memset(NAME,0,sizeof(NAME));
strcpy(NAME,User.name);
sprintf(sql,"select name from user1 where name='%s';",User.name);
ret=sqlite3_exec(pdb,sql,Tcunzai,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
sprintf(sql,"select state from user1 where name='%s';",User.name);
ret=sqlite3_exec(pdb,sql,Tonline,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
if(SIGN == 1 && SIGN3 == 1)
{
break;
}
else if(SIGN == 1 && SIGN3 == 0)
{
printf(" 此用户不在线!\n");
printf(" 请重新输入:");
fflush(stdout);
}
else
{
printf(" 此用户不存在!\n");
printf(" 请重新输入:");
fflush(stdout);
}
}
SIGN=0;
User.type=7;
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
ret=send(sockfd,&User,sizeof(User),0);
if(ret == -1)
{
perror("send");
return;
}
printf(" %s用户已被您踢出!\n",User.name);
sleep(1);
}
}
void Quit(int sockfd)
//退出
{
sleep(1);
system("clear");
int ret;
struct user User;
User.state=0;
User.type=8;
strcpy(User.name,NAME2);
ret=send(sockfd,&User,sizeof(User),0);
if(ret == -1)
{
perror("send");
return;
}
printf("❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥\n");
printf("❥❥❥❥ ʚ goodbye!~ ɞ ❥❥❥❥ \n");
printf("❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥\n");
sleep(1);
}
void TERMIN()
{
sleep(1);
system("clear");
printf("❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥\n");
printf("❥❥❥❥ 您选择了退出聊天室~ ❥❥❥❥\n");
printf("❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥❥\n");
sleep(1);
}
client-main.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#define PORT 1234
struct user
{
char name[10];
char ID[20];
char password[20];
int type;
int state;
char toname[10];
char record[100];
int fd;
int level;
struct user *next;
};
pthread_t tid[2];
int out=1;
//标志位:表示是否退出客户端
void* denglu(void *arg)
{
int ret;
char key1[10]={0};
//登录界面功能选择按键
char key2[10]={0};
//登录后功能选择按键
system("clear");
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
printf("❊❊❊❊❊ ♕ 聊天室 ♕ ❊❊❊❊❊\n");
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
sleep(2);
while(1)
{
system("clear");
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
printf("❊❊❊❊❊ 1.注册 ❊❊❊❊❊ \n");
printf("❊❊❊❊❊ 2.登录 ❊❊❊❊❊ \n");
printf("❊❊❊❊❊ 3.退出 ❊❊❊❊❊ \n");
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
printf("❊❊❊❊❊ 请选择您的功能 ❊❊❊❊❊\n");
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
scanf("%s",key1);
switch(key1[0])
{
case '1':
system("clear");
zhuce(*(int*)arg);
//注册界面
break;
case '2':
system("clear");
login(*(int*)arg);
//登录界面
getin: system("clear");
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
printf("❊❊❊❊❊ 1.在线用户 ❊❊❊❊❊ \n");
printf("❊❊❊❊❊ 2.私聊 ❊❊❊❊❊ \n");
printf("❊❊❊❊❊ 3.群聊 ❊❊❊❊❊\n");
printf("❊❊❊❊❊ 4.查询私聊记录 ❊❊❊❊❊ \n");
printf("❊❊❊❊❊ 5.查询群聊记录 ❊❊❊❊❊\n");
printf("❊❊❊❊❊ 6.开通会员 ❊❊❊❊❊\n");
printf("❊❊❊❊❊ 7.禁言 ❊❊❊❊❊\n");
printf("❊❊❊❊❊ 8.踢人 ❊❊❊❊❊ \n");
printf("❊❊❊❊❊ 9.退出 ❊❊❊❊❊ \n");
printf("❊❊❊❊❊ 0.解禁 ❊❊❊❊❊ \n");
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
printf("❊ 请选择您的功能 ❊\n");
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
scanf("%s",key2);
switch(key2[0])
{
case '1':
listonline();
//查看在线用户
sleep(2);
goto getin;
case '2':
chatprivate(*(int*)arg);
//私聊
sleep(2);
goto getin;
case '3':
chatall(*(int*)arg);
//群发
sleep(2);
goto getin;
case '4':
findprivate();
//查询私聊记录
sleep(2);
goto getin;
case '5':
findall();
//查询群聊记录
sleep(2);
goto getin;
case '6':
VIP(*(int*)arg);
//开通会员
sleep(2);
goto getin;
case '7':
shutup(*(int*)arg);
//禁言
sleep(2);
goto getin;
case '8':
Kickout(*(int*)arg);
//踢人
sleep(2);
goto getin;
case '9':
Quit(*(int*)arg);
//退出界面
sleep(2);
break;
case '0':
jiejin(*(int*)arg);
//解除禁言
sleep(2);
goto getin;
default:
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
printf("❊❊❊❊❊ 错误按钮(登录后)! ❊❊❊❊❊\n");
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
sleep(2);
goto getin;
}
break;
case '3':
goto breakout;
default:
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
printf("❊❊❊❊❊ 错误按钮(登录前)! ❊❊❊❊❊\n");
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
printf("错误按钮(登录前)!\n");
break;
}
}
breakout:TERMIN();
//退出客户端
out=0;
//复位
pthread_cancel(tid[0]);
//退出客户端后,将接受信息的进程杀死,不然一直阻塞在那里
}
void* Receive(void *arg)
{
int ret;
struct user User;
while(1)
{
memset(&User,0,sizeof(User));
ret=recv(*(int*)arg,&User,sizeof(User),0);
if(ret == -1)
{
perror("recv");
exit(1);
}
if(User.type == 3)
//私聊
{
printf("%s:%s\n",User.name,User.record);
}
if(User.type == 4)
//群发
{
printf("%s:%s\n",User.name,User.record);
}
if(User.type == 7)
//踢人
{
break;
}
}
}
int main()
{
int sockfd;
int ret;
char key1[10]={0};
//登录选择
char key2[10]={0};
//登录后选择
struct sockaddr_in server_addr;
sockfd=socket(PF_INET,SOCK_STREAM,0);
if(sockfd == -1)
{
perror("socket");
exit(1);
}
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=PF_INET;
server_addr.sin_port=htons(PORT);
server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
ret=connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
//连接服务器
if(ret == -1)
{
perror("connect");
exit(1);
}
while(1)
{
ret=pthread_create(&tid[0],NULL,Receive,(void*)&sockfd);
if(ret != 0)
{
perror("pthread_create");
exit(1);
}
ret=pthread_create(&tid[1],NULL,denglu,(void*)&sockfd);
if(ret != 0)
{
perror("pthread_create");
exit(1);
}
pthread_join(tid[0],NULL);
if(out == 0)
{
break;
}
pthread_cancel(tid[1]);
//先退出登录后的界面,回到注册登录退出界面,完成被踢就退出的功能
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
printf("❊❊❊❊❊ 您被管理员踢出了聊天室! ❊❊❊❊❊\n");
printf("❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊❊\n");
sleep(3);
}
return 0;
}
server.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/select.h>
#include<sys/time.h>
#include<unistd.h>
#include<sqlite3.h>
struct user
{
char name[10];
char ID[20];
char password[20];
int type;
int state;
char toname[10];
char record[100];
int fd;
int level;
struct user *next;
};
int tofd=0;
//私聊的通信管道号
char NAME[20]={0};
//暂时存储用户昵称
int onlineflag=0;
void zhuce(struct user User,int fd)
//消息类型1:注册
{
int ret;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite3_open");
return;
}
sprintf(sql, "create table if not exists user1 (name text,ID text,password text,state integer,level integer);");
//继续使用user1表
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_create");
return;
}
sprintf(sql,"insert into user1 (name,ID,password,state,level) values('%s','%s','%s',%d,%d);",User.name,User.ID,User.password,User.state,User.level);
//插入用户信息
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_insert");
return;
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
}
void login(struct user User,int fd)
//消息类型12:登录
{
int ret;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite3_open");
return;
}
sprintf(sql,"create table if not exists user2 (name text,fd integer);");
//继续使用user2表
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_create");
return;
}
sprintf(sql,"insert into user2(name,fd) values('%s',%d);",User.name,fd);
//将客户端的通信管道号插入表中
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_update");
return;
}
sprintf(sql,"update user1 set state=1 where ID='%s';",User.ID);
//设置在线
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_update");
return;
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
}
void Turn(char a[])
{
if(strcmp(a,"smile") == 0)
{
strcpy(a,"( ^_^ )");
}
if(strcmp(a,"cry") == 0)
{
strcpy(a,"T_T");
}
if(strcmp(a,"sweat") == 0)
{
strcpy(a,"-_-!");
}
if(strcmp(a,"angry") == 0)
{
strcpy(a,">_<");
}
if(strcmp(a,"dizzy") == 0)
{
strcpy(a,"+_+");
}
if(strcmp(a,"suprise") == 0)
{
strcpy(a,"(⊙ˍ⊙)");
}
}
int assign(void *para,int columnCount,char **columnValue,char **cloumnName)
//通过用户昵称找到通信管道号
{
tofd=atoi(columnValue[0]);
return 0;
}
void chatprivate(struct user User,int fd)
//消息类型13:私聊
{
int ret;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite3_open");
return;
}
sprintf(sql,"select fd from user2 where name='%s';", User.toname);
ret=sqlite3_exec(pdb,sql,assign,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite3_exec");
return;
}
Turn(User.record);
//将文字转换为表情符号
ret=send(tofd,&User,sizeof(User),0);
if(ret == -1)
{
perror("send");
return;
}
sprintf(sql, "create table if not exists Privatechatrecord (name text,toname text,record text);");
//创建Privatechat表
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_create");
return;
}
sprintf(sql,"insert into Privatechatrecord (name,toname,record) values('%s','%s','%s');",User.name,User.toname,User.record);
//存储私聊
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_insert");
return;
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
tofd=0;
}
int Tstate(void *para,int columnCount,char **columnValue,char **columnName)
//检测是否在线
{
if(strcmp(columnValue[0],"0") != 0)
{
onlineflag=1;
}
return 0;
}
void chatall(struct user User,int source_fd,int fd[],int k)
//消息类型14:群聊
{
int i;
int ret;
sqlite3 *pdb;
char sql[100]={0};
Turn(User.record);
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite3_open");
return;
}
sprintf(sql, "create table if not exists Groupchatrecord (name text,record text);");
//创建Groupchat表
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_create");
return;
}
sprintf(sql,"insert into Groupchatrecord (name,record) values('%s','%s');",User.name,User.record);
//存储群聊
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_insert");
return;
}
for(i=0;i<k;i++)
{
if(fd[i] == source_fd)
//给除了自己以外的用户发送消息
{
continue;
}
sprintf(sql,"select fd from user2 where fd='%d';",fd[i]);
ret=sqlite3_exec(pdb,sql,Tstate,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_exec");
return;
}
if(onlineflag == 1)
{
ret=send(fd[i],&User,sizeof(User),0);
if(ret == -1)
{
perror("send");
return;
}
onlineflag=0;
}
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
}
void VIP(struct user User)
//消息类型15:开通会员
{
int ret;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite3_open");
return;
}
sprintf(sql,"update user1 set level=2 where name='%s';",User.name);
//更新用户权限为管理员
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_update");
return;
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
}
void shutup(struct user User)
//消息类型16:禁言
{
int ret;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite3_open");
return;
}
sprintf(sql,"update user1 set level=0 where name='%s';",User.name);
//更新用户权限为被禁言
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_update");
return;
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
}
void kickout(struct user User)
//消息类型17:踢人
{
int ret;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite3_open");
return;
}
sprintf(sql,"update user1 set state=0 where name='%s';",User.name);
//更新用户不在线
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_update");
return;
}
sprintf(sql,"select fd from user2 where name='%s';", User.name);
//找到对应通信管道号
ret=sqlite3_exec(pdb,sql,assign,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite3_exec");
return;
}
sprintf(sql,"delete from user2 where name='%s';",User.name);
//将被踢用户从表中删除
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_delete");
return;
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
ret=send(tofd,&User,sizeof(User),0);
if(ret == -1)
{
perror("send");
return;
}
tofd=0;
}
void quit(struct user User)
//消息类型18:退出
{
int ret;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite3_open");
return;
}
sprintf(sql,"update user1 set state=0 where name='%s';",User.name);
//更新用户不在线
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_update");
return;
}
sprintf(sql,"delete from user2 where name='%s';",User.name);
//将用户从表中删除
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_delete");
return;
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
}
void jiejin(struct user User)
//消息类型16:禁言
{
int ret;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite3_open");
return;
}
sprintf(sql,"update user1 set level=1 where name='%s';",User.name);
//更新用户权限为解除禁言
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_update");
return;
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
return;
}
}
server_main.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/select.h>
#include<sys/time.h>
#include<unistd.h>
#include<sqlite3.h>
#define PORT 1234
struct user
{
char name[10];
char ID[20];
char password[20];
int type;
int state;
char toname[10];
char record[100];
int fd;
int level;
struct user *next;
};
int main()
{
int sockfd;
int ret;
int fd[100];
int MaxFd;
int i=0,j;
fd_set ReadFd,TmpFd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
struct user User;
sqlite3 *pdb;
char sql[100]={0};
ret=sqlite3_open("Database.db",&pdb);
if(ret != SQLITE_OK)
{
perror("sqlite3_open");
exit(1);
}
sprintf(sql,"create table if not exists user1 (name text,ID text,password text,state integer,level integer);");
//创建user1表
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_create1");
exit(1);
}
sprintf(sql,"create table if not exists user2 (name text,fd integer);");
//创建user2表
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_create1");
exit(1);
}
sprintf(sql,"create table if not exists Privatechatrecord (name text,toname text,record text);");
//创建Private chat record表
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_create2");
exit(1);
}
sprintf(sql, "create table if not exists Groupchatrecord (name text,record text);");
//创建Group chat record表
ret=sqlite3_exec(pdb,sql,NULL,NULL,NULL);
if(ret != SQLITE_OK)
{
perror("sqlite_create3");
exit(1);
}
ret=sqlite3_close(pdb);
if(ret != SQLITE_OK)
{
perror("sqlite_close");
exit(1);
}
sockfd=socket(PF_INET,SOCK_STREAM,0);
//创建平台
if(sockfd == -1)
{
perror("socket");
exit(1);
}
int opt=1;
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
//允许多开,避免地址覆盖
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=PF_INET;
server_addr.sin_port=htons(PORT);
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
ret=bind(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr));
//把自己绑定好
if(ret == -1)
{
perror("bind");
exit(1);
}
ret=listen(sockfd,10);
//监听信息
if(ret == -1)
{
perror("listen");
exit(1);
}
FD_ZERO(&ReadFd);
FD_ZERO(&TmpFd);
FD_SET(sockfd,&ReadFd);
MaxFd=sockfd;
while(1)
{
TmpFd=ReadFd;
ret=select(MaxFd+1,&TmpFd,NULL,NULL,NULL);
//用select阻塞
if(ret == -1)
{
perror("select");
exit(1);
}
if(FD_ISSET(sockfd,&TmpFd))//看看是不是 有客户(fd)向服务sockfd发起连接
{
int length=sizeof(client_addr);
fd[i]=accept(sockfd,(struct sockaddr*)&client_addr,&length);//如果有 则sockfd接受 保存客户信息
if(fd[i] == -1)
{
perror("accept");
exit(1);
}
FD_SET(fd[i],&ReadFd);//将客户加入监听集合
MaxFd=fd[i];//更新maxfd
i++;//每有一个客户发起连接 人数加一
}
else//fd 在发消息
{
for(j=0;j<i;j++)
{
if(FD_ISSET(fd[j],&TmpFd))//查看是哪个客户在发消息 引起了fd 的变化
{
memset(&User,0,sizeof(User));
ret=recv(fd[j],&User,sizeof(User),0);
if(ret == -1)
{
perror("recv");
exit(1);
}
if(User.type == 1)
//消息类型1:注册
{
zhuce(User,fd[j]);
}
if(User.type == 2)
//消息类型12:登录
{
login(User,fd[j]);
}
if(User.type == 3)
//消息类型13:私聊
{
chatprivate(User,fd[j]);
}
if(User.type == 4)
//消息类型14:群聊
{
chatall(User,fd[j],fd,i);
}
if(User.type == 5)
//消息类型15:开通会员
{
VIP(User);
}
if(User.type == 6)
//消息类型16:禁言
{
shutup(User);
}
if(User.type == 7)
//消息类型17:踢人
{
kickout(User);
}
if(User.type == 8)
//消息类型18:退出
{
quit(User);
}
if(User.type == 9)
//消息类型18:退出
{
jiejin(User);
}
}
}
}
}
return 0;
}
UDP参考网上小姐姐的代码 我做了封装
#ifndef _CHAT_H_
#define _CHAT_H_
#include <stdio.h>
#include <sqlite3.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <netinet/in.h> //包含socketaddr_in
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
#include <termios.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PORT 9999
#define reg 11 //注册,cmd
#define reg_success 12 //注册成功
#define existing 13 //账号已存在
#define log_in 14 //登录,cmd
#define log_success 15 //登录成功
#define logged 16 //账号已登录
#define log_error 17 //账号或密码错误
#define private_chat 18 //私聊
#define group_chat 19 //群聊
#define Gchat_failure 20 //群聊失败
#define online 21 //在线人数
#define Vip 22 //会员
#define shutup 23 //禁言
#define relieve 24 //解除禁言
#define kick 25 //踢人
#define face 26 //群发表情
#define send_useful 27 //发送常用语
#define Exit 28 //退出
#define quit 31 //下线
#define Send_success 29 //发送成功
#define Pchat_failure 30 //私聊失败
#define Send_failure 32 //发送失败
#define face_failure 33 //发送表情失败
#define vip_success 34 //开通会员成功
#define shutup_success 35 //禁言成功
#define kick_success 36 //踢人成功
#define shutup_failure 37 //禁言失败
#define kick_failure 38 //踢人失败
#endif
client_function.h
#ifndef _CLIENT_H_
#define _CLIENT_H_
struct info
{
char username[20]; //用户名
char password[20]; //密码
int cmd; //提取操作类型
int result; //返回标记
int port; //端口号
char message[50]; //保存信息
char toname[20]; //发送给谁
char fromname[20]; //从谁那里接收
char online_name[20][20]; //在线人员名单
int num;
int p_f;
char emoj[20]; //表情
int p_u;
char useful[20];
int vip;
char question[50];
char answer[50];
char file_name[50];
char file_content[2048];
};
//时间函数 自己百度查找
void time_show();
void welcome(void);
void bye(void);
void show();
//防止空格影响
void SCAN_N();
//登录之后的聊天界面
int chatshow();
//注册 将注册信息发送给服务器 进行注册 这里是确认注册信息的过程
int Register();
//登录 同上 确认登录信息
int Login();
//处理登陆后的函数
int deal_login();
//接收服务器发送的结果的接口函数
void *Recv_Server(void *arg);
#endif
client_main.c
\
#include "clientfunction.h"
#include "chat.h"
struct info RecvBuf; //接收方 的信息保存
struct info SendBuf; //发送方 的信息保存
struct sockaddr_in server_addr; //记录服务器地址 便于信息传输
char name[20] = { 0 };
int ret;
int sockfd;
int flag;
int out = 0;
//时间函数 自己百度查找
void time_show()
{
time_t rawtime;
struct tm *timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
printf("时间: %d 年 %d 月 %d 日 %d 时 %d 分 %d 秒\n\n", timeinfo->tm_year + 1900, timeinfo->tm_mon + 1,
timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
}
void welcome(void)
{
system("clear");
printf("\t\t\t*********************************************\n");
printf("\t\t\t* *\n");
printf("\t\t\t* *\n");
printf("\t\t\t* *\n");
printf("\t\t\t* Welcome To UDP Chatting Room ! *\n");
printf("\t\t\t* *\n");
printf("\t\t\t* *\n");
printf("\t\t\t* *\n");
printf("\t\t\t* *\n");
printf("\t\t\t*********************************************\n");
sleep(2);
}
void bye(void)
{
system("clear");
printf("\t\t\t*********************************************\n");
printf("\t\t\t\t* *\n");
printf("\t\t\t* *\n");
printf("\t\t\t* *\n");
printf("\t\t\t* Hope To See You Again ! *\n");
printf("\t\t\t* *\n");
printf("\t\t\t* *\n");
printf("\t\t\t* *\n");
printf("\t\t\t* *\n");
printf("\t\t\t*********************************************\n");
sleep(2);
}
void show()
{
system("clear");
printf("\t\t\t**********************************************\n");
printf("\t\t\t* *\n");
printf("\t\t\t* UDP聊天室 *\n");
printf("\t\t\t* *\n");
printf("\t\t\t* 1 注册 *\n");
printf("\t\t\t* 2 登录 *\n");
printf("\t\t\t* 3 退出 *\n");
printf("\t\t\t* *\n");
printf("\t\t\t* 请输入选择: *\n");
printf("\t\t\t**********************************************\n");
}
//防止空格影响
void SCAN_N()
{
char ch;
while ((getchar()) != '\n' && ch != EOF);//消除非法输入
}
//登录之后的聊天界面
int chatshow()
{
system("clear");
printf("\t\t\t");
time_show();
printf("\t\t\t**********************************************\n");
printf("\t\t\t* UDP聊天室!祝您聊天愉快! *\n");
printf("\t\t\t* 用户名:%s *\n", name);
if (SendBuf.vip == 1)
{
printf("\t\t\t* 尊贵的会员 *\n");
}
else
{
printf("\t\t\t* 普通用户 *\n");
}
printf("\t\t\t* *\n");
printf("\t\t\t* a 私聊 *\n");
printf("\t\t\t* b 群聊 *\n");
printf("\t\t\t* c 查看在线人数 *\n");
printf("\t\t\t* d 发送表情 *\n");
printf("\t\t\t* e 常用语 *\n");
printf("\t\t\t* f 开通会员 *\n");
printf("\t\t\t* g 禁言(需开通会员) *\n");
printf("\t\t\t* h 踢人(需开通会员) *\n");
printf("\t\t\t* i 查看聊天记录 *\n");
printf("\t\t\t* j 解禁 *\n");
printf("\t\t\t* k 退出 *\n");
printf("\t\t\t* 请输入您的选择: *\n");
printf("\t\t\t**********************************************\n");
}
//注册 将注册信息发送给服务器 进行注册 这里是确认注册信息的过程
int Register()
{
flag = 0;
system("clear");
SendBuf.cmd = reg;
char pass1[20] = { 0 };
char pass2[20] = { 0 };
printf("\t\t\t注册中......\n");
printf("\n\n");
printf("\t\t\t请输入你的用户名:\n");
printf("\t\t\t");
scanf("\t\t\t%s", SendBuf.username);
SCAN_N();
printf("\t\t\t请输入你的密码:\n");
printf("\t\t\t");
scanf("\t\t\t%s", pass1);
SCAN_N();
printf("\t\t\t请确认你的密码:\n");
printf("\t\t\t");
scanf("\t\t\t%s", pass2);
SCAN_N();
if (strcmp(pass1, pass2) != 0)
{
printf("\t\t\t密码输入不一致!请重新输入密码!\n");
printf("请在此重新输入你的密码:\n");
scanf("%s", pass2);
}
else
{
strcpy(SendBuf.password, pass1);
}
}
//登录 同上 确认登录信息
int Login()
{
system("clear");
SendBuf.cmd = log_in;
printf("\t\t\t登录中......\n");
printf("\n\n");
printf("\t\t\t请输入你的账号:\n");
printf("\t\t\t");
scanf("\t\t\t%s", SendBuf.username);
SCAN_N();
printf("\t\t\t请输入你的密码:\n");
printf("\t\t\t");
scanf("\t\t\t%s", SendBuf.password);
}
//处理登陆后的函数
int deal_login()
{
if (out == 1)
{
out--;
return Exit;
}
char choice2[10] = { 0 };
char file[2048] = { 0 };
char filename[50] = { 0 };
int fd;
while (1)
{
chatshow();
scanf("%s", choice2); //读入用户选择的功能字母
switch (choice2[0])
{
case 'a': //私聊
{
system("clear"); //清屏
if (flag == 23) //判断是否被禁言
{
printf("\n\t\t\t您已经被禁言了!\n");
sleep(2);
break;
}
printf("\t\t\t请输入对方的名字:\n");
printf("\t\t\t");
scanf("%s", SendBuf.toname);
SCAN_N();
printf("\t\t\t请输入您想要说的话:\n");
printf("\t\t\t");
scanf("%s", SendBuf.message);
SCAN_N();
SendBuf.cmd = private_chat; //操作符 为私聊
strcpy(SendBuf.username, name);
if (strcmp(SendBuf.toname, name) == 0)
{
sleep(1);
system("clear");
printf("\t\t\t不可以给自己发信息!\n");
printf("\t\t\t请重新输入用户名!\n");
break;
}
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
/* 发送给服务器 我要私聊某某 */
if (ret < 0)
{
perror("sendto_pchat");
exit(1);
}
sprintf(filename, "%s chat with %s.txt", name, SendBuf.toname);
fd = open(filename, O_CREAT | O_RDWR | O_APPEND, S_IRUSR | S_IWUSR);
if (fd == -1)
{
perror("open");
exit(1);
}
sprintf(file, "%s 给 %s 发送了一条消息:%s", name, SendBuf.toname, SendBuf.message);
ret = write(fd, file, strlen(file));
if (ret == -1)
{
perror("write");
exit(1);
}
printf("\t\t\t\t发送中...\n");
sleep(2);
break;
}
case 'b'://群聊
{
system("clear");
if (flag == 23) //同上
{
printf("\n\t\t\t您已经被禁言了!\n");
sleep(2);
break;
}
printf("\t\t\t请发送消息:\n");
scanf("%s", SendBuf.message);
SendBuf.cmd = group_chat;
strcpy(SendBuf.username, name);
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto_groupchat");
exit(1);
}
printf("\t\t\t发送中......\n");
sleep(2);
break;
}
case 'c': //查看在线人数
{
system("clear");
SendBuf.cmd = online; //操作符 查看在线
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto_onlinenum");
exit(1);
}
sleep(3); //注意如果人数很多 睡眠时间建议稍微长点 不然查看的效果很差
break;
}
case 'd': //群发表情
{
system("clear");
if (flag == 23)
{
printf("\n\t\t\t您已经被禁言了!\n");
sleep(2);
break;
}
char choice3[10] = { 0 };
SendBuf.cmd = face;
printf("\t\t\t**************************\n");
printf("\t\t\t1 感动 ≧◇≦ \n");
printf("\t\t\t2 无奈 ╮( ̄▽  ̄)╭\n");
printf("\t\t\t3 哭泣 T_T\n");
printf("\t\t\t4 惊讶 ⊙?⊙\n");
printf("\t\t\t5 喵 (= ̄ω ̄=)\n");
printf("\t\t\t6 害羞 (# ̄▽ ̄#)\n");
printf("\t\t\t请输入你的选择\n");
scanf("%s", choice3);
SendBuf.p_f = choice3[0];
strcpy(SendBuf.username, name);
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto_face");
exit(1);
}
printf("\t\t\t发送中......\n");
sleep(2);
break;
}
case 'e': //发送常用语
{
system("clear");
if (flag == 23)
{
printf("\n\t\t\t您已经被禁言了!\n");
sleep(2);
break;
}
char choice4[10] = { 0 };
printf("\t\t\t请输入对方的名字:\n");
printf("\t\t\t");
scanf("%s", SendBuf.toname);
strcpy(SendBuf.username, name);
SendBuf.cmd = send_useful;
printf("\t\t\t**************************\n");
printf("\t\t\t1 I see. 我明白了.\n");
printf("\t\t\t2 My god! 天哪!\n");
printf("\t\t\t3 No way! 不行!\n");
printf("\t\t\t4 Cheer up! 振作起来!\n");
printf("\t\t\t5 Good job! 做得好!\n");
printf("\t\t\t6 Bless you! 祝福你!\n");
printf("\t\t\t7 Thank you! 谢谢!\n");
printf("\n\t\t请输入你想发送的常用语:\n");
scanf("%s", choice4);
SCAN_N();
SendBuf.p_u = choice4[0];
if (strcmp(name, SendBuf.toname) == 0)
{
sleep(1);
system("clear");
printf("\t\t\t不可以给自己发送常用语");
printf("\t\t\t请重新输入用户名!\n");
return -1;
}
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto_useful");
exit(1);
}
printf("\n\t\t正在发送...\n");
sleep(2);
break;
}
case 'f': //开通会员
{
system("clear");
if (SendBuf.vip == 0)
{
char a[2];
system("clear");
printf("\n\n\n\t\t\t您确定要支付十万块成为会员吗?\n");
printf("\n\t\t\t您确认支付吗?(y/n)");
scanf("%s", a);
if (a[0] == 'y')
{
strcpy(SendBuf.username, name);
SendBuf.vip = 1;
SendBuf.cmd = Vip;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto_vip");
exit(1);
}
printf("\n\n\t\t请稍等...\n");
sleep(2);
}
else
{
break;
}
}
else if (SendBuf.vip == 1)
{
printf("您已经是会员了,无需再次开通!\n");
}
break;
}
case 'g': //禁言
{
if (SendBuf.vip == 1)
{
system("clear");
printf("请选择您想要禁言的人:\n");
scanf("%s", SendBuf.toname);
SendBuf.cmd = shutup;
strcpy(SendBuf.username, name);
if (strcmp(SendBuf.toname, name) == 0)
{
sleep(1);
system("clear");
printf("\t\t\t不可以禁言自己!\n");
printf("\t\t\t请重新输入用户名!\n");
break;
}
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto_shutup1");
exit(1);
}
printf("\n\n\t\t请稍等...\n");
sleep(2);
}
else if (SendBuf.vip == 0)
{
printf("您需要开通会员才能禁言别人哦!\n");
}
break;
}
case 'h': //踢人
{
if (SendBuf.vip == 1) //这里就不注意对方是不是会员了 会员之间相互踢还是可以的
{
system("clear");
printf("请选择您想要让他下线的人:\n");
scanf("%s", SendBuf.toname);
SendBuf.cmd = kick;
strcpy(SendBuf.username, name);
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto_kick1");
exit(1);
}
printf("\n\n\t\t请稍等...\n");
sleep(2);
}
else if (SendBuf.vip == 0)
{
printf("您需要开通会员才能让别人下线哦!");
}
break;
}
case 'i': //查看聊天记录
{
system("clear");
char n[20];
char filename1[50];
char file1[2048];
char kl;
int fd1;
int i = 0;
printf("\n\n\n\n\n\n\t\t\t您想看和谁的聊天记录呢?\n");
scanf("%s", n);
SCAN_N();
sprintf(filename1, "%s chat with %s.txt", name, n);
fd1 = open(filename1, O_RDONLY, S_IRUSR | S_IWUSR);
if (fd1 == -1)
{
system("clear");
printf("\n\n\n\n\n\n\n\t\t\t您与%s还没有聊天记录!\n", n);
break;
}
while (1)
{
memset(&kl, 0, sizeof(kl));
ssize_t read_bytes = read(fd1, &kl, sizeof(kl));
if (read_bytes == -1)
{
perror("read");
return -1;
}
if (read_bytes == 0)
{
break;
}
file1[i] = kl;
i++;
}
file1[i] = '\0';
printf("\n%s\n", file1);
sleep(3);
break;
}
case 'j': //解禁
{
char x[2];
if (flag == 0)
{
system("clear");
printf("\n\n\n\t\t\t您没有被禁言!\n");
}
else if (flag == 23)
{
if (SendBuf.vip == 0)
{
system("clear");
printf("\n\n\n\n\t\t\t您还没有开通会员,请先开通会员!\n");
}
else if (SendBuf.vip == 1)
{
system("clear");
printf("\n\n\n\n\t\t\t您想现在解禁吗!(y/n)\n");
scanf("%s", x);
SCAN_N();
if (x[0] == 'y')
{
flag = 0;
system("clear");
printf("\n\n\n\t\t\t恭喜您成功解禁!\n");
}
}
}
break;
}
case 'k': //下线
{
system("clear");
SendBuf.cmd = quit;
strcpy(SendBuf.username, name);
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto_quit1");
exit(1);
}
sleep(1);
return Exit;
}
case 'q':
return Exit;
default:
{
system("clear");
printf("\n\n\n\n");
printf("\n\n\t\t请输入a--z之间的选择!\n");
sleep(2);
break;
}
}
}
}
//接收服务器发送的结果的接口函数
void *Recv_Server(void *arg)
{
char q;
int i;
int length = sizeof(server_addr);
while (1)
{
ret = recvfrom(*(int *)arg, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&server_addr, &length);
if (ret < 0)
{
perror("recvfrom");
exit(1);
}
switch (RecvBuf.result)
{
case(private_chat) :
{
printf("\t\t\t%s 给你发了一条消息:%s\n", RecvBuf.fromname, RecvBuf.message);
memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));
break;
}
case(Send_success) :
{
system("clear");
printf("\t\t\t发送成功\n");
memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));
break;
}
case(Send_failure) :
{
system("clear");
printf("\t\t\t发送失败,对方不在线\n");
memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));
break;
}
case(Pchat_failure) :
{
system("clear");
printf("\t\t\t对不起,对方不在线!\n");
memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));
break;
}
case(group_chat) :
{
printf("\t\t\t%s 群发了一条消息:%s\n", RecvBuf.fromname, RecvBuf.message);
memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));
break;
}
case(Gchat_failure) :
{
system("clear");
printf("\t\t\t群聊失败!\n");
memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));
break;
}
case(online) :
{
system("clear");
printf("\t\t\t当前在线好友人数: %d\n", RecvBuf.num);
for (i = 0; i < RecvBuf.num; i++)
{
printf("\t\t\t%s\n", RecvBuf.online_name[i]);
}
memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));
break;
}
case(face) :
{
char emoj1[20] = { 0 };
switch (RecvBuf.p_f)
{
case '1':
{
strcpy(emoj1, "感动 ≧◇≦");
printf("\t\t\t%s 给大家发了一个表情:%s\n", RecvBuf.fromname, emoj1);
break;
}
case '2':
{
strcpy(emoj1, "无奈 ╮( ̄▽  ̄)╭");
printf("\t\t\t%s 给大家发了一个表情:%s\n", RecvBuf.fromname, emoj1);
break;
}
case '3':
{
strcpy(emoj1, "哭泣 T_T");
printf("\t\t\t%s 给大家发了一个表情:%s\n", RecvBuf.fromname, emoj1);
break;
}
case '4':
{
strcpy(emoj1, "惊讶 ⊙?⊙");
printf("\t\t\t%s 给大家发了一个表情:%s\n", RecvBuf.fromname, emoj1);
break;
}
case '5':
{
strcpy(emoj1, "喵 (= ̄ω ̄=)");
printf("\t\t\t%s 给大家发了一个表情:%s\n", RecvBuf.fromname, emoj1);
break;
}
case '6':
{
strcpy(emoj1, "害羞 (# ̄▽ ̄#)");
printf("\t\t\t%s 给大家发了一个表情:%s\n", RecvBuf.fromname, emoj1);
break;
}
}
break;
}
case(face_failure) :
{
system("clear");
printf("发送失败,没有该表情!\n");
sleep(2);
memset(&RecvBuf.result, 0, sizeof(RecvBuf.result));
break;
}
case (send_useful) :
{
char ue[50];
switch (RecvBuf.p_u)
{
case '1':
strcpy(ue, "I see. 我明白了.");
printf("\t\t\t%s给你发送了一句常用语:%s\n", RecvBuf.fromname, ue);
break;
case '2':
strcpy(ue, "My god! 天哪!");
printf("\t\t\t%s给你发送了一句常用语:%s\n", RecvBuf.fromname, ue);
break;
case '3':
strcpy(ue, "3 No way! 不行!");
printf("\t\t\t%s给你发送了一句常用语:%s\n", RecvBuf.fromname, ue);
break;
case '4':
strcpy(ue, "Cheer up! 振作起来!");
printf("\t\t\t%s给你发送了一句常用语:%s\n", RecvBuf.fromname, ue);
break;
case '5':
strcpy(ue, "Good job! 做得好!");
printf("\t\t\t%s给你发送了一句常用语:%s\n", RecvBuf.fromname, ue);
break;
case '6':
strcpy(ue, "Bless you! 祝福你!");
printf("\t\t\t%s给你发送了一句常用语:%s\n", RecvBuf.fromname, ue);
break;
case '7':
strcpy(ue, "Thank you! 谢谢!");
printf("\t\t\t%s给你发送了一句常用语:%s\n", RecvBuf.fromname, ue);
break;
}
break;
}
case(vip_success) :
{
printf("\t\t\t恭喜您成功开通会员\n");
sleep(2);
break;
}
case(shutup) :
{
flag = 23;
printf("\t\t\t%s已经把您禁言了!\n", RecvBuf.fromname);
break;
}
case(shutup_success) :
{
printf("\t\t\t禁言成功!\n");
sleep(2);
break;
}
case(shutup_failure) :
{
printf("\t\t\t对方不在线,禁言失败!\n");
break;
}
case(kick) :
{
out = 1;
printf("\t\t\t您已经被%s踢出了聊天室,请重新登录!\n", RecvBuf.fromname);
printf("\t\t\t输入q返回!\n");
break;
}
case(kick_success) :
{
printf("\t\t\t踢人成功!\n");
sleep(2);
break;
}
case(kick_failure) :
{
printf("\t\t\t对方不在线,踢人失败!\n");
break;
}
case(quit) :
{
system("clear");
printf("您已经成功下线!\n");
sleep(2);
break;
}
}
}
}
int main()
{
int length = sizeof(server_addr);
char choice[10] = { 0 };
pthread_t tid;
sockfd = socket(PF_INET, SOCK_DGRAM, 0); //创建套接字
if (-1 == sockfd)
{
perror("sockt");
exit(1);
}
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = PF_INET;
server_addr.sin_port = PORT;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
welcome();
while (1)
{
show();
scanf("%s", choice);
switch (atoi(&choice[0]))
{
case 1: //注册
{
if (Register() == -12)
{
break;
}
else
{
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto_register");
exit(1);
}
bzero(&SendBuf, sizeof(SendBuf));
ret = recvfrom(sockfd, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&server_addr, &length);
if (ret < 0)
{
perror("recvfrom_register");
exit(1);
}
if (RecvBuf.result == reg_success)
{
printf("\n\n\t\t\t恭喜您注册成功!\n");
}
else if (RecvBuf.result == existing)
{
printf("\n\n\t\t\t该账户已被注册!请重新注册!\n");
}
sleep(2);
break;
}
}
case 2: //登录
{
if (Login() == -14)
{
break;
}
else
{
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto_login");
exit(1);
}
bzero(&SendBuf, sizeof(SendBuf));
ret = recvfrom(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&server_addr, &length);
if (ret < 0)
{
perror("recvfrom_login");
exit(1);
}
if (SendBuf.result == log_success)
{
printf("\n\n\t\t\t恭喜你登录成功!\n");
strcpy(name, SendBuf.username);
sleep(2);
ret = pthread_create(&tid, NULL, (void *)Recv_Server, (void *)&sockfd); //起一个线程专门用来接收服务器发送给客户端的结果反馈
if (ret < 0)
{
perror("pthread_create");
exit(1);
}
pthread_detach(tid);
ret = deal_login();
if (ret == Exit)
{
break;
}
}
else if (SendBuf.result == logged)
{
printf("\n\n\t\t\t账号已登录!\n");
}
else if (SendBuf.result == log_error)
{
printf("\n\n\t\t\t账号或密码错误,请重新登录!\n");
}
}
break;
}
case 3:
{
bye();
system("clear");
exit(1);
break;
}
default:
{
system("clear");
printf("\n\n\n\n");
printf("\n\n\t\t请输入1--3之间的选择!\n");
sleep(2);
break;
}
}
}
return 0;
}
server_function.h
#ifndef _SERVER_H_
#define _SERVER_H_
#include "chat.h"
struct info
{
char username[20]; //用户名
char password[20]; //密码
int cmd; //提取操作类型
int result; //返回标记
int port; //端口号
char message[50]; //保存信息
char toname[20]; //发送给谁
char fromname[20]; //从谁那里接收
char online_name[20][20]; //在线人员名单
int num;
int p_f;
char emoj[20]; //表情
int p_u;
char useful[20];
int vip;
char question[50];
char answer[50];
char file_name[50];
char file_content[2048];
};
struct node
{
struct sockaddr_in client_addr; //保存客户地址
char name[20]; //记录客户姓名
struct node *next; //指向下一个用户
};
/*sockaddr_in 是internet环境下套接字的地址形式;;sockaddr_in在头文件#include<netinet/in.h>或#include <arpa/inet.h>中定义*/
typedef struct node Node; //起别名 简化结构体 取名为 Node 用Node创建新结构体 存储客户信息
typedef Node *Lnode; //同样 结构体取指针别名 对应的函数返回值是结构体类型
//注册函数
void register1();
//登录函数
void login(struct sockaddr_in tmp_addr);
//处理私聊
int deal_private(struct sockaddr_in tmp_addr);
//处理群聊 同上
int deal_group(struct sockaddr_in tmp_addr);
//显示在线人数
int deal_online();
//处理群发表情 同上
int deal_face(struct sockaddr_in tmp_addr);
//处理发送常用语 同上
int deal_useful(struct sockaddr_in tmp_addr);
//处理vip
int deal_vip(struct sockaddr_in tmp_addr);
//处理禁言 同上
int deal_shutup(struct sockaddr_in tmp_addr);
//处理踢人 同上
int deal_kick(struct sockaddr_in tmp_addr);
//处理下线
int deal_quit();
#endif
server_main.c
#include "serverfunction.h"
#include "chat.h"
struct info RecvBuf; //接收方 的信息保存
struct info SendBuf; //发送方 的信息保存
sqlite3 *ppdb = NULL; //打开一个数据库实例
int ret;
int sockfd;
Lnode head = NULL; //创建第一个节点
//注册函数
void register1()
{
char sql[100] = { 0 };
sprintf(sql, "insert into chat(username,password,vip) values('%s','%s','%d')", RecvBuf.username, RecvBuf.password, RecvBuf.vip);
/*将数据插入到 sql数据库中,上述语句在执行完sprintf语句后,
sql中保存的是INSERT语句字符串,可实现正确的插入。*/
char *errmsg = NULL; //保存 错误的原因
int ret;
ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg); /*如果没有成功创建数据库实例则报错
(参考https://www.cnblogs.com/zfyouxi/p/5258589.html*/
if (ret != SQLITE_OK)
{
perror("sqlite3_exec2");
SendBuf.result = existing; //账号已存在
printf("%s is insert failure:%s\n\n", RecvBuf.username, errmsg); //输出错因
return;
}
//没有报错即成功
printf("user insert success!yohoo~\n\n");
SendBuf.result = reg_success;
}
//登录函数
void login(struct sockaddr_in tmp_addr)
{
char sql[100] = { 0 };
char **Result = NULL; //返回记录,二维数组
int nrow; //查找出的 行数
int ncolumn; //查找出的 列数
int ret;
int i;
sprintf(sql, "select username, password ,vip from chat where username = '%s' and password = '%s'", RecvBuf.username, RecvBuf.password);
//查询语句 查看登录的用户信息
ret = sqlite3_get_table(ppdb, sql, &Result, &nrow, &ncolumn, NULL);/* char **dbResult; 字符型的二重指针,
将数据库里sqlite3_get_table()出来的数据以字符的方式给dbResult。*/
if (ret != SQLITE_OK) //未查询到表单数据
{
perror("sqlite3_get_table_login");
return;
}
if (1 == nrow) //如果chat表中已经有一个数据 同时数据的用户名和现在准备登录的用户名相同 则不允许登录
{
Lnode tmp = head->next;
Lnode p = (Lnode)malloc(sizeof(Node)); //创建一个节点存储用户信息
if (p == NULL)
{
printf("FAILURE!\n\n");
return;
}
while (tmp != head)
{
if (!strcmp(tmp->name, Result[3]))
{
printf("您的账号已登录!\n\n");
SendBuf.result = logged;
return;
}
tmp = tmp->next;
}
SendBuf.result = log_success;
strcpy(p->name, Result[3]); //存储用户名字
strcpy(SendBuf.username, Result[3]);
SendBuf.vip = *(Result[5]) - 48;
p->client_addr.sin_family = tmp_addr.sin_family;
p->client_addr.sin_port = tmp_addr.sin_port;
p->client_addr.sin_addr.s_addr = tmp_addr.sin_addr.s_addr;
printf("记录到 %s 的端口号是 : %d\n", p->name, p->client_addr.sin_port);
p->next = head->next;
head->next = p;
printf("%s 处于登录状态!\n\n", Result[3]);
}
else
{
SendBuf.result = log_error;
printf("您的账号或密码错误,请重新登录!\n\n");
}
}
//处理私聊
int deal_private(struct sockaddr_in tmp_addr)
{
int postion = 0; //创建一个标志位
Lnode tmp = head->next;
while (tmp != head)
{
if (strcmp(tmp->name, RecvBuf.toname) == 0) //查询 找到 用户名和接收名 相同 发送信息过去
{
postion = 1;
strcpy(SendBuf.message, RecvBuf.message);
strcpy(SendBuf.fromname, RecvBuf.username);
SendBuf.result = private_chat;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
if (ret == -1)
{
perror("sendto_chat");
exit(1);
}
break;
}
tmp = tmp->next;
}
if (postion)
{
SendBuf.result = Send_success;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret == -1)
{
perror("sendto_success");
exit(1);
}
}
else
{
SendBuf.result = Pchat_failure;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret == -1)
{
perror("sendto_failure");
exit(1);
}
}
}
//处理群聊 同上
int deal_group(struct sockaddr_in tmp_addr)
{
int postion = 0;
Lnode tmp = head->next;
while (tmp != head)
{
if (tmp->client_addr.sin_port != tmp_addr.sin_port)
{
postion = 1;
SendBuf.result = group_chat;
strcpy(SendBuf.fromname, RecvBuf.username);
printf("%s\n", SendBuf.fromname);
strcpy(SendBuf.message, RecvBuf.message);
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
if (ret < 0)
{
perror("sendto_group_chat");
exit(1);
}
}
tmp = tmp->next;
}
if (1 == postion)
{
SendBuf.result = Send_success;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret < 0)
{
perror("sendto_group_chat_success");
exit(1);
}
}
else
{
SendBuf.result = Gchat_failure;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret < 0)
{
perror("sendto_group_chat_failure");
exit(1);
}
}
}
//显示在线人数
int deal_online()
{
int i = 0;
SendBuf.num = 0;
Lnode tmp = head->next;
while (tmp != head)
{
SendBuf.num++;
strcpy(SendBuf.online_name[i], tmp->name);
i++;
tmp = tmp->next;
}
SendBuf.result = online;
}
//处理群发表情 同上
int deal_face(struct sockaddr_in tmp_addr)
{
int postion = 0;
Lnode tmp = head->next;
while (tmp != head)
{
if (tmp->client_addr.sin_port != tmp_addr.sin_port)
{
postion = 1;
SendBuf.result = face;
strcpy(SendBuf.fromname, RecvBuf.username);
SendBuf.p_f = RecvBuf.p_f;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
if (ret < 0)
{
perror("sendto_face");
exit(1);
}
}
tmp = tmp->next;
}
if (1 == postion)
{
SendBuf.result = Send_success;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret < 0)
{
perror("sendto_face_success");
exit(1);
}
}
else
{
SendBuf.result = face_failure;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret < 0)
{
perror("sendto_face_failure");
exit(1);
}
}
}
//处理发送常用语 同上
int deal_useful(struct sockaddr_in tmp_addr)
{
int postion = 0;
Lnode tmp = head->next;
while (tmp != head)
{
if (strcmp(tmp->name, RecvBuf.toname) == 0)
{
postion = 1;
SendBuf.result = send_useful;
SendBuf.p_u = RecvBuf.p_u;
strcpy(SendBuf.fromname, RecvBuf.username);
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
if (ret == -1)
{
perror("sendto_useful");
exit(1);
}
break;
}
tmp = tmp->next;
}
if (postion)
{
SendBuf.result = Send_success;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret == -1)
{
perror("sendto_success");
exit(1);
}
}
else
{
SendBuf.result = Send_failure;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret == -1)
{
perror("sendto_failure");
exit(1);
}
}
}
//处理vip
int deal_vip(struct sockaddr_in tmp_addr)
{
char sql[100] = { 0 };
sprintf(sql, "update chat set vip= %d where username = '%s';", RecvBuf.vip, RecvBuf.username);
//更新数据库 信息即可
ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
if (ret != SQLITE_OK)
{
perror("sqlite3_exec");
return;
}
SendBuf.vip = 1; //VIP 标志位 置一
SendBuf.result = vip_success;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret == -1)
{
perror("sendto_vip_failure");
exit(1);
}
printf("%s 恭喜您成为了会员 ...\n", SendBuf.username);
return 0;
}
//处理禁言 同上
int deal_shutup(struct sockaddr_in tmp_addr)
{
Lnode tmp = head->next;
int postion = 0;
while (tmp != head)
{
if (strcmp(tmp->name, RecvBuf.toname) == 0)
{
postion = 1;
SendBuf.result = shutup;
strcpy(SendBuf.fromname, RecvBuf.username);
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
if (ret < 0)
{
perror("sendto_shutup");
return;
}
}
tmp = tmp->next;
}
if (postion)
{
SendBuf.result = shutup_success;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret < 0)
{
perror("sendto_shutup_success");
return;
}
}
else
{
SendBuf.result = shutup_failure;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret < 0)
{
perror("sendto_shutup_failure");
return;
}
}
}
//处理踢人 同上
int deal_kick(struct sockaddr_in tmp_addr)
{
int postion = 0;
Lnode tmp = head->next;
while (tmp != head)
{
if (strcmp(tmp->name, RecvBuf.toname) == 0)
{
postion = 1;
SendBuf.result = kick;
strcpy(SendBuf.fromname, RecvBuf.username);
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp->client_addr, sizeof(tmp->client_addr));
if (ret < 0)
{
perror("sendto_kick");
return;
}
Lnode p = tmp->next; //借用指针将该处的人员删除 将后面的人员连接上来 代替此处人员
tmp->next = p->next;
free(p);
printf("%s logged out...\n", RecvBuf.username);
break;
}
tmp = tmp->next;
}
if (postion == 1)
{
SendBuf.result = kick_success;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret < 0)
{
perror("sendto_kick_success");
exit(1);
}
}
else
{
SendBuf.result = kick_failure;
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&tmp_addr, sizeof(tmp_addr));
if (ret < 0)
{
perror("sendto_shutup_failure");
exit(1);
}
}
}
//处理下线
int deal_quit()
{
Lnode tmp = head;
//1.如果是头结点
if (tmp->next->next == head)
{
if (strcmp(tmp->next->name, RecvBuf.username) == 0)
{
Lnode p = tmp->next; //借用指针将该处的人员删除 将后面的人员连接上来 代替此处人员
tmp->next = p->next;
free(p);
printf("%s logged out...\n", RecvBuf.username);
return;
}
tmp = tmp->next;
}
//2.不是头结点
while (tmp->next != head)
{
if (strcmp(tmp->next->name, RecvBuf.username) == 0)
{
SendBuf.result = quit;
Lnode l = tmp->next;
tmp->next = l->next;
free(l);
printf("%s logged out...\n", RecvBuf.username);
break;
}
tmp = tmp->next;
}
return 0;
}
int main()
{
struct sockaddr_in server_addr; //创建服务器 地址
struct sockaddr_in client_addr; //创建客户端 地址
int length;
int position;
char sql[100] = { 0 };
head = (Lnode)malloc(sizeof(Node));
if (NULL == head)
{
printf("Malloc Failure!\n");
return;
}
head->next = head;
sockfd = socket(PF_INET, SOCK_DGRAM, 0); //创建服务平台
if (-1 == sockfd)
{
perror("socket");
exit(1);
}
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = PORT;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //地址确定为 127.0.0.1
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); //服务器地址绑定
if (ret < 0)
{
perror("bind");
exit(1);
}
ret = sqlite3_open("chat.db", &ppdb); //如果存在 chat数据库 打开(可能是第二次执行程序的时候
if (ret != SQLITE_OK)
{
perror("sqlite3_open");
exit(1);
}
sprintf(sql, "create table if not exists chat (username text primary key, password text,vip integer);");
/* 如果不存在chat数据库 就创建一个chat */
ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
if (ret != SQLITE_OK)
{
perror("sqlite3_exec1");
exit(1);
}
while (1)
{
length = sizeof(client_addr);
ret = recvfrom(sockfd, &RecvBuf, sizeof(RecvBuf), 0, (struct sockaddr *)&client_addr, &length); //循环处理 接收信息
if (ret < 0)
{
perror("recvfrom");
exit(1);
}
printf("Recv From Client %d\n", client_addr.sin_port); //输出(地址) 接收自哪个客户端
printf("username is : %s\tpassword is : %s\n", RecvBuf.username, RecvBuf.password);
switch (RecvBuf.cmd) //根据接收到的 信息类型 执行相应的函数
{
case (reg) : //注册
{
register1();
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&client_addr, sizeof(client_addr)); //打包信息
if (ret < 0)
{
perror("sendto_server_register");
exit(1);
}
break;
}
case (log_in) : //登录
{
login(client_addr);
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&client_addr, sizeof(client_addr));
if (ret < 0)
{
perror("sendto_server_log_in");
exit(1);
}
break;
}
case (private_chat) : //私聊
{
deal_private(client_addr);
break;
}
case(group_chat) : //群聊
{
deal_group(client_addr);
break;
}
case(online) : //查看在线人数
{
deal_online();
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&client_addr, sizeof(client_addr));
if (ret == -1)
{
perror("sendto_online");
}
break;
}
case(face) : //群发表情
{
deal_face(client_addr);
break;
}
case(send_useful) : //发送常用语
{
deal_useful(client_addr);
break;
}
case(Vip) : //开通会员
{
deal_vip(client_addr);
break;
}
case(shutup) : //禁言
{
deal_shutup(client_addr);
break;
}
case(kick) : //踢人
{
deal_kick(client_addr);
break;
}
case(quit) : //下线
{
deal_quit();
ret = sendto(sockfd, &SendBuf, sizeof(SendBuf), 0, (struct sockaddr *)&client_addr, sizeof(client_addr));
if (ret == -1)
{
perror("sendto_quit");
}
break;
}
}
}
sqlite3_close(ppdb); //最后关闭数据库
return 0;
}