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是最简单的

服务器:

  1. 创建socket
  2. 绑定 bind
  3. 接受信息 recvfrom
  4. 指定发送的对象 sendto

客户端:

  1. 创建Socket
  2. Sendto 发送信息
  3. 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 1234struct 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 1234struct 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.1ret = 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;
}

方案二、三SELECT、UDP完成聊天室相关推荐

  1. 【UDP实现聊天室(附带源码)】eclipse平台

    要求: udp实现聊天室,要求服务端只负责好友列表的刷新,不负责消息的转发 服务端: 1.服务端监听的是3000端口,其他用户统一对3000进行监听,实现实时的好友列表更新: 2.好友列表list和l ...

  2. websocket(二):SSM+websocket的聊天室

    在github上面找了一个看起来还不错的网页版聊天室,基于ssm加websocket实现的,特此分享一下,github地址放在文章末尾,大家可以自行下载跑起来玩玩,项目如何跑起来我写在readme里面 ...

  3. java通信二:利用Socket实现聊天室功能

    最近研究了下java socket通信基础,利用代码实现了一个简单的多人聊天室功能,现把代码共享下,希望能帮到有兴趣了解的人. 目录结构: ChatClient: package com.panda. ...

  4. LinuxC语言のUDP简易聊天室 sokcet

    设计思路 考虑到只是一个简易版本的UDP聊天服务,所以很多不完善的地方 服务器 服务器我是开了一个父子进程,分别负责的 接受客户端的消息&&发送某一个客户端的信息 服务器的命令终端(只 ...

  5. Select 实现网络聊天室功能 (服务器端)

    服务器端: ChatRoom.h #ifndef _CHATROOM_H_H #define _CHATROOM_H_H#include <stdio.h> #include <st ...

  6. 【Linux网络编程】基于UDP实现多人聊天室

    文章目录 一.UDP的概念 1.1 UDP 1.2 UDP特点 二. 采用UDP实现多人聊天室原因 三.多人聊天室项目功能 四.实现多人聊天室项目流程分析 4.1 前期准备 4.1.1 定义结构体 4 ...

  7. 比心聊天室的架构演进

    一.比心语音房技术基本介绍 作为一家泛娱乐公司,语音业务是比心最重要的业务之一,而其中最核心的场景就是基于语音房技术实现的聊天室产品.相比于一般的业务系统,语音房业务系统的技术难度会更高一些,其难点主 ...

  8. 快速接入 | 从 0 到 1 构建语音聊天室

    导读:近年来,在线语音聊天的用户量持续上升.语音可承载的信息密度比文字图片丰富,又比视频更简单,不失为一种抓住Z世代年轻用户和实现流量变现的有效途径.为了满足用户的情感需求.娱乐需求和价值观认同,越来 ...

  9. AgileEAS.NET SOA 中间件平台.Net Socket通信框架-完整应用例子-在线聊天室系统-代码解析...

    一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台.Net Socket通信框架-介绍一文之中我们对AgileEAS.NET S ...

最新文章

  1. 监控Oracle性能的SQL
  2. android好用的第三方库2018使用总结
  3. linux 监控命令
  4. 二元隐函数求二阶偏导_在线计算专题(03):具体、抽象函数的导数、微分与方向导数的计算...
  5. Android之ActivityManage长用方法总结
  6. shell脚本手动执行成功,定时任务调用失败的解决方法。
  7. 力扣1103.分糖果
  8. 2018-2019-2 20165118 《网络对抗技术》Exp4 恶意代码分析
  9. Javascript连接数据库并查询和插入数据
  10. MySQL frm、MYD、MYI数据文件恢复
  11. Linux 创建无线热点
  12. linux命令获取reboot信息,linux的reboot命令
  13. 150. 逆波兰表达式求值(中等 栈 数组)
  14. Yapi 可视化接口管理平台部署文档
  15. table 点击文字按钮预览图片
  16. 【汇正财经】电网设备,享受改革的硕果
  17. 科研,办公几款强大又实用的软件(含安装包)
  18. 千峰java 笔记整理_JAVA学习笔记系列:菜鸟Vue学习笔记(四)
  19. 【操作系统 3.了解实模式与保护模式的区别】
  20. 28人买可乐喝,3个可乐瓶盖可以换一瓶可乐,那么要买多少瓶可乐,够28人喝?假如是50人,又需要买多少瓶可乐?(解读误区)

热门文章

  1. php oop 实际工作,PHP OOP注意点(一)
  2. php 解析配置文件,php 解析ini配置文件
  3. python鸡兔同笼编程输出不存在合理答案_Python 解答鸡兔同笼和五家共井问题
  4. 天气预报c是什么意思_大雪节气将至,为什么老话说:寒风迎大雪,三九天气暖?...
  5. github流程图_「强烈推荐」开源的在线流程图工具--draw.io
  6. linux eclipse 配置c++开发环境,用Eclipse搭建C/C++开发环境
  7. python fetchall方法_Python连接MySQL并使用fetchall()方法过滤特殊字符
  8. linux常见面试题
  9. java 图像处理 空白_使用Java进行图像处理的一些基础操作
  10. 为什么能通过域成员主机拿下域控服务器的密码呢