赞
踩
在Linux环境下,利用Socket通信实现网络聊天程序,主要包括以下功能:
(1)系统各菜单功能界面、聊天界面的显示
(2)用户的注册、登录(手机号注册,合格性检测,重复性检测),注册后创建用户文件夹
(3)可支持好友管理(好友列表在线显示、增删查,网络传输文件),账户管理(修改信息,权限变更(创新可调用MD5库文件)
(3)聊天方式分群聊和私聊两种方式,群聊可管理员设置禁言,代码实现禁言单用户,全员禁言代码类同(创新可加入自然语言检测,实现敏感词监督)
(4)保存聊天记录,代码实现保存私聊记录,群聊记录保存类同
(5)实现客户端之间网络传输文件
服务器每接上一个客户端,启动一个线程;
客户端创建收发线程与服务器交互。
Server.c
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <pthread.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <string.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <ctype.h>
- #include <memory.h>
- #include <netinet/ip.h>
- #include <netinet/tcp.h>
- #include <time.h>
- #include <malloc.h>
- #include <sys/stat.h>
- #include <termios.h>
-
- #define NUM 1024
- #define SIZE sizeof(cliMesg) //结构体cliMesg的大小
- typedef long long ll;
-
-
- //账户类
- typedef struct client_message
- {
- char id[20]; //每个账号唯一id, 手机号
- char passwd[20]; //账号密码
- char name[50]; //账号昵称
- char hy[100][20]; //好友列表,最大100个
- int hys; //好友数量
- int online; //0不在线, 1在线
- int fd; //存放客户端成功连接后accept产生的新的套接字, 不在线为-5
- int chatroom; //存放是否打开了双人聊天室,打开为1 , 没打开为0
- int admin; //管理员权限 -1禁言 - 踢出不能再进
- //bMesg status; //禁言
- long ed_time;
- struct client_message *next; //下一条链表的首地址
-
- }cliMesg;
-
- //信息类
- typedef struct friend_message
- {
- char rid[20]; //收信息的人
- char sid[20]; //发信息的人
- int type; //信息类型 , 好友请求1 , 私聊信息 2 , 好友请求回复信息3 , 文件传输4 , 文件回复5
- char mesg[1024]; //信息
- char fname[1024]; //文件名
- struct friend_message * next;//下一条信息的首地址
- }friMesg;
-
- cliMesg *head=NULL;
- friMesg *head1=NULL;
- int count =0; //账号数量
- int urev_count=0; //未发送的信息
-
- //创建账号信息的头指针
- cliMesg *create_count()
- {
- cliMesg *p1;
- p1=(cliMesg *)malloc(SIZE);
- if(p1==NULL)
- {
- printf("create error\n");
- return NULL;
- }
- p1->next=NULL;
-
- //记录账户
- FILE *fp;
- fp=fopen("counterMsg","a+"); //打开文件
- if(fp==NULL)
- {
- printf("open error\n");
- return NULL;
- }
-
- //文件为空
- if(fgetc(fp)==EOF)
- {
- fclose(fp);
- return p1;
- }
-
- //文件有内容
- rewind(fp); //文件指针重返文件头
-
- //获取账号数量
- int counter_num;
- fread(&counter_num,sizeof(int),1,fp);
- printf("counter_num=%d\n",counter_num);
- count=counter_num;
-
- //建立好友链表
- cliMesg t;
- cliMesg *tmp,*p;
- int i;
- for(i=0;i<counter_num;i++)
- {
- fread(&t,sizeof(cliMesg),1,fp);
- p=p1;
- while(p->next)
- {
- p=p->next;
- }
- tmp=(cliMesg *)malloc(sizeof(cliMesg));
- tmp->next=NULL;
- strcpy(tmp->id,t.id);
- strcpy(tmp->name,t.name);
- strcpy(tmp->passwd,t.passwd);
- tmp->admin=t.admin;
- tmp->hys=t.hys;
- tmp->ed_time=t.ed_time;
- //有好友将数据存入好友链表
- int j;
- for(j=0;j<tmp->hys;j++)
- {
- strcpy(tmp->hy[j],t.hy[j]);
- }
-
- tmp->fd= -5; //初始未登录
- tmp->chatroom=0; //初始未私聊
- tmp->online=0; //初始未在线
- //tmp->admin=0; //初始为普通用户
- p->next=tmp;
-
- }
-
- fclose(fp);
- return p1;
-
- }
-
- //创建未查看信息的头指针
- friMesg *create_buffmsg()
- {
- friMesg *x;
- x=(friMesg *)malloc(sizeof(friMesg));
- if(x==NULL)
- {
- printf("create error\n");
- return NULL;
- }
- x->next=NULL;
-
- FILE *fp;
- fp=fopen("buffMsg","a+");
- if(fp==NULL)
- {
- printf("open error\n");
- return NULL;
- }
-
- //如果为空文件关闭文件直接返回头指针
- if(fgetc(fp)==EOF)
- {
- fclose(fp);
- return x;
- }
-
- rewind(fp);
-
- int n;
- fread(&n,sizeof(int),1,fp);
- printf("urev_num=%d\n",n);
- urev_count=n;
-
- friMesg t;
- friMesg *p,*p1;
- //创建未查看信息链表
- int i;
- for(i=0;i<n;i++)
- {
- fread(&t,sizeof(friMesg),1,fp);
- p1=x;
- while(p1->next)
- {
- p1=p1->next;
- }
- p=(friMesg *)malloc(sizeof(friMesg));
- p->next=NULL;
- strcpy(p->rid,t.rid);
- strcpy(p->sid,t.sid);
- p->type=t.type;
- strcpy(p->mesg,t.mesg);
- p1->next=p;
- }
- fclose(fp);
- return x;
- }
-
- //获取系统时间
- char **get_time()
- {
- char **str=(char **)malloc(NUM*sizeof(char *));
- time_t t;
- struct tm * lt;
- time (&t);//获取Unix时间戳。
- lt = localtime (&t);//转为时间结构。
- sprintf ( str,"%04d/%02d/%02d %02d:%02d:%02d\n",lt->tm_year+1900, lt->tm_mon, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec);//输出结果
- return str;
- }
-
- //保存账户信息
- void saveclient()
- {
- FILE *fp;
- fp=fopen("counterMsg","w"); //打开文件
- if(fp==NULL)
- {
- printf("open error\n");
- return;
- }
- printf("账户个数=%d",count);
- fwrite(&count,sizeof(int),1,fp); //先保存账号个数
-
- cliMesg* p;
- p=head;
- if(p->next==NULL) //如果账号列表为空 , 关闭文件并退出函数
- {
- fclose(fp);
- return ;
- }
-
- p=p->next;
- //按结构体大小保存账号信息
- while(p)
- {
- fwrite(p,sizeof(cliMesg),1,fp);
- p=p->next;
- }
- printf("账号信息保存成功\n");
-
- fclose(fp);
-
- }
-
- //保存未查看的消息
- void savefile()
- {
- FILE *fp;
- fp=fopen("buffMsg","w");
- if(fp==NULL)
- {
- printf("open error\n");
- return;
- }
- printf("未查看信息个数=%d\n",urev_count);
- fwrite(&urev_count,sizeof(int),1,fp);
-
- friMesg *p;
- p=head1;
- if(p->next==NULL)
- {
- fclose(fp);
- return;
- }
-
- p=p->next;
- while(p)
- {
- fwrite(p,sizeof(cliMesg),1,fp);
- p=p->next;
- }
- printf("信息保存成功");
- fclose(fp);
-
- }
-
- //服务器上当前客户端id.txt保存聊天记录
- void savefile2(char str[1024],char id[20])
- {
- FILE *fp;
- char ch[1024];
- sprintf(ch,"./%s/%s.txt",id,id);
- fp=fopen(ch,"a+");
- if(fp==NULL) //打开错误关闭程序
- return ;
- memset(ch,0,1024);
- strcat(str,"\n"); //txt文档每行句末尾加特殊换行符
- strcpy(ch,str);
- fwrite(ch,strlen(ch),1,fp);
- printf("聊天记录保存成功\n");
- fclose(fp);
- }
-
- //帐号合格性检查
- int isnum1(char s[20])
- {
- int i=0;
- while(s[i])
- {
- if(!isdigit(s[i]))
- {
- return 0;
- }
- i++;
- }
- if(i<11)
- {
- return 0;
- }
- return 1;
- }
-
- //用户注册
- void add(int fd)
- {
- cliMesg *p1,*p,*p2;
-
- int leap=0; //标识符,账号是否能正确注册
- p=(cliMesg *)malloc(SIZE);
- if(p==NULL)
- return;
- char str[256];
- char str1[256];
- memset(str,0,sizeof(str));
- memset(str1,0,sizeof(str1));
- strcpy(str,"请输入您要注册的手机号");
- send(fd,str,strlen(str),0);
- memset(str,0,sizeof(str));
- recv(fd,str,sizeof(str),0);
- strcpy(str1,str);
- if(!isnum1(str)) //判断是否纯数字账号
- {
- memset(str,0,sizeof(str));
- strcpy(str,"请输入正确的手机号\n");
- send(fd,str,strlen(str),0);
- return;
- }
- p1=head;
- //判断注册账户是否存在
- while(p1->next)
- {
- if(strcmp(p1->next->id,str)==0)
- {
- leap=1;
- break;
- }
- p1=p1->next;
- }
- if(leap==1)
- {
- memset(str,0,sizeof(str));
- strcpy(str,"账号重复\n");
- send(fd,str,strlen(str),0);
- return;
- }
- //正常注册
- strcpy(p->id,str1);
- memset(str,0,sizeof(str));
- strcpy(str,"请输入密码");
- send(fd,str,strlen(str),0);
-
- memset(str,0,sizeof(str));
- recv(fd,str,sizeof(str),0);
- strcpy(p->passwd,str);
-
- memset(str,0,sizeof(str));
- strcpy(str,"请输入昵称");
- send(fd,str,strlen(str),0);
-
- memset(str,0,sizeof(str));
- recv(fd,str,sizeof(str),0);
- strcpy(p->name,str);
- p1=head;
- while(p1->next)
- {
- p1=p1->next;
- }
- p1->next=p;
- p->hys=0;
- p->online=0;
- p->fd=-5;
- p->next=NULL;
- memset(str,0,sizeof(str));
- strcpy(str,"注册成功,您可以登录了\n");
- send(fd,str,strlen(str),0);
- count++; //全局变量账号数量+1
- //保存账户信息
- saveclient();
- memset(str,0,sizeof(str));
- sprintf(str,"mkdir ./%s",p->id);
- system(str);
-
- }
-
- //账户匹配检查
- int check_iscount(char id[20])
- {
- cliMesg *p;
- if(head->next==NULL)
- {
- return 0;
- }
- p=head->next;
- while(p)
- {
- if(strcmp(id,p->id)==0)
- {
- return 1;
- }
- p=p->next;
- }
- return 0;
- }
-
- //密码匹配检查
- int check_countpasswd(char id[20],char passwd[20])
- {
- cliMesg *p;
- if(head->next==NULL)
- {
- return 0;
- }
- p=head->next;
-
- while(p)
- {
-
- if(strcmp(id,p->id)==0 && strcmp(passwd,p->passwd)==0)
- {
- return 1;
- }
- p=p->next;
- }
- return 0;
- }
-
- //判断是否在线
- int countOnline(char id[20])
- {
- cliMesg *p;
- p=head;
- while(p)
- {
- if((strcmp(p->id,id)==0) && p->online==1)
- {
- return 1;
- }
- p=p->next;
- }
- return 0;
- }
-
- //好友列表
- void list_friends(int fd,char id[20])
- {
- char sendbuf[1024]={0};
- cliMesg *p,*p1;
- int cnt=0;
- p=head;
- p=p->next;
- while(p)
- {
- if(strcmp(p->id,id)==0)
- {
- break;
- }
- p=p->next;
- }
- int num=p->hys;
- if(num==0)
- {
- memset(sendbuf,0,sizeof(sendbuf));
- strcpy(sendbuf,"好友列表为空");
- send(fd,sendbuf,strlen(sendbuf),0);
- return;
- }
- memset(sendbuf,0,sizeof(sendbuf));
- strcpy(sendbuf,"***************好友列表***************");
- send(fd,sendbuf,strlen(sendbuf),0);
- int i;
- for(i=0;i<num;i++)
- {
- p1=head->next;
- char str[20]={0};
- while(p1)
- {
- if(strcmp(p1->id,p->hy[i])==0)
- {
- strcpy(str,p1->name);
- break;
- }
- p1=p1->next;
- }
- memset(sendbuf,0,sizeof(sendbuf));
- if(p1->online==1)
- cnt++;
- sprintf(sendbuf,"%d 好友账号[%s],昵称[%s],[%d]\n",i+1,p->hy[i],str,p1->online);
- send(fd,sendbuf,strlen(sendbuf),0);
- }
- memset(sendbuf,0,sizeof(sendbuf));
- sprintf(sendbuf,"在线好友个数=%d\n",cnt);
- send(fd,sendbuf,strlen(sendbuf),0);
- memset(sendbuf,0,sizeof(sendbuf));
- strcpy(sendbuf,"**************************************");
- send(fd,sendbuf,strlen(sendbuf),0);
-
- }
-
- //查找已加好友
- void find_friends(int fd,char id[20])
- {
- cliMesg *p,*p1;
- p=head;
- char sendbuf[1024]={0};
- char recvbuf[1024]={0};
- char find_id[1024]={0};
-
- strcpy(sendbuf,"请输入您要查找的手机号");
- send(fd,sendbuf,strlen(sendbuf),0);
- recv(fd,find_id,sizeof(find_id),0);
- //查找手机号是否存在
- if(check_iscount(find_id)==0)
- {
- memset(sendbuf,0,sizeof(sendbuf));
- strcpy(sendbuf,"此号码不存在");
- send(fd,sendbuf,strlen(sendbuf),0);
- return;
- }
- //查找自己是否有该好友
- p=p->next;
- while(p)
- {
- if(strcmp(p->id,id)==0)
- {
- break;
- }
- p=p->next;
- }
- if(p->hys==0)
- {
- memset(sendbuf,0,sizeof(sendbuf));
- strcpy(sendbuf,"没有此好友");
- send(fd,sendbuf,strlen(sendbuf),0);
- }
- int i;
- int num=p->hys;
- for(i=0;i<num;i++)
- {
- //如果找到
- if(strcmp(p->hy[i],find_id)==0)
- {
- //将其昵称取出
- p1=head->next;
- char str[20]={0};
- while(p1)
- {
- if(strcmp(p1->id,find_id)==0)
- {
- strcpy(str,p1->name);
- break;
- }
- p1=p1->next;
- }
- memset(sendbuf,0,sizeof(sendbuf));
- sprintf(sendbuf,"该好友账户为%s,昵称为%s",find_id,str);
- send(fd,sendbuf,strlen(sendbuf),0);
- }
-
- }
- }
-
- //删除好友
- void del_friends(int fd,char id[20])
- {
- cliMesg *p,*p1;
- int i,leap=0;
- char sendbuf[1024]={0};
- char recvbuf[1024]={0};
-
- p=he
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。