实现目标
一个在Linux下可以使用的聊天软件,要求至少实现如下功能:
1. 采用Client/Server架构
2. Client A 登陆聊天服务器前,需要注册自己的ID和密码
3. 注册成功后,Client A 就可以通过自己的ID和密码登陆聊天服务器
4. 多个Client X 可以同时登陆聊天服务器之后,与其他用户进行通讯聊天
5. Client A成功登陆后可以查看当前聊天室内其他在线用户Client x
6. Client A可以选择发消息给某个特定的Client X,即”悄悄话”功能
7. Client A 可以选择发消息全部的在线用户,即”群发消息”功能
8. Client A 在退出时需要保存聊天记录
9. Server端维护一个所有登陆用户的聊天会的记录文件,以便备查
可以选择实现的附加功能:
1. Server可以内建一个特殊权限的账号admin,用于管理聊天室
2. Admin可以将某个Client X “提出聊天室”
3. Admin可以将某个Client X ”设为只能旁听,不能发言”
4. Client 端发言增加表情符号,可以设置某些自定义的特殊组合来表达感情.如输入:),则会自动发送”XXX向大家做了个笑脸”
5. Client段增加某些常用话语,可以对其中某些部分进行”姓名替换”,例如,输入/ClientA/welcome,则会自动发送”ClientA 大侠,欢迎你来到咱们的聊天室”
附加功能:
文件传输
部分主要代码:
客户端:
client_main.h
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <signal.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <string.h>
- #include <errno.h>
- #include <pthread.h>
- #include <sys/types.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #define PORT 6666
- #define MAXLEN 1000
- #define OK 1
- #define FAULT 0
- struct message /*消息结构体*/
- {
- char flag[15]; /*标志位*/
- char name[20]; /*用户名*/
- char msg[MAXLEN]; /*消息内容*/
- char addressee[20]; /*传输文件目的用户*/
- int size; /*传输内容字节数*/
- };
- int qid = -1,fd = -1;
- int sockfd = -1; /*套接字描述符*/
- int savefilefd = -1; /*保存文件描述符*/
- char filefromname[20]; /*文件来源名*/
- char chat_log[100]; /*聊天记录名*/
- pthread_mutex_t lock ; /*线程锁*/
client_handle.h
- #ifndef CLIENT_HANDLE_H
- #define CLIENT_HANDLE_H
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <signal.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <string.h>
- #include <errno.h>
- #include <pthread.h>
- #include <sys/types.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #define PORT 8888
- #define MAXLEN 1000
- #define OK 1
- #define FAULT 0
- struct message /*消息结构体*/
- {
- char flag[15]; /*标志位*/
- char name[20]; /*用户名*/
- char msg[MAXLEN]; /*消息内容*/
- char addressee[20]; /*传输文件目的用户*/
- int size; /*传输内容字节数*/
- };
- extern int qid,fd;
- extern int sockfd; /*套接字描述符*/
- extern int savefilefd; /*保存文件描述符*/
- extern char filefromname[20]; /*文件来源名*/
- extern char chat_log[100]; /*聊天记录名*/
- extern pthread_mutex_t lock ; /*线程锁*/
- char filefromuser[20]; /*文件发送者用户名*/
- char locname[20]; /*本客户端用户名*/
- int Interface();
- void cutStr(char str[],char left[], int n, char right[],int m, char c);
- int help(char str[]);
- void expression(char name[],char msg[]);
- void common_use_words(char msg[]);
- void handlesendfile();
- void handlerecvfile(struct message *msg);
- void handlerecvmsg(int *sockfd);
- int admin_kick(int sockfd,struct message *a);
- int admin_screen(int sockfd,struct message *a);
- int login_admin(struct message *a);
- int login_success(struct message *a);
- int Register(struct message *a);
- void log_user(struct message *a);
- #endif //CLIENT_HANDLE_H
my_system_call.h
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <signal.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <string.h>
- #include <errno.h>
- #include <pthread.h>
- #include <sys/types.h>
- #include <fcntl.h>
- #include <sys/stat.h>
client_main.c
- /***************************************************
- File name: client.c
- Author:Chenchunjian
- Data:2012
- Description:聊天软件客户端main函数
- ***************************************************/
- #include "../../include/client_main.h"
- int main(int argc, char *argv[])
- {
- int ret;
- int do_number;
- char str[MAXLEN];
- char buf[MAXLEN];
- char buf_new[100];
- struct message msg;
- struct message a;
- struct sockaddr_in my_addr;
- time_t timep;
- enum action{log=1,reg,ex};
- struct hostent *host;
- if(argc!=2)
- {
- fprintf(stderr,"Usage:%s hostname \a\n",argv[0]);
- exit(1);
- }
- if((host=gethostbyname(argv[1]))==NULL)
- {
- fprintf(stderr,"Gethostname error\n");
- exit(1);
- }
- while(1)
- {
- if((sockfd=my_socket(PF_INET,SOCK_STREAM,0)) < 0) /*创建套接字,使用TCP协议*/
- {
- exit(-1);
- }
- bzero(&my_addr,sizeof(struct sockaddr_in)); /*清空地址结构*/
- my_addr.sin_family = AF_INET; /*使用IPV4通信域*/
- my_addr.sin_port = htons(PORT); /*端口号转换为网络字节序*/
- my_addr.sin_addr = *((struct in_addr *)host->h_addr); /*可接受任意地址*/
- if(my_connect(sockfd,(struct sockaddr *)(&my_addr),sizeof(my_addr)) == -1) /*主动连接服务器*/
- {
- printf("正在连接,请稍等……\n");
- exit(1);
- }
- do_number = Interface(); /*登录界面*/
- switch(do_number)
- {
- case log: /*登录*/
- {
- int n = 3;
- while(n)
- {
- log_user(&a);
- if(my_strcmp(a.msg,"hello,admin!") == 0) /*管理员登录成功*/
- {
- if(login_admin(&a) == 0)
- {
- return FAULT;
- }
- }
- if(my_strcmp(a.msg,"login,success!") == 0) /*用户登录成功*/
- {
- if(login_success(&a) == FAULT)
- {
- return FAULT;
- }
- }
- else /*登录未成功*/
- {
- n--;
- printf("你还有 %d次机会!\n",n);
- }
- }
- my_close(sockfd);
- exit(3);
- break;
- }
- case reg: /*注册*/
- {
- Register(&a);
- break;
- }
- case ex: /*退出*/
- {
- my_close(sockfd);
- printf("离开聊天室!\n");
- break;
- }
- default:
- {
- break;
- }
- }
- }
- my_close(sockfd);
- return FAULT;
- }
admin.c
- #include "../../include/client_handle.h"
- /***************************************************
- 函数名:admin_chat
- 功能:管理员聊天功能
- 传入参数:int sockfd,struct message *a
- 返回值:退出返回FAULT
- ***************************************************/
- int admin_chat(int sockfd,struct message *a)
- {
- char str[MAXLEN];
- char buf[MAXLEN];
- time_t timep;
- sprintf(chat_log,"./chat_log/%s.txt",(*a).name);
- if((fd=my_open(chat_log,O_RDWR|O_CREAT|O_APPEND,0777)) < 0)
- {
- printf("打开聊天记录失败!");
- exit(1);
- }
- setbuf(stdin,NULL);
- my_strcpy((*a).flag,"all");
- printf("尊敬的%s你好,如需帮助请输入:.help\n",locname);
- while(1)
- {
- memset((*a).msg,0,strlen((*a).msg));
- memset(str,0,strlen(str));
- usleep(100000);
- printf("TO %s:\n",(*a).flag);
- setbuf(stdin,NULL);
- gets(str);
- if(OK == help(str)) //提示信息
- {
- continue;
- }
- my_strcpy((*a).name,locname);
- my_strcpy(buf,(*a).flag);
- cutStr(str,(*a).flag,15,(*a).msg,MAXLEN,'$'); //调用字符切割函数
- expression((*a).name,(*a).msg); //表情替换函数
- common_use_words((*a).msg); //常用语使用函数
- if(my_strcmp((*a).flag,"exit") == 0)
- {
- return FAULT;
- }
- if(my_strcmp((*a).flag,"view") == 0)
- {
- my_send(sockfd,a,sizeof((*a)),0); //请求查看在线用户
- my_strcpy((*a).flag,buf);
- continue;
- }
- if(my_strcmp((*a).flag,"all") == 0)
- {
- my_send(sockfd,a,sizeof(*a),0);
- continue;
- }
- if ((my_strcmp((*a).flag,"trans") == 0) && (savefilefd <=0))
- {
- if ((my_strcmp((*a).msg,"agree") == 0) && (savefilefd == 0))
- {
- char savefilename[MAXLEN];
- my_strcpy((*a).addressee,filefromuser);
- printf("请输入你想保存的文件名:\n");
- do
- {
- setbuf(stdin,NULL);
- gets(savefilename);
- savefilefd = open(savefilename,O_RDWR|O_CREAT|O_EXCL,0777);
- if(savefilefd == -1)
- {
- printf("文件已存在,你重新输入:\n");
- }
- }while(savefilefd == -1);
- if(savefilefd < 0)
- {
- printf("接收文件失败!\n");
- savefilefd = -1;
- }
- else
- {
- my_strcpy((*a).msg,"agree");
- my_send(sockfd,a,sizeof(*a),0);
- printf("文件接收中……\n");
- }
- }
- else
- {
- memset(str,0,strlen(str));
- cutStr((*a).msg,(*a).addressee,20,str,MAXLEN,'$');
- if (str[0] != '\0' && (*a).addressee[0] != '\0')
- {
- char transfileallname[22];
- sprintf(transfileallname,"./%s",str);
- savefilefd = open(str,O_RDWR,0666);
- if(savefilefd < 0)
- {
- printf("打开文件失败!\n");
- savefilefd = -1;
- }
- else
- {
- memset((*a).msg,0,strlen((*a).msg));
- my_strcpy((*a).msg,str);
- my_send(sockfd,a,sizeof(*a),0);
- }
- }
- else
- {
- my_strcpy((*a).msg,"disagree");
- my_strcpy((*a).name,locname);
- my_strcpy((*a).addressee,filefromuser);
- my_send(sockfd,a,sizeof(*a),0);
- }
- }
- my_strcpy((*a).flag,buf);
- continue;
- }
- if (my_strcmp((*a).flag,"trans") == 0)
- {
- my_strcpy((*a).flag,buf);
- }
- else
- {
- my_strcpy(buf,(*a).flag);
- my_strcpy((*a).addressee,(*a).flag);
- my_strcpy((*a).flag,"personal");
- my_send(sockfd,a,sizeof(*a),0); //发送私信
- my_strcpy((*a).flag,buf);
- time (&timep);
- memset(str,0,strlen(str));
- sprintf(str,"%s你对 %s 说: %s\n",ctime(&timep),(*a).flag,(*a).msg);
- printf("%s",str);
- my_write(fd,str,strlen(str)); //写入聊天记录文件中
- }
- }
- }
- /***************************************************
- 函数名:admin_kick
- 功能:管理员替人操作
- 传入参数:int sockfd,struct message *a
- 返回值:成功返回1,否则返回0
- ***************************************************/
- int admin_kick(int sockfd,struct message *a)
- {
- char str[MAXLEN];
- do
- {
- printf("你想把谁踢出聊天室:\n");
- setbuf(stdin,NULL); //清空缓存
- gets(str);
- }while(my_strcmp(str,"admin") == 0);
- if(my_strcmp(str,"") == 0) //str为空
- {
- return FAULT;
- }
- else
- {
- my_strcpy((*a).flag,"admin_kick"); //管理员踢人标志
- my_strcpy((*a).msg,str);
- my_send(sockfd,a,sizeof(struct message),0); //客户端把要求传给服务器
- }
- return OK;
- }
- /***************************************************
- 函数名:admin_screen
- 功能:管理员禁言功能
- 传入参数:int sockfd,struct message *a
- 返回值:成功返回1,否则返回0
- ***************************************************/
- int admin_screen(int sockfd,struct message *a)
- {
- char str[MAXLEN];
- do
- {
- printf("你想禁言/解禁谁:\n");
- setbuf(stdin,NULL);
- gets(str);
- }while(my_strcmp(str,"admin") == 0);
- if(my_strcmp(str,"") == 0)
- {
- return FAULT;
- }
- else
- {
- my_strcpy((*a).flag,"admin_screen"); //禁言标志
- my_strcpy((*a).msg,str);
- my_send(sockfd,a,sizeof(struct message),0);
- }
- return OK;
- }
- /***************************************************
- 函数名:login_admin
- 功能:管理员登录
- 传入参数:struct message *a
- 返回值:成功返回1,否则返回0
- ***************************************************/
- int login_admin(struct message *a)
- {
- int do_number;
- pthread_t pid;
- memset((*a).msg,0,strlen((*a).msg)); //清空消息
- my_strcpy(chat_log,"admin"); //聊天记录名
- pthread_create(&pid,NULL,(void*)handlerecvmsg,(void *)&sockfd); //创建线程
- while(1)
- {
- usleep(500000);
- do
- {
- printf("1.踢人 2.禁言/解禁 3.查看在线用户 4.聊天 5.退出\n");
- printf("please input:\n");
- setbuf(stdin,NULL); //清空缓存
- scanf(" %d",&do_number);
- system("clear");
- setbuf(stdin,NULL); //清空缓存
- }while((do_number != 1) && (do_number != 2) && (do_number != 3) && (do_number != 4)&& (do_number != 5));
- switch(do_number)
- {
- case 1:
- {
- admin_kick(sockfd,a);
- break;
- }
- case 2:
- {
- admin_screen(sockfd,a);
- break;
- }
- case 3:
- {
- my_strcpy((*a).flag,"view");
- my_send(sockfd,a,sizeof(*a),0);
- break;
- }
- case 4:
- {
- admin_chat(sockfd,a);
- break;
- }
- case 5:
- {
- my_close(sockfd);
- return FAULT;
- }
- default:
- {
- break;
- }
- }
- }
- return OK;
- }
- #include "../../include/client_handle.h"
- /***************************************************
- 函数名:handlerecvfile
- 功能:文件接收
- 传入参数:struct message *msg
- 返回值:无
- ***************************************************/
- void handlerecvfile(struct message *msg)
- {
- int n;
- struct message recvmsg = *msg;
- if(my_strcmp(recvmsg.msg,"end$") == 0) //接收标志为end$
- {
- printf("文件传输结束!\n");
- my_close(savefilefd);
- savefilefd = -1;
- return ;
- }
- else
- {
- pthread_mutex_lock(&lock); //上锁
- n=my_write(savefilefd,recvmsg.msg,recvmsg.size); //写入文件,保存聊天记录
- pthread_mutex_unlock(&lock); //解琐
- if(n < recvmsg.size && n > 0)
- {
- printf("接收文件出错!\n");
- return ;
- }
- }
- return ;
- }
- /***************************************************
- 函数名:handlesendfile
- 功能:文件传输
- 传入参数:无
- 返回值:无
- ***************************************************/
- void handlesendfile()
- {
- struct message filedata;
- do
- {
- memset(filedata.msg,0,sizeof(filedata.msg)); //清空消息缓存
- filedata.size =read(savefilefd,filedata.msg,1000);
- my_strcpy(filedata.flag,"transf");
- my_strcpy(filedata.addressee,filefromname);
- if (filedata.size == 0)
- {
- printf("文件传输完毕!\n");
- my_strcpy(filedata.msg,"end$");
- my_send(sockfd,&filedata,sizeof(struct message),0); //向服务器发送结束标志
- }
- else if (filedata.size > 0)
- {
- my_send(sockfd,&filedata,sizeof(struct message),0); //发送文件数据
- usleep(100000);
- }
- else
- {
- printf("读取文件失败,文件传输中止\n");
- break;
- }
- }while(filedata.size > 0);
- my_close(savefilefd);
- savefilefd = -1 ;
- }
handlerecvmsg.c
- #include "../../include/client_handle.h"
- /***************************************************
- 函数名:handlerecvmsg
- 功能:消息接收
- 传入参数:int *sockfd
- 返回值:无
- ***************************************************/
- void handlerecvmsg(int *sockfd)
- {
- int connfd = *sockfd;
- int nread;
- char buf[1024];
- char str[1024];
- struct message recvmsg;
- time_t timep; //显示当前时间
- if((fd=my_open(chat_log,O_RDWR|O_CREAT|O_APPEND,0777)) < 0) //创建聊天记录文件
- {
- printf("打开聊天记录失败!");
- exit(1);
- }
- while(1)
- {
- nread = my_recv(connfd,&recvmsg,sizeof(struct message),0); //接受文件
- if(nread == 0)
- {
- printf("You have detached from the server!\n");
- my_close(fd);
- my_close(connfd);
- exit(0);
- }
- else if (my_strcmp(recvmsg.flag,"all") == 0) //接受群发信息
- {
- time (&timep);
- memset(str,0,strlen(str));
- sprintf(str,"%s%s 对大家说: %s\n",ctime(&timep),recvmsg.name,recvmsg.msg);
- printf("%s",str);
- my_write(fd,str,strlen(str)); //聊天信息写入文件
- }
- else if (my_strcmp(recvmsg.flag,"personal") == 0) //接受私信
- {
- time (&timep);
- memset(str,0,strlen(str));
- sprintf(str,"%s%s 对你说: %s\n",ctime(&timep),recvmsg.name,recvmsg.msg);
- printf("%s",str);
- my_write(fd,str,strlen(str)); //保存聊天记录
- }
- else if (my_strcmp(recvmsg.flag,"sermsg") == 0) //系统提示信息
- {
- time (&timep);
- memset(str,0,strlen(str));
- sprintf(str,"%s系统信息: %s\n",ctime(&timep),recvmsg.msg);
- printf("%s",str);
- my_write(fd,str,strlen(str));
- continue;
- }
- else if (my_strcmp(recvmsg.flag,"view") == 0) //收到查看在线用户标志
- {
- time (&timep);
- memset(str,0,strlen(str));
- sprintf(str,"%s在线用户:\n%s\n",ctime(&timep),recvmsg.msg);
- printf("%s",str);
- continue;
- }
- else if (my_strcmp(recvmsg.flag,"trans") == 0) //传输文件标志
- {
- pthread_t pid;
- if (my_strcmp(recvmsg.msg,"agree") == 0) //同意接受文件标志
- {
- my_strcpy(filefromname,recvmsg.name);
- printf("文件传送中……\n");
- //创建线程发送文件
- pthread_create(&pid,NULL,(void *)handlesendfile,NULL); //创建发送文件线程
- }
- else if(my_strcmp(recvmsg.msg,"disagree") == 0)
- {
- printf("对方拒绝接收文件\n");
- my_close(savefilefd);
- savefilefd = -1;
- }
- else if(my_strcmp(recvmsg.msg,"noexist") == 0)
- {
- printf("对不起,该客户端不存在\n");
- my_close(savefilefd);
- savefilefd = -1;
- }
- else
- {
- my_strcpy(filefromuser,recvmsg.name);
- my_strcpy(filefromname,recvmsg.msg);
- printf("%s向你传文件%s,是否同意接受?\n同意请输入:trans$agree\t不同意请输入:trans$disagree\n",recvmsg.name,recvmsg.msg);
- savefilefd = 0;
- }
- continue;
- }
- else if(my_strcmp(recvmsg.flag,"transf") == 0)
- {
- pthread_t pid_transf;
- pthread_create(&pid_transf,NULL,(void *)handlerecvfile,&recvmsg); //创建文件传输线程
- pthread_join(pid_transf,NULL);
- continue;
- }
- else
- {
- if(my_strcmp(recvmsg.flag,"") == 0)
- {
- continue;
- }
- }
- }
- }
handlestr.c
- #include "../../include/client_handle.h"
- /***************************************************
- 函数名:cutStr
- 功能:将字符串str在字符c处分割,前后两段
- 分别赋给left和right,left最大长度为n,str最大
- 长度为max
- 传入参数:char str[],char left[], int n, char right[],int max, char c
- 返回值:无
- ***************************************************/
- void cutStr(char str[],char left[], int n, char right[],int max, char c)
- {
- int i,k,j;
- for(i = 0 ; i < n ;i++)
- {
- if(str[i] == c) //c为str的分割符
- break;
- }
- if(i == n)
- {
- i = -1;
- }
- else
- {
- memset(left,0,strlen(left));
- for(k = 0 ; k < i ; k++)
- {
- left[k] = str[k]; //c左边的字符串赋给left[]
- }
- }
- for(j = i+1 ; j < max;j++)
- {
- if(str[j] == '\0')
- break;
- right[j-i-1] = str[j]; //c右边的字符串给right[]
- }
- left[i] = '\0';
- if(j < max)
- {
- right[j-i-1] = '\0';
- }
- else
- {
- right[max] = '\0';
- }
- }
- /***************************************************
- 函数名:common_use_words
- 功能:常用语替换
- 传入参数:char msg[]
- 返回值:无
- ***************************************************/
- void common_use_words(char msg[])
- {
- int i=0,j=0;
- char common[MAXLEN];
- char tmp[MAXLEN];
- if(msg[0] == '/')
- {
- my_strcpy(tmp,msg);
- memset(msg,0,strlen(msg));
- for(i=1;i<MAXLEN;i++)
- {
- if(tmp[i] != '/')
- {
- msg[i-1] = tmp[i];
- }
- else
- {
- break;
- }
- }
- msg[i-1] = ',';
- msg[i] = '\0';
- i++;
- for(j=0;i<MAXLEN;i++,j++)
- {
- if(tmp[i] != '\0')
- {
- common[j] = tmp[i];
- }
- else
- {
- break;
- }
- }
- common[j] = '\0';
- if(my_strcmp(common,"welcome") == 0)
- {
- strcat(msg,"欢迎来到我们的聊天室^_^"); //连接字符串
- return ;
- }
- strcat(msg,common);
- }
- }
- /***************************************************
- 函数名:expression
- 功能:常用表情替换
- 传入参数:char name[],char msg[],int m
- 返回值:无
- ***************************************************/
- void expression(char name[],char msg[])
- {
- if(my_strcmp(msg,":)") == 0)
- {
- sprintf(msg,"%s 做了个笑脸!",name);
- }
- if(my_strcmp(msg,":(") == 0)
- {
- sprintf(msg,"%s 表情很沮丧!",name);
- }
- if(my_strcmp(msg,"囧") == 0)
- {
- sprintf(msg,"%s 表情很囧!",name);
- }
- if(my_strcmp(msg,"哈哈") == 0)
- {
- sprintf(msg,"哈哈 ^_^");
- }
- if(my_strcmp(msg,"汗") == 0)
- {
- sprintf(msg,"~_~|||");
- }
- if(my_strcmp(msg,"晕") == 0)
- {
- sprintf(msg,"@_@");
- }
- }
- #include "../../include/client_handle.h"
- /***************************************************
- 函数名:Interface
- 功能:登录界面
- 传入参数:无
- 返回值:无
- ***************************************************/
- int Interface()
- {
- int do_number;
- do
- {
- system("clear");
- printf("----------------------------------\n");
- printf(" 欢迎进入聊天室 \n");
- printf(" 1.登录 \n");
- printf(" 2.注册 \n");
- printf(" 3.退出 \n");
- printf("----------------------------------\n");
- printf("请选择:\n");
- setbuf(stdin,NULL);
- scanf(" %d",&do_number);
- setbuf(stdin,NULL);
- }while((do_number != 1) && (do_number != 2) && (do_number != 3));
- return do_number;
- }
- /***************************************************
- 函数名:help
- 功能:帮助
- 传入参数:char str[]
- 返回值:成功返回1,否则返回0
- ***************************************************/
- int help(char str[])
- {
- if(my_strcmp(str,".help") == 0)
- {
- printf("尊敬的%s用户,你好:\n",locname);
- printf("all$hello!-------------对所有人说hello!\n");
- printf("bill$hello!------------对bill说hello!\n");
- printf("trans$bill$hello.txt---传文件hello.txt给bill\n");
- printf("trans$agree------------同意接收文件\n");
- printf("trans$disagree---------不同意接收文件\n");
- printf("view$------------------查看在线用户\n");
- printf("exit$------------------退出\n");
- return OK;
- }
- else
- {
- return FAULT;
- }
- }
log.c
- #include "../../include/client_handle.h"
- /***************************************************
- 函数名:log_user
- 功能:用户登录
- 传入参数:struct message *a
- 返回值:无
- ***************************************************/
- void log_user(struct message *a)
- {
- do
- {
- printf("请输入用户名(10字以内):\n");
- memset((*a).name,0,strlen((*a).name));
- scanf("%s",(*a).name);
- my_strcpy(locname,(*a).name);
- printf("请输入密码(20位以内):\n");
- memset((*a).msg,0,strlen((*a).msg));
- scanf("%s",(*a).msg);
- }while(strlen((*a).name)>20 || strlen((*a).msg)>20);
- my_strcpy((*a).flag,"login");
- my_send(sockfd,a,sizeof(*a),0); //向服务器发送登录信息
- printf("正在登录,请稍等……\n");
- my_recv(sockfd,a,sizeof(*a),0);
- printf("recv the message from server:%s\n",(*a).msg);
- }
- /***************************************************
- 函数名:login_success
- 功能:登录成功进入聊天模式
- 传入参数:struct message *a
- 返回值:退出返回0,否则返回1
- ***************************************************/
- int login_success(struct message *a)
- {
- char str[MAXLEN];
- char buf[MAXLEN];
- time_t timep;
- pthread_t pid;
- sprintf(chat_log,"./chat_log/%s.txt",(*a).name);
- if((fd=my_open(chat_log,O_RDWR|O_CREAT|O_APPEND,0777)) < 0)
- {
- printf("打开聊天记录失败!");
- exit(1);
- }
- pthread_create(&pid,NULL,(void*)handlerecvmsg,(void *)&sockfd); //创建接受消息线程
- setbuf(stdin,NULL);
- my_strcpy((*a).flag,"all");
- printf("尊敬的%s你好,如需帮助请输入:.help\n",locname);
- while(1)
- {
- memset((*a).msg,0,strlen((*a).msg));
- memset(str,0,strlen(str));
- usleep(100000);
- printf("TO %s:\n",(*a).flag);
- setbuf(stdin,NULL);
- gets(str);
- if(OK == help(str)) //提示信息
- {
- continue;
- }
- my_strcpy((*a).name,locname);
- my_strcpy(buf,(*a).flag);
- cutStr(str,(*a).flag,15,(*a).msg,MAXLEN,'$'); //调用字符切割函数
- expression((*a).name,(*a).msg); //表情替换函数
- common_use_words((*a).msg); //常用语使用函数
- if(my_strcmp((*a).flag,"exit") == 0)
- {
- return FAULT;
- }
- if(my_strcmp((*a).flag,"view") == 0)
- {
- my_send(sockfd,a,sizeof((*a)),0); //请求查看在线用户
- my_strcpy((*a).flag,buf);
- continue;
- }
- if(my_strcmp((*a).flag,"all") == 0)
- {
- my_send(sockfd,a,sizeof(*a),0);
- continue;
- }
- if ((my_strcmp((*a).flag,"trans") == 0) && (savefilefd <=0))
- {
- if ((my_strcmp((*a).msg,"agree") == 0) && (savefilefd == 0))
- {
- char savefilename[MAXLEN];
- my_strcpy((*a).addressee,filefromuser);
- printf("请输入你想保存的文件名:\n");
- do
- {
- setbuf(stdin,NULL);
- gets(savefilename);
- savefilefd = open(savefilename,O_RDWR|O_CREAT|O_EXCL,0777);
- if(savefilefd == -1)
- {
- printf("文件已存在,你重新输入:\n");
- }
- }while(savefilefd == -1);
- if(savefilefd < 0)
- {
- printf("接收文件失败!\n");
- savefilefd = -1;
- }
- else
- {
- my_strcpy((*a).msg,"agree");
- my_send(sockfd,a,sizeof(*a),0);
- printf("文件接收中……\n");
- }
- }
- else
- {
- memset(str,0,strlen(str));
- cutStr((*a).msg,(*a).addressee,20,str,MAXLEN,'$');
- if (str[0] != '\0' && (*a).addressee[0] != '\0')
- {
- char transfileallname[22];
- sprintf(transfileallname,"./%s",str);
- savefilefd = open(str,O_RDWR,0666);
- if(savefilefd < 0)
- {
- printf("打开文件失败!\n");
- savefilefd = -1;
- }
- else
- {
- memset((*a).msg,0,strlen((*a).msg));
- my_strcpy((*a).msg,str);
- my_send(sockfd,a,sizeof(*a),0);
- }
- }
- else
- {
- my_strcpy((*a).msg,"disagree");
- my_strcpy((*a).name,locname);
- my_strcpy((*a).addressee,filefromuser);
- my_send(sockfd,a,sizeof(*a),0);
- }
- }
- my_strcpy((*a).flag,buf);
- continue;
- }
- if (my_strcmp((*a).flag,"trans") == 0)
- {
- my_strcpy((*a).flag,buf);
- }
- else
- {
- my_strcpy(buf,(*a).flag);
- my_strcpy((*a).addressee,(*a).flag);
- my_strcpy((*a).flag,"personal");
- my_send(sockfd,a,sizeof(*a),0); //发送私信
- my_strcpy((*a).flag,buf);
- time (&timep);
- memset(str,0,strlen(str));
- sprintf(str,"%s你对 %s 说: %s\n",ctime(&timep),(*a).flag,(*a).msg);
- printf("%s",str);
- my_write(fd,str,strlen(str)); //写入聊天记录文件中
- }
- }
- return OK;
- }
- #include "../../include/client_handle.h"
- /***************************************************
- 函数名:Register
- 功能:注册
- 传入参数:struct message *a
- 返回值:返回0
- ***************************************************/
- int Register(struct message *a)
- {
- char password_t[MAXLEN];
- do
- {
- printf("请输入用户名(10字以内):\n");
- memset((*a).name,0,strlen((*a).name));
- setbuf(stdin,NULL);
- scanf("%s",(*a).name);
- }while(strlen((*a).name)>20);
- while(1)
- {
- printf("请输入密码(20位以内):\n");
- memset((*a).msg,0,strlen((*a).msg));
- setbuf(stdin,NULL);
- scanf("%s",(*a).msg);
- printf("请再次输入密码(20位以内):\n");
- memset(password_t,0,strlen(password_t));
- setbuf(stdin,NULL);
- scanf("%s",password_t);
- if(my_strcmp((*a).msg,password_t) != 0 || strlen((*a).msg)>20 || strlen(password_t)>20)
- {
- printf("密码出错!\n");
- }
- else
- {
- break;
- }
- }
- my_strcpy((*a).flag,"reg");
- my_send(sockfd,a,sizeof(*a),0);
- printf("正在注册,请稍等……\n");
- my_recv(sockfd,a,sizeof(*a),0);
- printf("recv the message from server:%s\n",(*a).msg);
- sleep(3);
- }
服务器:
check.h
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <string.h>
- #include <pthread.h>
- #include <string.h>
- #include <sqlite3.h>
- #define MAXLEN 1000
- #define REG_OK 1
- #define REG_FAULT 0
- #define LOG_USER 0
- #define LOG_ADMIN 1
- #define LOG_FAULT -1
- struct message /*消息结构体*/
- {
- char flag[15]; /*标志位*/
- char name[20]; /*用户名*/
- char msg[MAXLEN]; /*消息内容*/
- char addressee[20]; /*传输文件目的用户*/
- int size; /*传输内容字节数*/
- };
- int reg_check(struct message *recievemsg);
- int login_check(struct message *recievemsg);
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <errno.h>
- #include <netinet/in.h>
- #include <pthread.h>
- typedef struct _clientinf /*用户结构体*/
- {
- char name[20]; /*用户名*/
- struct sockaddr_in addr_in; /*地址*/
- int decr; /*socket文件描述符*/
- pthread_t pid; /*线程号*/
- int speak; /*禁言标志*/
- }clientinf;
- typedef clientinf datatype;
- typedef struct _LNode /*在线链表结构体*/
- {
- datatype data;
- struct _LNode * next;
- }LNode,*LinkList;
- extern LinkList CreateLinkList(void);
- extern void deletelist(LinkList L ,datatype e);
- extern void insertend(LinkList L,datatype e);
- extern void DisplayList(LinkList L);
server.h
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <string.h>
- #include <netdb.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <unistd.h>
- #include <arpa/inet.h>
- #include <ctype.h>
- #include "linklist.h"
- #include "check.h"
- #define MAXLEN 1000
- #define portnumber 6666 /* 宏定义端口号 */
- #define MAX_LINE 80
- LinkList clientlink;
- #include "../../include/check.h"
- /***************************************************
- 函数名:reg_check
- 功能:注册检查
- 传入参数:struct message *recievemsg
- 返回值:成功REG_OK,失败REG_FAULT
- ***************************************************/
- int reg_check(struct message *recievemsg)
- {
- int fd;
- int read_size,write_size;
- struct message cmpmsg;
- char *p_name;
- char *p_passwore;
- int rc,i,ncols;
- sqlite3 *db;
- sqlite3_stmt *stmt;
- char sql[128] ;
- const char *tail;
- if(strlen(recievemsg->name)>20 || strlen(recievemsg->msg)>20 )
- {
- return REG_FAULT;
- }
- if(my_strcmp(recievemsg->name,"admin")==0)
- {
- return REG_FAULT;
- }
- if(my_strcmp(recievemsg->name,"all")==0)
- {
- return REG_FAULT;
- }
- if(my_strcmp(recievemsg->name,"reg")==0)
- {
- return REG_FAULT;
- }
- if(my_strcmp(recievemsg->name,"login")==0)
- {
- return REG_FAULT;
- }
- if(my_strcmp(recievemsg->name,"trans")==0)
- {
- return REG_FAULT;
- }
- /*打开数据库*/
- rc = sqlite3_open("./src/db/chat.db",&db);
- if(rc)
- {
- fprintf(stderr,"can't open databse:%s",sqlite3_errmsg(db));
- sqlite3_close(db);
- return REG_FAULT;
- }
- /*检查重名退出*/
- memset(sql,0,sizeof(sql));
- sprintf(sql,"select * from member where name='%s';",(recievemsg->name));
- rc = sqlite3_prepare(db,sql,strlen(sql),&stmt,&tail);
- if(rc != SQLITE_OK)
- {
- fprintf(stderr,"SQLerror:%s",sqlite3_errmsg(db));
- }
- /*执行*/
- rc = sqlite3_step(stmt);
- ncols = sqlite3_column_count(stmt);
- while (rc == SQLITE_ROW)
- {
- rc = sqlite3_step(stmt);
- sqlite3_finalize(stmt);
- sqlite3_close(db);
- return REG_FAULT;
- }
- /*销毁stmt*/
- sqlite3_finalize(stmt);
- /*注册*/
- memset(sql,0,sizeof(sql));
- sprintf(sql,"insert into member (name,password) values(?,?);");
- rc = sqlite3_prepare(db,sql,strlen(sql),&stmt,&tail);
- if(rc != SQLITE_OK)
- {
- fprintf(stderr,"SQLerror:%s",sqlite3_errmsg(db));
- }
- p_name = recievemsg->name;
- sqlite3_bind_text(stmt,1,p_name,strlen(p_name),NULL);
- p_passwore = recievemsg->msg;
- sqlite3_bind_text(stmt,2,p_passwore,strlen(p_passwore),NULL);
- rc = sqlite3_step(stmt);
- sqlite3_finalize(stmt);
- /*关闭数据库*/
- sqlite3_close(db);
- return REG_OK;
- }
- /***************************************************
- 函数名:login_check
- 功能:注册检查
- 传入参数:struct message *recievemsg
- 返回值:管理员admin成功LOG_ADMIN,
- 普通用户成功LOG_USER,失败LOG_FAULT
- ***************************************************/
- int login_check(struct message *recievemsg)
- {
- int fd;
- int read_size,write_size;
- struct message cmpmsg;
- char *p_name;
- char *p_passwore;
- int rc,i,ncols;
- sqlite3 *db;
- sqlite3_stmt *stmt;
- char sql[128] ;
- const char *tail;
- /*打开数据库*/
- rc = sqlite3_open("./src/db/chat.db",&db);
- if(rc)
- {
- fprintf(stderr,"can't open databse:%s",sqlite3_errmsg(db));
- sqlite3_close(db);
- return LOG_FAULT;
- }
- /*检查用户名密码*/
- memset(sql,0,sizeof(sql));
- sprintf(sql,"select * from member where name='%s' and password='%s';",(recievemsg->name),(recievemsg->msg));
- rc = sqlite3_prepare(db,sql,strlen(sql),&stmt,&tail);
- if(rc != SQLITE_OK)
- {
- fprintf(stderr,"SQLerror:%s",sqlite3_errmsg(db));
- }
- /*执行*/
- rc = sqlite3_step(stmt);
- ncols = sqlite3_column_count(stmt);
- while (rc == SQLITE_ROW)
- {
- rc = sqlite3_step(stmt);
- sqlite3_finalize(stmt);
- sqlite3_close(db);
- if(strcmp(recievemsg->name,"admin") == 0)
- {
- return LOG_ADMIN;
- }
- else
- {
- return LOG_USER;
- }
- }
- /*销毁stmt*/
- sqlite3_finalize(stmt);
- /*关闭数据库*/
- sqlite3_close(db);
- return LOG_FAULT;
- }
server.c
- #include "../../include/server.h"
- /***************************************************
- 函数名:main
- 功能:聊天软件服务器
- 传入参数:void
- 返回值:int
- ***************************************************/
- int main(void)
- {
- int re;
- int fd;
- struct message a;
- datatype e;
- LinkList transfileNode;
- char buf[MAXLEN],str[MAXLEN];
- time_t timep;
- clientinf clientNode;
- clientNode.speak = 1;
- my_strcpy(clientNode.name,"***");
- clientlink=CreateLinkList();
- if((fd=my_open("./chat_log_server/chat_log_server.txt",O_RDWR|O_CREAT|O_APPEND,0777)) < 0)
- {
- printf("failure to open chat_log_server!");
- exit(1);
- }
- int lfd;
- int cfd;
- int sfd;
- int rdy;
- struct sockaddr_in sin;
- struct sockaddr_in cin;
- int client[FD_SETSIZE]; /* 客户端连接的套接字描述符数组 */
- int maxi;
- int maxfd; /* 最大连接数 */
- fd_set rset;
- fd_set allset;
- socklen_t addr_len; /* 地址结构长度 */
- char buffer[MAX_LINE];
- int i;
- int n;
- int len;
- int opt = 1; /* 套接字选项 */
- char addr_p[20];
- /* 对server_addr_in 结构进行赋值 */
- bzero(&sin,sizeof(struct sockaddr_in)); /* 先清零 */
- sin.sin_family=AF_INET;
- sin.sin_addr.s_addr=htonl(INADDR_ANY); //表示接受任何ip地址 将ip地址转换成网络字节序
- sin.sin_port=htons(portnumber); //将端口号转换成网络字节序
- /* 调用socket函数创建一个TCP协议套接口 */
- if((lfd=my_socket(AF_INET,SOCK_STREAM,0))==-1) // AF_INET:IPV4;SOCK_STREAM:TCP
- {
- fprintf(stderr,"Socket error:%s\n\a",strerror(errno));
- exit(1);
- }
- /*设置套接字选项 使用默认选项*/
- my_setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
- /* 调用bind函数 将serer_addr结构绑定到sockfd上 */
- if(my_bind(lfd,(struct sockaddr *)(&sin),sizeof(struct sockaddr))==-1)
- {
- fprintf(stderr,"Bind error:%s\n\a",strerror(errno));
- exit(1);
- }
- /* 开始监听端口 等待客户的请求 */
- if(my_listen(lfd,20)==-1)
- {
- fprintf(stderr,"Listen error:%s\n\a",strerror(errno));
- exit(1);
- }
- printf("正在连接.......\n");
- maxfd = lfd; /*对最大文件描述符进行初始化*/
- maxi = -1;
- /*初始化客户端连接描述符集合*/
- for(i = 0;i < FD_SETSIZE;i++)
- {
- client[i] = -1;
- }
- FD_ZERO(&allset); /* 清空文件描述符集合 */
- FD_SET(lfd,&allset); /* 将监听字设置在集合内 */
- /* 开始服务程序的死循环 */
- while(1)
- {
- rset = allset;
- /*得到当前可以读的文件描述符数*/
- rdy = select(maxfd + 1, &rset, NULL, NULL, NULL);
- if(FD_ISSET(lfd, &rset))
- {
- addr_len = sizeof(sin);
- /* 接受客户端的请求 */
- if((cfd=my_accept(lfd,(struct sockaddr *)(&cin),&addr_len))==-1)
- {
- fprintf(stderr,"Accept error:%s\n\a",strerror(errno));
- exit(1);
- }
- /*查找一个空闲位置*/
- for(i = 0; i<FD_SETSIZE; i++)
- {
- if(client[i] <= 0)
- {
- client[i] = cfd; /* 将处理该客户端的连接套接字设置到该位置 */
- break;
- }
- }
- /* 太多的客户端连接 服务器拒绝俄请求 跳出循环 */
- if(i == FD_SETSIZE)
- {
- printf("too many clients");
- exit(1);
- }
- FD_SET(cfd, &allset); /* 设置连接集合 */
- if(cfd > maxfd) /* 新的连接描述符 */
- {
- maxfd = cfd;
- }
- if(i > maxi)
- {
- maxi = i;
- }
- if(--rdy <= 0) /* 减少一个连接描述符 */
- {
- continue;
- }
- }
- /* 对每一个连接描述符做处理 */
- for(i = 0;i< FD_SETSIZE;i++)
- {
- if((sfd = client[i]) < 0)
- {
- continue;
- }
- if(FD_ISSET(sfd, &rset))
- {
- /*如果没有可以读的套接字 退出循环*/
- if(--rdy < 0)
- {
- break;
- }
- re = my_recv(sfd,&a,sizeof(a)+1,0);
- clientNode.decr = sfd;
- my_strcpy(clientNode.name,a.name);
- if(re == 0) /*客户端断开连接*/
- {
- server_exit(&a, &clientNode) ;
- fflush(stdout); /* 刷新 输出终端 */
- my_close(sfd);
- FD_CLR(sfd, &allset); /*清空连接描述符数组*/
- client[i] = -1;
- }
- else
- {
- if(my_strcmp(a.flag,"login") == 0) /*客户端请求登录*/
- {
- if(overlap(a) == 0) /*若该用户名不在线*/
- {
- server_login(&a,&clientNode); /*处理登录请求*/
- }
- else /*若该用户名已在线*/
- {
- strcpy(a.msg,"overlap");
- my_send(clientNode.decr,&a,sizeof(struct message),0);/*返回重名提示*/
- }
- continue;
- }
- else if(my_strcmp(a.flag,"reg") == 0) /*客户端请求注册*/
- {
- server_reg(&a,&clientNode); /*处理注册请求*/
- continue;
- }
- else if (my_strcmp(a.flag,"all") == 0) /*客户端请求广播*/
- {
- if(server_all(&a,&clientNode) == 1) /*处理广播请求*/
- {
- memset(str,0,strlen(str));
- time (&timep);
- sprintf(str,"%s%s TO %s: %s\n",ctime(&timep),a.name,a.flag,a.msg);
- printf("%s",str);
- my_write(fd,str,strlen(str)); /*将广播写入聊天记录*/
- }
- continue;
- }
- else if(my_strcmp(a.flag,"personal") == 0) /*客户端请求私聊*/
- {
- if(server_personal(&a,&clientNode) == 1) /*处理私聊请求*/
- {
- memset(str,0,strlen(str));
- time (&timep);
- sprintf(str,"%s%s TO %s: %s\n",ctime(&timep),a.name,a.addressee,a.msg);
- printf("%s",str);
- my_write(fd,str,strlen(str)); /*将私聊写入聊天记录*/
- }
- }
- else if(my_strcmp(a.flag,"view") == 0) /*客户端请求查看在线用户*/
- {
- server_view(&a,&clientNode); /*处理查看在线用户请求*/
- continue;
- }
- else if(my_strcmp(a.flag,"admin_kick") == 0) /*管理员替人请求*/
- {
- int closefd;
- closefd = server_admin_kick(&a,&clientNode); /*处理管理员替人请求*/
- FD_CLR(closefd, &allset); /*清空连接描述符数组*/
- int j;
- for(j = 0;j< FD_SETSIZE;j++)
- {
- if(closefd == client[j])
- {
- client[j]=-1;
- break;
- }
- }
- continue;
- }
- else if(my_strcmp(a.flag,"admin_screen") == 0)/*管理员禁言请求*/
- {
- server_admin_screen(&a,&clientNode);/*处理管理员禁言请求*/
- continue;
- }
- else if(my_strcmp(a.flag,"trans") == 0) /*客户端文件传输请求*/
- {
- server_trans(&a,&clientNode); /*处理客户端文件传输请求*/
- continue;
- }
- else if(my_strcmp(a.flag,"transf") == 0) /*客户端文件数据传输请求*/
- {
- server_transf(&a); /*传送文件*/
- continue;
- }
- }
- }
- }
- }
- close(lfd);
- return 0;
- }
server_admin.c
- #include "../../include/server_handle.h"
- /***************************************************
- 函数名:server_admin_kick
- 功能:处理管理员踢人功能
- 传入参数:struct message *a, clientinf *clientNode
- 返回值:成功返回踢出客户端的fd,否则返回0
- ***************************************************/
- int server_admin_kick(struct message *a, clientinf *clientNode)
- {
- int closefd;
- datatype e;
- my_strcpy(e.name,(*a).msg);
- LinkList L;
- L = (LinkList)findlist(clientlink,e);
- if(L == NULL)
- {
- my_strcpy((*a).flag,"sermsg");
- sprintf((*a).msg,"该用户不在线\n");
- my_send((*clientNode).decr,a,sizeof(struct message),0);
- return 0;
- }
- else
- {
- closefd=L->data.decr;
- my_close(closefd);
- deletelist(clientlink,e);
- L = clientlink;
- L = L->next;
- my_strcpy((*a).flag,"sermsg");
- sprintf((*a).msg,"%s 被管理员踢出了聊天室!",(*a).msg);
- while(L != NULL)
- {
- my_send(L->data.decr,a,sizeof(struct message),0);
- L = L->next;
- }
- }
- return closefd;
- }
- /***************************************************
- 函数名:server_admin_screen
- 功能:处理管理员禁言功能
- 传入参数:struct message *a, clientinf *clientNode
- 返回值:成功返回1,否则返回0
- ***************************************************/
- int server_admin_screen(struct message *a, clientinf *clientNode)
- {
- datatype e;
- my_strcpy(e.name,(*a).msg);
- LinkList L;
- L = (LinkList)findlist(clientlink,e);
- if(L == NULL)
- {
- my_strcpy((*a).flag,"sermsg");
- sprintf((*a).msg,"该用户不在线\n");
- my_send((*clientNode).decr,a,sizeof(struct message),0);
- return 0;
- }
- else
- {
- L->data.speak = (L->data.speak+1)%2;
- my_strcpy((*a).flag,"sermsg");
- if(L->data.speak == 0)
- {
- sprintf((*a).msg,"%s 被管理员禁言了!",(*a).msg);
- }
- else
- {
- sprintf((*a).msg,"%s 被管理员解禁!",(*a).msg);
- }
- L = clientlink;
- L = L->next;
- while(L != NULL)
- {
- my_send(L->data.decr,a,sizeof(struct message),0);
- L = L->next;
- }
- }
- return 1;
- }
server_chat.c
- #include "../../include/server_handle.h"
- /***************************************************
- 函数名:server_all
- 功能:处理客户端群发消息
- 传入参数:struct message *a, clientinf *clientNode
- 返回值:禁言返回0,否则返回1
- ***************************************************/
- int server_all(struct message *a, clientinf *clientNode)
- {
- datatype e;
- my_strcpy(e.name,(*a).name);
- LinkList L;
- L = (LinkList)findlist(clientlink,e);
- if(L != NULL)
- {
- if(L->data.speak == 0)
- {
- my_strcpy((*a).flag,"sermsg");
- sprintf((*a).msg,"对不起,你已经被管理员禁言了!");
- my_send(L->data.decr,a,sizeof(struct message),0);
- return 0;
- }
- }
- if (my_strcmp((*a).msg,"") != 0)
- {
- L = clientlink;
- L = L->next;
- my_strcpy((*a).name,(*clientNode).name);
- while(L != NULL)
- {
- my_send(L->data.decr,a,sizeof(struct message),0);
- L = L->next;
- }
- }
- return 1;
- }
- /***************************************************
- 函数名:server_personal
- 功能:处理客户端私聊
- 传入参数:struct message *a, clientinf *clientNode
- 返回值:成功返回1,否则返回0
- ***************************************************/
- int server_personal(struct message *a, clientinf *clientNode)
- {
- datatype e;
- my_strcpy(e.name,(*a).name);
- LinkList L;
- L = (LinkList)findlist(clientlink,e);
- if(L != NULL)
- {
- if(L->data.speak == 0)
- {
- my_strcpy((*a).flag,"sermsg");
- sprintf((*a).msg,"对不起,你已经被管理员禁言了!");
- my_send(L->data.decr,a,sizeof(struct message),0);
- return 0;
- }
- }
- L = clientlink;
- L=L->next;
- my_strcpy(e.name,(*a).addressee);
- L = (LinkList)findlist(clientlink,e);
- if(L == NULL)
- {
- my_strcpy((*a).flag,"sermsg");
- sprintf((*a).msg,"该用户不在线\n");
- my_send((*clientNode).decr,a,sizeof(struct message),0);
- return 0;
- }
- else
- {
- if (my_strcmp((*a).msg,"") != 0)
- {
- my_send(L->data.decr,a,sizeof(struct message),0);
- }
- }
- return 1;
- }
server_login_exit.c
- #include "../../include/server_handle.h"
- /***************************************************
- 函数名:overlap
- 功能:重名用户检查
- 传入参数:struct message a
- 返回值:重名返回1,否则返回0
- ***************************************************/
- int overlap(struct message a)
- {
- LinkList L;
- L = clientlink->next;
- while(L != NULL)
- {
- if(my_strcmp(L->data.name,a.name) == 0)
- {
- return 1;
- }
- else
- {
- L = L->next;
- }
- }
- return 0;
- }
- /***************************************************
- 函数名:server_login
- 功能:处理客户端登录
- 传入参数:struct message *a, clientinf *clientNode
- 返回值:无
- ***************************************************/
- int server_login(struct message *a, clientinf *clientNode)
- {
- int i;
- char buf[MAXLEN];
- i = login_check(a);
- if(i == 1)
- {
- printf("管理员admin登录成功!\n");
- my_strcpy((*a).msg,"hello,admin!");
- my_strcpy((*clientNode).name,(*a).name);
- insertend(clientlink,*clientNode);
- my_send((*clientNode).decr,a,sizeof(struct message),0);
- }
- else
- {
- if(i == 0)
- {
- printf("%s 登录成功!\n",(*a).name);
- memset((*a).msg,0,strlen((*a).msg));
- my_strcpy((*a).msg,"login,success!");
- my_strcpy((*clientNode).name,(*a).name);
- insertend(clientlink,*clientNode);
- my_send((*clientNode).decr,a,sizeof(struct message),0);
- LinkList L;
- L = clientlink;
- L=L->next;
- my_strcpy((*a).flag,"sermsg");
- sprintf((*a).msg,"欢迎 %s 进入聊天室!",(*a).name);
- while(L != NULL)
- {
- my_send(L->data.decr,a,sizeof(struct message),0);
- L = L->next;
- }
- }
- else
- {
- printf("%s 登录失败!\n",(*a).name);
- my_strcpy((*a).msg,"login,failure!");
- my_send((*clientNode).decr,a,sizeof(struct message),0);
- }
- }
- }
- /***************************************************
- 函数名:server_exit
- 功能:处理客户端与服务器断开连接
- 传入参数:struct message *a, clientinf *clientNode
- 返回值:无
- ***************************************************/
- int server_exit(struct message *a, clientinf *clientNode)
- {
- LinkList L;
- L = clientlink->next;
- while(L != NULL)
- {
- if(L->data.decr == (*clientNode).decr)
- {
- my_strcpy((*clientNode).name,L->data.name);
- break;
- }
- else
- {
- L = L->next;
- }
- }
- my_strcpy((*a).flag,"sermsg");
- printf("%s 离开聊天室\n",(*clientNode).name);
- deletelist(clientlink ,(*clientNode));
- L = clientlink;
- L=L->next;
- sprintf((*a).msg,"%s 离开聊天室",(*clientNode).name);
- while(L != NULL)
- {
- my_send(L->data.decr,a,sizeof(struct message),0);
- L = L->next;
- }
- }
server_reg.c
- #include "../../include/server_handle.h"
- /***************************************************
- 函数名:server_reg
- 功能:客户端注册处理
- 传入参数:struct message *a, clientinf *clientNode
- 返回值:无
- ***************************************************/
- int server_reg(struct message *a, clientinf *clientNode)
- {
- int i;
- char buf[MAXLEN];
- i = reg_check(a);
- if(i == 1)
- {
- printf("%s 注册成功!\n",(*a).name);
- my_strcpy((*a).msg,"register,success!");
- my_strcpy((*clientNode).name,(*a).name);
- my_send((*clientNode).decr,a,sizeof(struct message),0);
- }
- else
- {
- printf("%s 登录失败!\n",(*a).name);
- my_strcpy((*a).msg,"register,failure!");
- my_send((*clientNode).decr,a,sizeof(struct message),0);
- }
- }
server_trans.c
- #include "../../include/server_handle.h"
- /***************************************************
- 函数名:server_trans
- 功能:处理传输文件请求
- 传入参数:struct message *a,clientinf *clientNode
- 返回值:无
- ***************************************************/
- void server_trans(struct message *a,clientinf *clientNode)
- {
- LinkList L;
- L = clientlink;
- L=L->next;
- while(L != NULL)
- {
- if (my_strcmp(L->data.name,(*a).addressee)== 0)
- {
- break;
- }
- L = L->next;
- }
- if(L == NULL)
- {
- my_strcpy((*a).msg,"noexist");
- my_send((*clientNode).decr,a,sizeof(struct message),0);
- return ;
- }
- L = clientlink;
- L=L->next;
- while(L != NULL)
- {
- if (my_strcmp(L->data.name,(*a).name)== 0)
- {
- break;
- }
- L = L->next;
- }
- if(L == NULL)
- {
- my_strcpy((*a).msg,"noexist");
- my_send((*clientNode).decr,a,sizeof(struct message),0);
- }
- else
- {
- L = clientlink->next;
- while(L != NULL)
- {
- if(my_strcmp(L->data.name,(*a).addressee) == 0)
- {
- break;
- }
- else
- {
- L = L->next;
- }
- }
- my_send(L->data.decr,a,sizeof(struct message),0);
- }
- }
- /***************************************************
- 函数名:server_transf
- 功能:传输文件数据
- 传入参数:struct message *a
- 返回值:无
- ***************************************************/
- void server_transf(struct message *a)
- {
- LinkList L;
- L = clientlink->next;
- while(L != NULL)
- {
- if(my_strcmp(L->data.name,(*a).addressee) == 0)
- {
- break;
- }
- else
- {
- L = L->next;
- }
- }
- my_send(L->data.decr,a,sizeof(struct message),0);
- }
server_view.c
- #include "../../include/server_handle.h"
- /***************************************************
- 函数名:server_view
- 功能:处理客户端查看当前在线用户
- 传入参数:struct message *a, clientinf *clientNode
- 返回值:无
- ***************************************************/
- int server_view(struct message *a, clientinf *clientNode)
- {
- char str[MAXLEN],buf[MAXLEN];
- LinkList L;
- int i = 1;
- L = clientlink;
- L=L->next;
- memset(buf,0,strlen(buf));
- while(L != NULL)
- {
- memset(str,0,strlen(str));
- if(L->data.speak==1)
- {
- sprintf(str,"%d. %s (在线)\n",i,L->data.name);
- my_strcat(buf,str);
- }
- else
- {
- sprintf(str,"%d. %s (禁言)\n",i,L->data.name);
- my_strcat(buf,str);
- }
- L = L->next;
- i++;
- }
- my_strcpy((*a).name,(*clientNode).name);
- my_strcpy((*a).msg,buf);
- my_send((*clientNode).decr,a,sizeof(struct message),0);
- }