linux 下网络编程 聊天室项目

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

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

使用数据库: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));

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/47992.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Netty网络聊天室之基础网关搭建

前言 最近在学习Netty框架&#xff0c;使用的学习教材是李林锋著的《Netty权威指南》。国内关于netty的书籍几乎没有&#xff0c;这本书算是比较好的入门资源了。 我始终觉得&#xff0c;学习一个新的框架&#xff0c;除了研究框架的源代码之外&#xff0c;还应该使用该框架自…

PC端聊天机器人界面(html实现)

实现效果&#xff1a; 直接上代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width,initial-scale1"><title>PC机…

【HTML5期末大作业】制作一个简单HTML我的班级网页(HTML+CSS+JS)

&#x1f4c2;文章目录 一、&#x1f468;‍&#x1f393;网站题目二、✍️网站描述三、&#x1f4da;网站介绍四、&#x1f4a0;网站演示五、⚙️ 网站代码&#x1f9f1;HTML结构代码&#x1f492;CSS样式代码 六、&#x1f947; 如何让学习不再盲目七、&#x1f381;更多干货…

html5网页制作代码-我的班级网页 HTML期末大作业 学校班级网页制作模板

Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业&#xff0c;校园班级网页设计 | 我的班级网页 | 我的学校 | 校园社团 | 校园运动会 | 等网站的设计与制作 | HTML期末大学生网页设计作业 HTML&#xff1a;结构 CSS&#xff1a;…

大模型中的“罗翔老师”来了!

明敏 发自 凹非寺量子位 | 公众号 QbitAI 大模型中的“罗翔老师”&#xff0c;出现了&#xff01; 北大团队打造的法律大模型ChatLaw&#xff0c;发布即冲上知乎热搜第一。 它具备大模型能力和充足法律知识&#xff0c;能给法律小白们答疑解惑、提供法律建议。 比如针对网络热议…

大模型中的「罗翔老师」!北大兔展联合团队搞出ChatLaw,发布即登顶热榜,可提供法律咨询...

明敏 发自 凹非寺量子位 | 公众号 QbitAI 大模型中的“罗翔老师”&#xff0c;出现了&#xff01; 北大团队打造的法律大模型ChatLaw&#xff0c;发布即冲上知乎热搜第一。 它具备大模型能力和充足法律知识&#xff0c;能给法律小白们答疑解惑、提供法律建议。 比如针对网络热议…

chatgpt赋能python:Python入门:实现一个简单小游戏

Python入门&#xff1a;实现一个简单小游戏 Python是一种强大而又易于学习的编程语言&#xff0c;常用于开发网络应用、游戏和数据处理。如果你想尝试Python编程&#xff0c;实现一个简单的小游戏是一个不错的开始。在这篇文章中&#xff0c;我们将介绍如何实现一个猜数字游戏…

chatgpt赋能Python-python_hangman游戏

Python Hangman游戏&#xff1a;玩游戏学编程 Python是一种高级编程语言&#xff0c;它简单易学&#xff0c;具有强大的功能和广泛的应用领域。要成为一名Python开发工程师&#xff0c;除了理论知识之外&#xff0c;还需要实践知识&#xff0c;因此&#xff0c;我们介绍一个有…

excel在线_图片转Excel表格在线工具,分享几款不错的工具

你是否遇到这种情况&#xff0c;工作中需要将纸张或图片上的表格&#xff0c;在Excel中照着做出来&#xff1f;照着做太麻烦&#xff0c;今天&#xff0c;易老师给大家分享几款&#xff0c;可以将图片表格识别到Excel表格工具&#xff0c;可以大大的提升我们办公效率。 白描网页…

图片转表格怎么转?这篇文章告诉你

在日常的工作中&#xff0c;不知道你们是否会遇到这样的情况&#xff1a;你收到了一张表格图片&#xff0c;需要对它进行数据统计和分析&#xff0c;但你却无法直接对图片上的数据进行分析&#xff0c;所以大多数的人都会直接手动输入&#xff0c;这样子不仅耗时耗力&#xff0…

