服务端使用框架:非阻塞轮询;

客户端使用框架:多线程;

使用数据库:mysql;

实现主要功能:

1.注册;

2.登录;

3.群聊;

4.私聊;

5.查看聊天记录;

6.查看在线人数;

7.修改个性签名;

8.修改密码;

9.发送文件;

10.退出登录;

11.注销账号;

进入时界面:左边服务器,右边客户端;

登录成功时界面:

客户端:

client.h

#ifndef _select_h_
#define _select_h_
#include <stdio.h>
#include <time.h>
#define SIZE 1024
#define NOW_MAX 20
typedef struct msg          //表示聊天时的信息
{char msg[SIZE];        //消息内容char localname[20];       //消息目的名称char account[20];            //账户char fromname[20];      //消息来源名称char password[20];      //用户密码   char signname[40];      //个性签名   int cmd;                //工作模式int num;                //用于保存文件复制的字节数
}Msg;//最大允许并行客户端数量void regisc(int client_socket);void main_menu(void);int Ask_server(int client_socket);int entry(int client_socket);void user_menu(void);void User_used(int client_socket);void * readMsg (void *v);void entry_out(int client_socket);void chat_all(int client_socket);void chat_one(int client_socket);void client_logout(int client_socket);void save(Msg*msg);void look_chat();void see_now_time(int client_socket);void revise_sign(int client_socket);void revise_password(int client_socket);void client_guanli(int client_socket);void transfer_file(int client_socket);//传输文件void transfer_file_y(int client_socket);//同意接受文件void transfer_file_n(int client_socket);//拒绝接受文件void start_transfer_file(int client_socket);//开始传输文件void save_transfer_file(Msg * buf);//接受文件#endif

client.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include<netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include "client.h"#define SER_IP       "127.0.0.1"
#define SER_PORT     6789#define LISTEN_MAX   100
char myname[20]={0};
char signname[100]={0};
char account_c[100]={0};
char mylocalname[20]; //用于保存传输文件来源的名字
char fsignname[40]; //用于保存文件传输名字
int root=0;
int flag = 1;
void *recvdata_do_handler(void *a);
/********************************************* TCP通信客户端流程* 1,创建套接字* 2,请求连接* 3,收发数据* 4,关闭套接字* *************************************************/int main(int argc, char  *argv[])
{//1.创建套接字   IPV4  流式套接字  TCP协议int clifd = socket(AF_INET,SOCK_STREAM,0);if(clifd == -1){perror("socket");return -1;}printf("clifd = %d\n",clifd);struct sockaddr_in seraddr;memset(&seraddr,0,sizeof(struct sockaddr_in));seraddr.sin_family = AF_INET;//ipv4协议类型seraddr.sin_addr.s_addr = inet_addr(SER_IP);seraddr.sin_port = htons(SER_PORT);//端口    网络字节序//2.请求连接if(connect(clifd,(struct sockaddr *)&seraddr,sizeof(struct sockaddr_in)) == -1){perror("connect");return -1;}printf("连接成功\n");Ask_server(clifd);close(clifd);return 0;
}void main_menu(void)
{system("clear");printf("\n\n\n\n\n\n\n\n");printf("+++++++++++++++++++++++++++++++++++++++++\n");printf("+++\t    欢迎使用101聊天室      +++\n");printf("+++\t\t1,注册                +++\n");printf("+++\t\t2,登录                +++\n");printf("+++\t\t3,退出                +++\n");printf("+++++++++++++++++++++++++++++++++++++++++\n");}int Ask_server(int client_socket)
{char ch;int ret;while(1){main_menu();//引用菜单栏printf("请输入您要做操作\n");scanf("%c",&ch);while(getchar() != '\n');switch(ch){case '1':    //注册regisc(client_socket);sleep(1);break;case '2':    //登录ret = entry(client_socket);if (ret == 1){User_used(client_socket);    //调用函数表示用户界面}sleep(1);break;case '3':    //退出exit(0);break;}}
}
//注册函数
void regisc(int client_socket)
{Msg msg;memset(&msg,0,sizeof(msg));msg.cmd=1;printf("请输入用户名\n");scanf("%s",msg.fromname);while(getchar() != '\n');printf("请输入账号\n");scanf("%s",msg.account);while(getchar() != '\n');printf("请输入密码\n");scanf("%s",msg.password);while(getchar() != '\n');printf("请输入个性签名\n");scanf("%s",msg.signname);while(getchar() != '\n');send(client_socket,&msg,sizeof(msg),0);recv(client_socket,&msg,sizeof(msg),0);printf("%d\n",msg.cmd);if(msg.cmd == 1001){printf("注册成功\n");}else if (msg.cmd == -1){printf("用户名以存在,注册失败\n");}else{printf("系统繁忙,注册失败\n");}sleep(2);}//登录账号
int entry(int client_socket)
{Msg msg;memset(&msg,0,sizeof(msg));msg.cmd = 2;printf("登录,请输入账号名: ");scanf("%s",msg.account);while(getchar() != '\n');printf("登录,请输入密码: ");scanf("%s",msg.password);while(getchar() != '\n');printf("\n");write(client_socket, &msg, sizeof(msg));memset(&msg,0,sizeof(msg));read(client_socket, &msg, sizeof(msg));printf("%d\n",msg.cmd);if(msg.cmd == -1)    //表示用户不存在{printf("登录失败,系统繁忙.\n");sleep(2);return -1;}if(msg.cmd == -2)    //表示用户不存在{printf("登录失败,用户不存在.\n");sleep(2);return -2;}if(msg.cmd == -3){printf("登录失败,用户已登录.\n");sleep(2);return -3;}  if(msg.cmd == -4){printf("登录失败,密码错误.\n");sleep(2);return -4;}   if(msg.cmd == 1002){printf("登录成功,登录中...\n");printf("%s %s \n",msg.fromname,msg.signname);strcpy(myname,msg.fromname);      //保存在线名字strcpy(signname, msg.signname);   //保存个性签名strcpy(account_c,msg.account);    //保存账号root=msg.num; //获取权限sleep(2);return 1;}
}void user_menu(void)
{system("clear");printf("%s: %s\n",myname,signname);//printf("\n\n\n\n\n\n\n");printf("++++++++++++++++++++++++++++++++++++++++\n");printf("+++                                  +++\n");printf("+++\t   欢迎使用101聊天室      +++\n");printf("+++                                  +++\n");printf("++++++++++++++++++++++++++++++++++++++++\n");printf("+++\t\t1,群聊               +++\n");printf("+++\t\t2,私聊               +++\n");printf("+++\t\t3,退出登录           +++\n");printf("+++\t\t4,查看聊天记录       +++\n");printf("+++\t\t5,显示当前在线人员   +++\n");printf("+++\t\t6,修改个性签名       +++\n");printf("+++\t\t7,修改密码           +++\n");printf("+++\t\t8,传输文件           +++\n");printf("+++\t\t9,注销账号           +++\n");printf("+++\t\tA,管理           +++\n");printf("++++++++++++++++++++++++++++++++++++++++\n");
}//用户界面
void User_used(int client_socket)
{//要进行读写分离pthread_t read_id;pthread_create(&read_id, NULL, readMsg, (void *)&client_socket);pthread_detach(read_id);   //等待线程分离char ch;flag=1;while(flag){user_menu();//调用第二个用户界面printf("请输入您要做操作\n");scanf("%c",&ch);while(getchar() != '\n');switch(ch){case '1':        //群聊chat_all(client_socket);break;case '2':        //私聊chat_one(client_socket);break;case '3':        //退出登录   entry_out(client_socket);flag = 0;break;case '4':        //查看聊天记录look_chat();  break;case '5':        //显示当前在线人数 see_now_time(client_socket);break;case '6':        //修改个性签名revise_sign(client_socket);break;case '7':        //修改密码revise_password(client_socket);sleep(1);   break;case '8':        //传输文件transfer_file(client_socket);break;case 'y':        //表示愿意接受文件transfer_file_y(client_socket);printf("接收中\n");getchar();break;case 'n':        //表示不愿意接受文件transfer_file_n(client_socket);sleep(1);break;        case '9':client_logout(client_socket);//表示注销账号flag=0;break;case 'a':if(root==1)//判断是不是管理员client_guanli(client_socket);elseprintf("管理失败没有权限\n");sleep(1);break;}}//pthread_cancel(read_id);
}//读写分离专门收消息
void * readMsg (void *v)
{int client_socket = *((int*)v);Msg buf;time_t t;struct tm *pt;int i = 0;while(1){memset(&buf,0,sizeof(Msg));int ret = read(client_socket, &buf, sizeof(Msg));if(ret == -1){perror("read");break;}switch(buf.cmd){case 3:  printf(" %s\n",buf.msg);save(&buf);    //保存聊天记录break;case 4:   //私聊printf(" %s\n",buf.msg);save(&buf);    //保存聊天记录break;case -3:  //私聊失败printf("私聊失败,用户不存在或下线\n");break;case 5 :  //退出登录printf("%s 退出登录\n",buf.fromname);sleep(1);pthread_exit(NULL);    //线程退出break;case 6 :   //显示当前在线人数printf("当前在线人员:\n");printf("%s\n",buf.msg);break;case 7 :  //修改个性签名成功strcpy(signname,buf.signname);printf("修改个性签名成功\n");break;case -7 :  //修改个性签名失败printf("修改个性签名失败\n");break;case 8    :   //修改密码成功printf("修改密码成功\n");entry_out(client_socket);flag=0;break;case -8 :   //修改密码失败printf("修改密码失败\n");break;case 9  :   //调用函数确认是否接受文件system("clear");printf("请问你是否接受来自 %s 的文件 %s(y/n)\n",buf.fromname,buf.signname);strcpy(mylocalname,buf.fromname);   //保存传输文件来源名字sleep(1);break;case -9 :   //表示传输文件失败,没有找到该人printf("发送文件失败,好友不在线或不存在\n");sleep(1);break;case 10 :   //表示愿意接受文件,开始传输start_transfer_file(client_socket);sleep(1);break;case -10 :  //表示不愿意接受文件printf("发送文件失败,好友拒绝接受文件\n");sleep(1);break;case 11 :   //接受文件save_transfer_file(&buf);break;//printf("%d\n",i);case 22:printf("%s\n",buf.msg);break;case 87:printf("禁言成功\n");break;case 88:printf("踢人成功\n");break;case 99:printf("注销成功\n");sleep(1);pthread_exit(NULL);    //线程退出break;default:break;}}
}void entry_out(int client_socket)//退出登录
{Msg msg;memset(&msg,0,sizeof(msg));msg.cmd=5;strcpy(msg.account,account_c);strcpy(msg.fromname,myname);send(client_socket,&msg,sizeof(msg),0);sleep(1);}void chat_all(int client_socket)//群聊
{system("clear");Msg msg;time_t t;char senr[150];memset(&msg,0,sizeof(msg));msg.cmd = 3;strcpy(msg.fromname,myname);strcpy(msg.localname,"All");printf("输入quit退出\n");printf("请输入你要群发送的信息\n");while(1){memset(msg.msg,0,sizeof(msg.msg));memset(senr,0,sizeof(senr));// getchar();time(&t);struct tm *pt = localtime(&t);getchar();printf("%d年%d月%d日 %d:%d:%d\n",pt->tm_year+1900,pt->tm_mon+1,pt->tm_mday,pt->tm_hour,pt->tm_min,pt->tm_sec);sprintf(msg.msg,"\t\t\t%d年%d月%d日 %d:%d:%d\n\t\t\t",pt->tm_year+1900,pt->tm_mon+1,pt->tm_mday,pt->tm_hour,pt->tm_min,pt->tm_sec);printf("%s:",msg.fromname);scanf("%s",senr);strcat(msg.msg,msg.fromname);strcat(msg.msg,":");strcat(msg.msg,senr);while(getchar() != '\n');if(strcmp("quit",senr)==0)break;write(client_socket, &msg, sizeof(Msg));}save(&msg);sleep (2);
}void chat_one(int client_socket)//私聊
{system("clear");Msg msg;char senr[150];time_t t;memset(&msg,0,sizeof(msg));msg.cmd = 4;printf("请输入你要聊天的对象:\n");scanf ("%s",msg.localname);while(getchar() != '\n');strcpy (msg.fromname,myname);while(1){getchar();time(&t);struct tm *pt = localtime(&t);printf("%d年%d月%d日 %d:%d:%d\n",pt->tm_year+1900,pt->tm_mon+1,pt->tm_mday,pt->tm_hour,pt->tm_min,pt->tm_sec);sprintf(msg.msg,"\t\t\t%d年%d月%d日 %d:%d:%d\n\t\t\t",pt->tm_year+1900,pt->tm_mon+1,pt->tm_mday,pt->tm_hour,pt->tm_min,pt->tm_sec);printf("%s:",msg.fromname);scanf("%s",senr);while(getchar() != '\n');if(strcmp("quit",senr)==0){break;}strcat(msg.msg,msg.fromname);strcat(msg.msg,":");strcat(msg.msg,senr);write(client_socket, &msg, sizeof(Msg));save(&msg);    //保存聊天记录}sleep(2);
}void client_logout(int client_socket)//注销
{Msg msg;memset(&msg,0,sizeof(msg));msg.cmd=99;strcpy (msg.account,account_c);send(client_socket,&msg,sizeof(msg),0);
}void save(Msg*msg)//保存
{char buf2[120];char ai[1050];memset(buf2,0,sizeof(buf2));memset(ai,0,sizeof(ai));if(strcmp(myname,msg->fromname)==0){sprintf(buf2,"../liaotianjilu/%s & %s.txt",msg->fromname,msg->localname);}else{sprintf(buf2,"../liaotianjilu/%s & %s.txt",msg->localname,msg->fromname);}    int ps=open(buf2,O_WRONLY|O_CREAT|O_APPEND,0644);sprintf(ai,"%s\n",msg->msg);write(ps,ai,strlen(ai));close (ps);}void look_chat()//查看聊天记录
{char buf2[120];char ai[10500];memset(ai,0,sizeof(ai));memset(buf2,0,sizeof(buf2));printf("查看与谁的聊天记录:\n");scanf("%s",buf2);while(getchar()!='\n');sprintf(ai,"../liaotianjilu/%s & %s.txt",myname,buf2);int ps=open(ai,O_RDONLY);if(ps==-1){printf("查看失败\n");sleep(1);return;}memset(ai,0,sizeof(ai));read(ps,ai,sizeof(ai));printf("%s\n",ai);getchar();close(ps);}void see_now_time(int client_socket)//查看在线人数
{Msg msg;memset(&msg,0,sizeof(msg));msg.cmd = 6;strcpy (msg.fromname,myname);write(client_socket, &msg, sizeof(Msg));sleep(2);
}void client_guanli(int client_socket)//管理
{Msg msg;memset(&msg,0,sizeof(msg));printf("请选择:1禁言,2踢人\n");int i;scanf("%d",&i);while(getchar()!='\n');if(i==1){msg.cmd=87;printf("请选择要禁言的人:\n");see_now_time(client_socket);scanf("%s",msg.localname);}else if(i==2){msg.cmd=88;printf("请选择要踢的人:\n");see_now_time(client_socket);scanf("%s",msg.localname);}else{printf("管理失败\n");return;}strcpy (msg.fromname,myname);write(client_socket, &msg, sizeof(Msg));sleep(1);
}//修改个性签名
void revise_sign(int client_socket)
{Msg msg;memset(&msg,0,sizeof(msg));msg.cmd = 7;printf("请输入新的个性签名:");scanf("%s",msg.signname);while(getchar() != '\n');strcpy(msg.fromname,myname);   //需要保存名字strcpy(msg.account,account_c);write(client_socket, &msg, sizeof(Msg));sleep(2);
}//修改密码
void revise_password(int client_socket)
{Msg msg;memset(&msg,0,sizeof(msg));msg.cmd = 8;printf("请输入新的密码: ");scanf("%s",msg.password);while(getchar() != '\n');strcpy(msg.fromname,myname);   //需要保存名字strcpy(msg.account,account_c);write(client_socket, &msg, sizeof(Msg));sleep(2);
}   void transfer_file(int client_socket)//传输文件
{Msg msg;msg.cmd = 9;printf("请输入你要传输文件的对象:");scanf ("%s",msg.localname);while(getchar() != '\n');printf("请输入你要传输的本地文件名:");scanf ("%s",msg.signname);while(getchar() != '\n');strcpy(msg.fromname,myname);   //需要保存名字write(client_socket, &msg, sizeof(Msg));printf("等待验收中...\n");strcpy(fsignname,msg.signname);strcpy(mylocalname,msg.localname);getchar();}//表示愿意接受文件
void transfer_file_y(int client_socket)
{Msg msg;msg.cmd = 10;strcpy(msg.fromname,myname); strcpy(msg.localname,mylocalname); strcpy(mylocalname,"\0");    //用完后置零write(client_socket, &msg, sizeof(Msg));
}//表示不愿意接受文件
void transfer_file_n(int client_socket)
{Msg msg;msg.cmd = -10;strcpy(msg.fromname,myname); strcpy(msg.localname,mylocalname); strcpy(mylocalname,"\0");    //用完后置零write(client_socket, &msg, sizeof(Msg));
}//传出文件来源开始传输文件
void start_transfer_file(int client_socket)
{Msg msg;char ai[120];msg.cmd = 11; strcpy(msg.fromname,myname); strcpy(msg.signname,fsignname);strcpy(msg.localname,mylocalname);sprintf(ai,"../send/%s",msg.signname);int fd = open(ai,O_RDONLY); if(fd == -1){perror("open");printf("传输失败\n");return ;}int ret = 0;int i = 0;while(ret = read(fd,msg.msg,SIZE)){if(ret == -1){perror("read");break;}if (ret == 0){break;}msg.num = ret;write(client_socket, &msg, sizeof(Msg));usleep(10000);     //这个睡眠时间减缓传输速度,降低不可预祝错误出现}printf("文件复制完成传输\n");strcpy(fsignname,"\0");strcpy(mylocalname,"\0");close(fd);
}//接受文件
void save_transfer_file(Msg * buf)
{char ai[120];sprintf(ai,"../recv/%s",buf->signname);int fd = open(ai,O_WRONLY|O_CREAT|O_APPEND,0777);write(fd,buf->msg,buf->num);if(buf->num != SIZE){printf ("文件接受完成\n");}close (fd);}

服务端:

select.h

#ifndef _select_h_
#define _select_h_
#include <stdio.h>
#define SIZE 1024
#define NOW_MAX 20
typedef struct msg          //表示聊天时的信息
{char msg[SIZE];        //消息内容char localname[20];       //消息目的名称char account[20];            //账户char fromname[20];      //消息来源名称char password[20];      //用户密码   char signname[40];      //个性签名   int cmd;                //工作模式int num;                //用于保存文件复制的字节数
}Msg;//最大允许并行客户端数量typedef struct now_client   //在线人数
{char name[20];int socket;int jin;int ti;
}NowClient;
int regiss(int client_socket, Msg *msg);
int entry(int client_socket, Msg *msg);
void server_entryout(int client_socket,Msg *msg);
void server_chatall(int client_socket, Msg * msg);
void server_chatone(int client_socket, Msg * msg);
void server_logout(int client_socket,Msg *msg);
void server_save(Msg*msg);
void see_nowuser(int client_socket, Msg * msg);
void sremove(int client_socket, Msg * msg);
void shutup(int client_socket, Msg * msg);
void server_transfer_file(int client_socket, Msg * msg);//收到开始传输文件命令void server_transfer_file_y(Msg * msg);//接受文件void server_transfer_file_n(Msg * msg);//拒绝文件void server_start_transfer_file(Msg * msg);//开始文件传输
void server_revise_sign(int client_socket, Msg * msg);
void server_revise_password(int client_socket, Msg * msg);
#endif

server.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include<netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include "select.h"
#include "1mysql.h"#define SER_IP       "127.0.0.1"
#define SER_PORT     6789#define LISTEN_MAX   100
NowClient user[NOW_MAX];    //表示当前在线人的资料/********************************************* TCP通信服务器端流程* 1,创建套接字* 2,绑定* 3,监听* 4,等待连接* 5,收发数据* 6,关闭套接字* *************************************************/int all_clifd[256] = {0};//存放所有的客户端描述符
int count = 0;//计数
MYSQL *my_sql;//数据库描述符void accept_do_handler(int sockfd);
void recv_do_handler(int sockfd);
void send_to_all_cli(char *buf);int sockfd;
void guan()//关闭函数
{close(sockfd);mysql_close(my_sql);exit(-1);
}
int main(int argc, char  *argv[])
{pid_t pid= fork();if (pid==0){//1.创建套接字   IPV4  流式套接字  TCP协议sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd == -1){perror("socket");return -1;}printf("sockfd = %d\n",sockfd);signal(10,guan);//2.绑定struct sockaddr_in seraddr;memset(&seraddr,0,sizeof(struct sockaddr_in));seraddr.sin_family = AF_INET;//ipv4协议类型// seraddr.sin_addr;//ip地址  网络字节序// inet_aton(SER_IP,&seraddr.sin_addr);seraddr.sin_addr.s_addr = inet_addr(SER_IP);seraddr.sin_port = htons(SER_PORT);//端口    网络字节序int opt=1;setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));if(bind(sockfd,(struct sockaddr *)&seraddr,sizeof(struct sockaddr_in)) == -1){perror("bind");return -1;}printf("绑定成功\n");//3.监听if(listen(sockfd,LISTEN_MAX) == -1){perror("listen");return -1;}printf("监听成功\n");//非阻塞轮询int maxfd = sockfd;//处理连接请求--》sockfd发生可读变化//接收数据--》clifd发生可读变化fd_set readfds;//检测可读变化my_sql=Sconnect();//连接数据库int ret = 0;// struct timeval select_time;int i = 0;while(1){////先去清空集合FD_ZERO(&readfds);//再去添加FD_SET(sockfd,&readfds);for(i = 0;i<count;i++){//添加描sockfd述符FD_SET(all_clifd[i],&readfds);//求出来最大的if(all_clifd[i]>maxfd){maxfd = all_clifd[i];}}printf("\n");//永久阻塞ret = select(maxfd+1,&readfds,NULL,NULL,NULL);if(ret == -1){perror("select");return -1;}else if(ret == 0){printf("超时\n");continue;}//有变化,会打断阻塞,将集合里边没有变化的删除掉else{// printf("有文件描述符发生变化\n");//判断是谁发生的变化,根据变化去作处理//轮询从0到maxfd所有的文件描述符for(i = 0;i<=maxfd;i++){//检查发生变化的是否是readfds集合里边的if(FD_ISSET(i,&readfds)==1){//服务器套接字描述符发生变化//有客户端请求连接if(i == sockfd){accept_do_handler(sockfd);}//有客户端发消息else{recv_do_handler(i);}}} }}}else{char a;while(1){printf("y/n\n");a=getchar();if(a=='y'){printf("1");kill(pid,10);exit(0);}}}
}void accept_do_handler(int sockfd)
{//4.等待连接//存放连接成功之后,客户端的IP地址和端口struct sockaddr_in cliaddr;memset(&cliaddr,0,sizeof(struct sockaddr_in));socklen_t len = sizeof(struct sockaddr_in);int clifd = accept(sockfd,(struct sockaddr *)&cliaddr,&len);if(clifd == -1){perror("accept");return;}//存储所有的客户端描述符all_clifd[count] = clifd;count++;}void recv_do_handler(int client_socket)
{// 5.数据收发int i = 0;int ret = 0;int pos = 0;//记录下表Msg msg;memset(&msg,0,sizeof(msg));//阻塞ret = recv(client_socket,&msg,sizeof(msg),0);char shi[1024];sprintf(shi,"%s %s %s %s",msg.fromname,msg.account,msg.signname,msg.password);printf("%s\n",shi);if(ret==-1){perror("recv");return ;}else if(ret == 0){for(i = 0;i<count;i++){if(all_clifd[i] == client_socket){all_clifd[i] = 0;pos = i;break;}}for(i = pos;i<count-1;i++){all_clifd[i] = all_clifd[i+1];}all_clifd[count-1]=0;count--;}else{switch (msg.cmd){case 1 :    // 注册regiss(client_socket, &msg);break;case 2 :    //登录ret = entry(client_socket, &msg);send(client_socket , &msg ,sizeof(Msg),0);if (ret == 1){//在线人数加1int i;for (i=0; i<NOW_MAX; i++){if(user[i].socket == 0){strcpy(user[i].name, msg.fromname);user[i].socket = client_socket;user[i].jin=0;user[i].ti=0;printf("客户端在线人数加一\n");break;}}char guanbuf[1000];sprintf(msg.msg,"%s已登录",msg.fromname);msg.cmd=22;//用户界面for(i=0;i<NOW_MAX;i++){if(user[i].socket == 0)continue;if(user[i].socket==client_socket)continue;send(user[i].socket,&msg,sizeof(Msg),0);}  }    break;case 3://群聊server_chatall(client_socket, &msg);server_save(&msg);break;case 4 :    //私聊server_chatone(client_socket, &msg);server_save(&msg); break;case 5://退出登录server_entryout(client_socket,&msg);sprintf(msg.msg,"%s已下线",msg.fromname);msg.cmd=22;for(i=0;i<NOW_MAX;i++){if(user[i].socket == 0)continue;if(user[i].socket==client_socket)continue;send(user[i].socket,&msg,sizeof(Msg),0);}  break;case 6://在线人数see_nowuser(client_socket,&msg);break;case 7://改签名server_revise_sign(client_socket, &msg);break;case 8://改密码server_revise_password(client_socket, &msg);break;case 9://传输文件server_transfer_file(client_socket, &msg);break;case 10:   //接受传输文件server_transfer_file_y(&msg);break;case -10 : //拒绝传输文件server_transfer_file_n(&msg);break;case 11:   //一切条件都已成立,直接开始传输server_start_transfer_file(&msg);break;case 87://禁言shutup(client_socket,&msg);break;case 88://移除sremove(client_socket,&msg);break;case 99://注销server_logout(client_socket,&msg);break;}}}int regiss(int client_socket, Msg *msg)//注册
{//printf("nihaos%d\n",__LINE__);int flag;int i=-1,j=-1,a=0;i=search(my_sql,msg);j=search1(my_sql);if(j==0){a=1;}printf("%d\n",i);if(i==0){ //printf("nihaos%d\n",__LINE__);flag= data_insert(my_sql,msg,client_socket,a);msg->cmd+=1000;}else if(i==1)msg->cmd=-1;printf("%d\n",msg->cmd);// printf("nihaos%d\n",__LINE__);send(client_socket,msg,sizeof(Msg),0);}int entry(int client_socket, Msg *msg)
{printf(" %s进行登录\n",msg->fromname);//用户登录int flag = Entry_User(my_sql,msg,client_socket);if (flag == -1){printf("登录失败,系统繁忙\n");msg->cmd = -1;return -1;}if (flag == -2){printf("登录失败,用户名不存在\n");msg->cmd = -2;return -2;}if (flag == -3){printf("登录失败,用户已登录\n");msg->cmd = -3;return -3;}if (flag == -4){printf("登录失败,密码错误\n");msg->cmd = -4;return -4;}else {printf("登录成功\n");msg->cmd += 1000;return 1;}
}void server_entryout(int client_socket,Msg *msg)//退出登录
{int ret= change(my_sql,"type","0",msg->account);//printf("%d\n",client_socket);if(ret==0){int i ;for(i=0; i<NOW_MAX; i++){if(user[i].socket == client_socket){user[i].socket = 0;printf("客户端在线人数减一\n");break;}}msg->cmd=5;sprintf(msg->msg,"退出登录成功");}else{sprintf(msg->msg,"退出登录失败");msg->cmd=-5;}//printf("%d\n",client_socket);char shi [1024];sprintf(shi,"%s %s %s %s %d",msg->fromname,msg->account,msg->signname,msg->password,msg->cmd);printf("%s\n",shi);send(client_socket,msg,sizeof(Msg),0);//printf("fasongcg\n");
}void server_chatall(int client_socket, Msg * msg)//群聊
{printf (" %s 进行群发.\n",msg->fromname);int j;for (j=0; j<NOW_MAX; j++){if(user[j].socket==client_socket){if(user[j].ti==1){memset(msg->msg,0,1000);sprintf(msg->msg,"发送失败已被移除群聊");write(client_socket, msg , sizeof(Msg));return ;}if(user[j].jin==1){memset(msg->msg,0,1000);sprintf(msg->msg,"发送失败已被禁言");write(client_socket, msg , sizeof(Msg));return ;}break;}}int i;for(i=0; i<NOW_MAX; i++){if (user[i].socket != 0&&user[i].socket!=client_socket&&user[i].ti!=1){write(user[i].socket, msg , sizeof(Msg));}}
}void server_chatone(int client_socket, Msg * msg)//私聊
{printf ("私聊 %s发送信息给%s\n",msg->fromname,msg->localname);int i;for(i=0; i<NOW_MAX; i++){if(user[i].socket != 0 && strcmp(user[i].name, msg->localname) == 0){write(user[i].socket, msg , sizeof(Msg));printf("私聊成功\n");break;}}if (i == NOW_MAX){msg->cmd = -3;    //表示私聊失败write(client_socket, msg , sizeof(Msg));printf("私聊失败\n");}
}void server_logout(int client_socket,Msg *msg)//注销
{int ret=mysql_delete(my_sql,msg->account);if(ret==0){printf("注销成功\n");int i ;for(i=0; i<NOW_MAX; i++){if(user[i].socket == client_socket){user[i].socket = 0;printf("客户端在线人数减一\n");break;}}msg->cmd=99;}elsemsg->cmd=-99;send(client_socket,msg,sizeof(Msg),0);
}void server_save(Msg*msg)//保存聊天记录
{char buf2[120];char ai[1250];memset(buf2,0,sizeof(buf2));memset(ai,0,sizeof(ai));sprintf(buf2,"../serverliaotianjilu/all.txt");int ps=open(buf2,O_WRONLY|O_CREAT|O_APPEND,0644);sprintf(ai,"%s->%s:%s\n",msg->fromname,msg->localname,msg->msg);write(ps,ai,strlen(ai));close (ps);}void see_nowuser(int client_socket, Msg * msg)//在线人员
{printf("%s 查看当前在线人员\n",msg->fromname);int i;int len;char buf[1024] = {0};for(i=0; i<NOW_MAX; i++){if(user[i].socket != 0){strcat(buf,user[i].name);len = strlen(buf);buf[len] = ' ';}}strcpy(msg->msg,buf);write(client_socket, msg, sizeof(Msg));printf("查看成功\n");
}void server_revise_sign(int client_socket, Msg * msg)//修改个性签名
{printf("%s 修改个性签名\n",msg->fromname);int ret = change(my_sql,"signname",msg->signname,msg->account);    //修改数据库if (ret == -1){msg->cmd = -7;printf("%s 修改个性签名失败\n",msg->fromname);write(client_socket, msg, sizeof(Msg));}printf("%s 修改个性签名成功\n",msg->fromname);write(client_socket, msg, sizeof(Msg));
}//修改密码
void server_revise_password(int client_socket, Msg * msg)
{printf("%s 修改密码\n",msg->fromname);int ret = change(my_sql,"passwd",msg->password,msg->account);if (ret == -1){msg->cmd = -8;printf("%s 修改密码失败\n",msg->fromname);write(client_socket, msg, sizeof(Msg));}printf("%s 修改密码成功\n",msg->fromname);write(client_socket, msg, sizeof(Msg));
}void shutup(int client_socket, Msg * msg)//禁言
{int i;for (i=0; i<NOW_MAX; i++){if(strcmp(user[i].name ,msg->localname)==0){user[i].jin=1;break;}}write(client_socket, msg, sizeof(Msg));
}void sremove(int client_socket, Msg * msg)//移除
{int i;for (i=0; i<NOW_MAX; i++){if(strcmp(user[i].name ,msg->localname)==0){user[i].ti=1;break;}}write(client_socket, msg, sizeof(Msg));
}//传输文件
void server_transfer_file(int client_socket, Msg * msg)
{printf ("%s 请求发送%s文件给 %s\n",msg->fromname,msg->signname,msg->localname);int i;for(i=0; i<NOW_MAX; i++){if(user[i].socket != 0 && strcmp(user[i].name, msg->localname) == 0){write(user[i].socket, msg , sizeof(Msg));printf("发送给%s信息进行判断是否接受\n",msg->localname);break;}}if (i == NOW_MAX){msg->cmd == -9;    //表示传输文件失败write(client_socket, msg , sizeof(Msg));printf("发送文件失败,好友不在线或不存在\n");}
}void server_transfer_file_y(Msg * msg)//接收文件
{printf("%s 接受文件传输.\n",msg->fromname);int i;for(i=0; i<NOW_MAX; i++){if(user[i].socket != 0 && strcmp(user[i].name, msg->localname) == 0){write(user[i].socket, msg , sizeof(Msg));break;}}
}//拒绝文件
void server_transfer_file_n(Msg * msg)
{printf("%s 不愿意接受文件传输.\n",msg->fromname);int i;for(i=0; i<NOW_MAX; i++){if(user[i].socket != 0 && strcmp(user[i].name, msg->localname) == 0){write(user[i].socket, msg , sizeof(Msg));break;}}
}void server_start_transfer_file(Msg * msg)
{//printf("文件传输中\n");int i;for(i=0; i<NOW_MAX; i++){if(user[i].socket != 0 && strcmp(user[i].name, msg->localname) == 0){write(user[i].socket, msg , sizeof(Msg));    //写文件数据break;}}if(msg->num != 1024){printf("文件传输完成\n");}
}

数据库端:

1mysql.h

#ifndef _mysql_h_
#define _mysql_h_
#include <stdio.h>
#include <mysql/mysql.h>
#include <string.h>
#include <stdlib.h>
#include "select.h"
#define HOSTNAME        "localhost"
#define USERNAME        "root"
#define PASSWD          "1"
#define DATABASENAME    "chatroom"
#define TABLENAME       "infor"
void print_all_data(MYSQL *mysql,Msg *msg);
int search(MYSQL *mysql,Msg *msg);MYSQL * Sconnect();
int data_insert(MYSQL *mysql,Msg *msg,int sockfd,int root);
int  Entry_User(MYSQL *con,Msg *msg,int my_sockfd);
int change(MYSQL *my_sql,char *field,char * changenaem,char *naem);
int mysql_delete(MYSQL *my_sql,char *deletename);
int search1(MYSQL *mysql);
#endif

mysql.c

#include "1mysql.h"
#include "select.h"
MYSQL * Sconnect()//连接数据库
{static MYSQL my_sql;//0.初始化核心结构体mysql_init(&my_sql);//1.连接数据库//指定使用"hello"数据库MYSQL*p =  mysql_real_connect(&my_sql,HOSTNAME,USERNAME,PASSWD,DATABASENAME,0,NULL,0);if(p == NULL){// perror("mysql_real_connect");printf("mysql_error:%s\n",mysql_error(&my_sql));return NULL;}printf("数据库连接成功\n");return &my_sql;
}void print_all_data(MYSQL *mysql,Msg *msg)
{char buf[256];int ret = 0;memset(buf,0,sizeof(buf));sprintf(buf,"SELECT * FROM %s",TABLENAME);// printf("buf:%s\n",buf);ret = mysql_real_query(mysql,buf,strlen(buf));if(ret != 0){printf("mysql_error:%s\n",mysql_error(mysql));return;}// printf("查询数据成功\n");//获取结果集MYSQL_RES *pres = mysql_store_result(mysql);if(pres == NULL){printf("mysql_error:%s\n",mysql_error(mysql));return;}    // printf("获取结果集成功\n");MYSQL_ROW row;int i,j;for(i = 0;i<mysql_num_rows(pres);i++){//读取结果集里边的一行数据row = mysql_fetch_row(pres);if(row ==  NULL){printf("mysql_error:%s\n",mysql_error(mysql));return;}for(j=0;j<mysql_num_fields(pres);j++){printf("%s\t",row[j]?row[j]:NULL);}printf("\n");}//释放结果集mysql_free_result(pres);
}int search(MYSQL *mysql,Msg *msg)//查询数据表某一项
{int ret;char buf[256];
printf("nihaos\n");sprintf(buf,"SELECT * FROM %s WHERE account='%s'",TABLENAME,msg->account);ret = mysql_real_query(mysql,buf,strlen(buf));MYSQL_RES *pres = mysql_store_result(mysql);uint64_t rownum =  mysql_num_rows(pres);return rownum;
}int search1(MYSQL *mysql)//查询数据表
{int ret;char buf[256];
printf("nihaos\n");sprintf(buf,"SELECT * FROM %s ",TABLENAME);ret = mysql_real_query(mysql,buf,strlen(buf));MYSQL_RES *pres = mysql_store_result(mysql);uint64_t rownum =  mysql_num_rows(pres);return rownum;
}int data_insert(MYSQL *mysql,Msg *msg,int sockfd,int root)//插入数据表
{char query[1024];sprintf(query,"insert into %s values('%s','%s','%s','%d','%d','%d','%s')",TABLENAME ,msg->fromname,msg->account,msg->password,0,sockfd,root,msg->signname);printf("%s\n",query);if((mysql_real_query(mysql,query,(unsigned int)strlen(query))) != 0){printf("insert failed.\n");return 0;}return 1;
}int  Entry_User(MYSQL *con,Msg *msg,int my_socket)//登录
{char query[1024],shi[1024];sprintf(query,"SELECT * FROM %s WHERE account = '%s'",TABLENAME,msg->account);if((mysql_real_query(con,query,(unsigned int)strlen(query))) != 0){printf("insert failed.\n");return -1;}MYSQL_RES *pres = mysql_store_result(con);uint64_t rownum =  mysql_num_rows(pres);if(rownum==0){return -2;}MYSQL_ROW row;int num_fields=mysql_num_fields(pres);row=mysql_fetch_row(pres);if(strcmp(row[3],"1")==0){return -3;}if(strcmp(msg->password,row[2])!=0){return -4;}char di[10];sprintf(di,"%d",my_socket);change(con,"socket",di,msg->account);change(con,"type","1",msg->account);strcat(msg->signname,row[6]);strcat(msg->fromname,row[0]);if(strcmp(row[5],"1")==0)msg->num=1;elsemsg->num=0;return 0;}int change(MYSQL *my_sql,char *field,char * changenaem,char *naem)//修改数据表
{char query[1024];sprintf(query,"update  %s set %s = '%s' where account='%s'",TABLENAME,field,changenaem,naem);if((mysql_real_query(my_sql,query,(unsigned int) strlen(query)))!=0){printf("insert failed.\n");return -1;}
return 0;}int mysql_delete(MYSQL *my_sql,char *deletename)//删除数据表
{char query[1024];sprintf(query,"delete from %s  where account='%s'",TABLENAME,deletename);if((mysql_real_query(my_sql,query,(unsigned int) strlen(query)))!=0){printf("insert failed.\n");return -1;}
return 0;}

编译客户端:gcc client.c -lmysqlclient -lpthread -o c

编译服务端:gcc server.c mysql.c -lmysqlclient -lpthread -o s

注意:使用mysql要安装相应的库;

安装服务器端

sudo apt-get install mysql-server

安装客户端

sudo apt-get install mysql-client

安装C语言API库

sudo apt-get install libmysqlclient-dev

如果想直接运行代码的话还要在mysql里面添加chatroom数据库,在chatroom库里面添加infor数据表;

步骤1:创建chatroom数据库,代码:create database chatroom;

步骤2:进入chatroom数据库,代码:use chatroom;

步骤3:创建infor数据表,代码:CREATE TABLE infor(name varchar(20),account varchar(20),passwd varchar(20),type int,socket int,root int,signname varchar(100));

linux 下网络编程 聊天室项目相关推荐

  1. Linux c网络编程聊天室项目

    涉及内容 C/s框架,多线程,进程,TCP/UDP双协议,c库文件,sqlite3,线程池,码量6000+ 主要实现功能:注册,登录,忘记.修改.查找密码,信息群私收发,文件群私收发,常用语问候语群私 ...

  2. Linux环境下——C语言聊天室项目

    由于使用了多线程操作,客户端进入程序后请先随便注册一次用户后再进行使用. 本程序默认第一个用户即ID为1的用户为超级管理员. 由于线程阻塞,最后的踢人操作有阻塞,需要在被踢出在线链表后手动下线. 看了 ...

  3. Linux下网络编程

    Linux下网络编程初步 Linux以其源代码公开闻名于世,并以其稳定性和可靠性雄霸操作系统领域,在网络应用技术方面使用得更加广泛.很久以来它就是Windows的重要对手之一.随着网络时代的来临,Li ...

  4. java网络编程-聊天室

    目录 V01 # 聊天室客户端(V1) # 聊天室服务端(V1) V02 # 聊天室客户端(V2) # 聊天室服务端(V2) V03 V04 # 聊天室客户端(V4) # 聊天室服务端(V4) V05 ...

  5. linux下多人聊天室

    客户端 一个在Linux下可以使用的聊天软件,要求至少实现如下功能:1. 采用Client/Server架构2. Client A 登陆聊天服务器前,需要注册自己的ID和密码3. 注册成功后,Clie ...

  6. Linux网络编程--聊天室客户端程序

    聊天室客户端程序 #define _GNU_SOURCE 1 #include <sys/types.h> #include <sys/socket.h> #include & ...

  7. linux下c语言聊天室程序,纯C语言Socket实现聊天室

    最近在学习嵌入式开发,练习C语言小项目,基本是参考别人的代码,做了些修改实现了聊天室,纯C语言编写. 想直接看源码的跳到最后. 一.练习内容 socket通信流程 管道的使用 epoll的使用 首先要 ...

  8. 【Netty】NIO 网络编程 聊天室案例

    文章目录 一. NIO 聊天室需求 二. NIO 聊天室 服务器端 代码分析 三. NIO 聊天室 客户端 代码分析 四. NIO 聊天室 服务器端 完整代码 五. NIO 聊天室 客户端 完整代码 ...

  9. linux下网络编程设置非阻塞,UNIX网络编程 非阻塞connect的实现

    一.<UNIX网络编程>-非阻塞connect 在一个TCP套接口被设置为非阻塞之后调用connect,connect会立即返回EINPROGRESS错误,表示连接操作正在进行中,但是仍未 ...

最新文章

  1. SpringBoot定义统一的controller返回格式
  2. IntelliJ IDEA2016学习小结
  3. C++类的Const数组的初始化
  4. php 固定人数拼手气_独立统计在线人数和访问数代码分享(php)
  5. 微软工程院院长:1万多应聘者挑不出100人
  6. linux源码文件名,Linux中文件名解析处理源码分析
  7. 华为联发科可以升级鸿蒙吗,华为鸿蒙系统降临!首批升级手机确定,联发科芯片被放弃?...
  8. 华为鸿蒙系统小米,继华为鸿蒙之后,又一国产系统在悄悄崛起:小米MIOS全面曝光...
  9. 随笔--四个月培训小结
  10. Python 第三方扩展库
  11. 每日作业-品优购详情页
  12. 某同学:1年经验和1本软考证书,很迷茫~
  13. c# 操作word光标
  14. linux桌面lxde 安装_Ubuntu怎么安装轻量级的LXDE桌面
  15. python:使用 PythonMagick 生成 icon 图标
  16. tmp在java中的意思_tmp是什么文件?tmp文件用什么打开?图文讲解
  17. MySql 表空间查询
  18. 2018-2019第一学期Java助教心得
  19. python里写中文出现 “SyntaxError: Non-ASCII character... but no encoding declared”解决方法
  20. Redis缓存的雪崩、穿透、击穿

热门文章

  1. 汇报工作就使用麦肯锡的结构化思考、SCQA表达框架
  2. python编写一个名片_详解Python做一个名片管理系统
  3. TAGE-SC-L Branch Predictors
  4. 青少年CTF训练平台Misc-Middle愿风神忽悠你题解
  5. 判断门禁卡是否加密_离无卡生活更进一步!判断您的门禁卡能否被手机NFC功能模拟...
  6. 网络聊天程序的设计与实现
  7. studio one 3 机架声道设置_PotPlayer:最强电脑影音视频播放器 | 附基础设置和精美皮肤推荐...
  8. 趣图:大佬如何解决bug的
  9. 使用python实现mysql测试数据的准备(大批量导入数据)
  10. matlab电力电子技术仿真错误,Matlab在电力电子技术仿真中的应用