Excel转TXT怎么转?介绍两个办法

出于工作需要我们经常会用到excel&#xff0c;其统计分析、图表等功能十分便利。有时为了便于分享或其他需求也会将Excel转为其他格式&#xff0c;其中Excel转TXT怎么转你知道吗&#xff1f;这里给大家推荐两种方法~ 使用格式转换软件 具体转换步骤如下&#xff1a; 步骤一、先…

好用的excel图片转表格的方法都在这了

在日常生活中&#xff0c;我们经常会在工作群中收到领导或者同事发来的表格&#xff0c;不过这种表格往往都是以截图的方式传送过来&#xff0c;如果我们要重新编辑的话&#xff0c;再新建一个表格就比较浪费时间。如果可以有转换工具可以把Excel图片直接转成表格编辑&#xff…

图片转Excel表格在线工具,分享几款不错的工具!

你是否遇到这种情况,工作中需要将纸张或图片上的表格,在Excel中照着做出来?照着做太麻烦,今天,易老师给大家分享几款,可以将图片表格识别到Excel表格工具,可以大大的提升我们办公效率。 白描网页版 入口 :https://web.baimiaoapp.com/image-to-excel 白描支持图片转文…

图片转表格怎么转?看完这篇你就会了

在日常的办公中&#xff0c;我们有时会收到领导或者是同事发来的表格&#xff0c;不过这些表格往往都是以截图的形式发送过来的。如果我们想要编辑的话&#xff0c;就需要新做一个表格&#xff0c;可是根据图片的数据重新制作的话&#xff0c;就得花费很多时间。其实我们可以使…

将长表格图片转Excel表格

大家好,我是小小明。 最近很多朋友和同事问我如何将图片转Excel表格,老实说这方面现成的工具基本都不好使,不过百度AI有支持进行表格图片识别的接口,我们只要按照百度AI的要求传入相应的数据进行识别即可。 需求与技术点 需求,有两张超长的表格图片: 现在希望将其识别…

浪潮信息AS13000G6高密分布式存储加速测序进程

基因测试作为生命科学领域内的重要一环&#xff0c;在实施的过程中面临重重挑战&#xff0c;如何满足数据存储量及数据可靠性的需求&#xff1f;浪潮信息提供了一个新的解决方案。 此前&#xff0c;针对求臻医学信息化平台的相关需求及基因测序的业务特点&#xff0c;浪潮信息携…

一场VR大赛引发的元宇宙“狂飙”

319个团队、480人参赛&#xff0c;第三届华为云VR开发应用大赛盛况空前&#xff0c;而新设立的“人气数字人形象奖”“人气虚拟偶像奖”等&#xff0c;让大赛又一次“破圈”&#xff0c;人气直升。通过大赛&#xff0c;我们看到虚拟现实、数字人、元宇宙等正“脱虚向实”&#…

提高效率:使用这些工具,让你开发和学习更简单

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; 目录 零、ChatGPT一、代码1.代码备忘清单2.菜鸟教程3.代码转图片4.代码在线运行5.LaTeX 公式编辑器6.GitCode、GitHub 等代码仓库平台 二、绘图1.Canva 可画2.Echarts Js画图3.算法可视化4.函数绘图5.遇到 Alt 截不…

Photoshop-Beta智能版ps安装教程

Photoshop-Beta智能版ps安装教程 获取方式 安装包工具&#xff0c;关注公众号搜索 荷逸云&#xff0c;发送关键词&#xff1a;ps&#xff0c;即可获得 安装教程 0&#xff1a;注意事项 注意&#xff1a;安装此工具需要魔法上网&#xff0c;获取魔法方式&#xff1a; http…

手机上如何给图片加水印?

我们都知道&#xff0c;手机的抠图软件确实不太好找&#xff0c;不过我还是找到一款效果还不错的软件。 具体的操作步凑&#xff1a; 1、用手机打开多御浏览器软件&#xff0c;在软件首页找到实用工具&#xff0c;如图&#xff1a; 2、进入实用工具后&#xff0c;点击左侧办公…