欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 八卦 > EX_25/2/10

EX_25/2/10

2025/2/11 10:30:21 来源:https://blog.csdn.net/qq_74406476/article/details/145556393  浏览:    关键词:EX_25/2/10

epoll实现多路客户端之间的登录注册及消息和文件传输

服务器部分

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
#include <sys/epoll.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;enum Type{TYPE_REGIST,TYPE_LOGIN,TYPE_CHAT,TYPE_FILE_UPLOAD_REQUEST
};typedef struct Pack{enum Type type;char name[20];char pswd[20];char filename[20];long filesize;char tarname[20];char text[1024];
}pack_t;// 李四:你好
typedef struct User{char name[20];char pswd[20];int sock;int hasMsg; // 用来表示当前客户端是否拥有未读消息的数据:0表示不拥有,1表示拥有未读消息char msg[1024]; // 用来缓存针对该用户的未读消息
//	当该用户上线的时候,检索一下hasMsg是0还是1,如果是1,就将msg里面的数据发给自己int hasfileMsg;char fileMsg[1024];}user_t;user_t user_arr[50] = {0};
int user_len = 0;void read_data(int client);
void insert_user(user_t user);
int find_user(const char* username);int main(int argc, const char *argv[])
{if(argc != 2){printf("请输入端口号\n");return 1;}// ./server 8888int port = atoi(argv[1]);// 将字符串 8888 转换成int类型port// 创建服务器套接字int server = socket(AF_INET,SOCK_STREAM,0);// 准备网络地址结构体:struct sockaddr_inaddr_in_t addr = {0};addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = inet_addr("0.0.0.0");// 为套接字绑定ip 和 portif(bind(server,(addr_t*)&addr,sizeof(addr)) == -1){perror("bind");return 1;}// 监听listen(server,10);// 创建监视列表int epfd = epoll_create1(EPOLL_CLOEXEC);// 将 0 和 server 存入监视列表 epfd 中struct epoll_event epoll_stdin = {.events = EPOLLIN,.data.fd = 0};struct epoll_event epoll_server = {.events = EPOLLIN,.data.fd = server};epoll_ctl(epfd,EPOLL_CTL_ADD,0,&epoll_stdin);epoll_ctl(epfd,EPOLL_CTL_ADD,server,&epoll_server);// 准备一个数组,用来存放所有激活的描述符struct epoll_event arr[50] = {0};while(1){int len = epoll_wait(epfd,arr,50,-1);for(int i=0;i<len;i++){int fd = arr[i].data.fd;// 将到底是哪个描述符激活了单独取出来if(fd == server){printf("有新客户端连接\n");int client = accept(server,0,0);struct epoll_event epoll_client = {.events = EPOLLIN,.data.fd = client};epoll_ctl(epfd,EPOLL_CTL_ADD,client,&epoll_client);}else if(fd == 0){char buf[64] = "";scanf("%63s",buf);while(getchar()!=10);printf("键盘输入数据:%s\n",buf);}else{read_data(fd);}}}return 0;
}void insert_user(user_t user){user_arr[user_len] = user;user_len ++;
}int find_user(const char* username){for(int i=0;i<user_len;i++){if(strcmp(username,user_arr[i].name) == 0){return i;}}return -1;
}void read_data(int client){//while(1){pack_t pack = {0};int res = read(client,&pack,sizeof(pack));//if(res == 0){break;}switch(pack.type){case TYPE_REGIST:{int res = find_user(pack.name);// 根据用户发来的账号,在数组中查询是否存在char* msg = NULL;if(res == -1){ // 如果不存在返回-1user_t user = {0};strcpy(user.name,pack.name);strcpy(user.pswd,pack.pswd);insert_user(user);msg = "注册成功";}else{// 如果存在,返回这个账号在数组中的下标位置msg = "该账号已存在";}strcpy(pack.text,msg);write(client,&pack,sizeof(pack));break;}case TYPE_LOGIN:{int res  = find_user(pack.name);char* msg = NULL;if(res == -1){msg = "该账号不存在";}else{user_t user = user_arr[res];// 将找到的用户单独拎出来if(strcmp(user.pswd,pack.pswd) == 0){msg = "登录成功";user_arr[res].sock = client;// user_arr[res] 是根据当前登录用户发送过来的账号,找到的存放在数组中的用户结构体// client 是当前正在登录的用户在服务器的套接字if(user_arr[res].hasMsg == 1){// 说明当前用户存在未读消息pack_t pack = {0};pack.type = TYPE_CHAT;strcpy(pack.text , user_arr[res].msg); // 将缓存的消息写入 pack.text 里面write(client,&pack,sizeof(pack)); // 将缓存消息发给新登录的客户端user_arr[res].hasMsg = 0;}//存在未读文件if(user_arr[res].hasfileMsg==1){pack_t pack={0};pack.type=TYPE_FILE_UPLOAD_REQUEST;strcpy(pack.text,user_arr[res].fileMsg);write(client,&pack,sizeof(pack));user_arr[res].hasfileMsg=0;}}else{	msg = "密码错误";}}strcpy(pack.text,msg);write(client,&pack,sizeof(pack));break;}case TYPE_CHAT:{char* msg = NULL;// 聊天的时候,客户端会发来如下格式的信息 "张三:你好",表明 你好这条消息是发给张三的// 所以我们要根据张三的账号,找到张三的套接字,张三的姓名和套接字都存放在 结构体数组 user_arr里面int res = find_user(pack.tarname);if(res == -1){msg = "该用户不存在";strcpy(pack.text,msg);write(client,&pack,sizeof(pack));}else{user_t user = user_arr[res];// user_arr[res] 为准备接受聊天信息的用户if(user.sock == 0){//msg = "用户未登录";//strcpy(pack.text,msg);//write(client,&pack,sizeof(pack));user_arr[res].hasMsg = 1;// 表明当前用户存在了未读消息strcpy(user_arr[res].msg , pack.text); // 将准备发送给该用户的消息,缓存到user_arr[res].msg里面去}else{// 用户存在并登录的状态int tarsock = user.sock;write(tarsock,&pack,sizeof(pack));}}break;}case TYPE_FILE_UPLOAD_REQUEST:{//printf("接收到客户端文件上传请求:%s %s\n",pack.tarname,pack.filename);int res = find_user(pack.tarname);if(res == -1){// 没注册 今晚作业printf("该用户不存在\n");}else{if(user_arr[res].sock == 0){// 不在线,也是今晚作业user_arr[res].hasfileMsg=1;strcpy(user_arr[res].fileMsg,pack.text);}else{// 目标用户在线,直接将接收到的pack包转发给目标用户printf("转发文件中...\n");write(user_arr[res].sock,&pack,sizeof(pack));}}break;}}//}
}

客户端部分

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;enum Type{TYPE_REGIST,TYPE_LOGIN,TYPE_CHAT,TYPE_FILE_UPLOAD_REQUEST
};typedef struct Pack{enum Type type;char name[20];char pswd[20];char filename[20];long filesize;char tarname[20];char text[1024];
}pack_t;void* thread_main(void* arg){int client = *(int*)arg;while(1){pack_t pack = {0};int res = read(client,&pack,sizeof(pack));if(res == 0){break;}switch(pack.type){case TYPE_REGIST:{printf("%s\n",pack.text);break;}case TYPE_LOGIN:{printf("%s\n",pack.text);break;}case TYPE_CHAT:{printf("接收到消息:%s\n",pack.text);break;}case TYPE_FILE_UPLOAD_REQUEST:{char filename[128] = "./client_file_system/";// 获取文件名,方便打开文件strcat(filename , pack.filename);int fd = open(filename,O_CREAT | O_TRUNC | O_WRONLY,0666);// 获取文件长度long filesize = pack.filesize;long readed_size = 0;//printf("接收到文件名和文件大小\n");while(1){pack_t filepack = {0};int res = read(client,&filepack,sizeof(filepack)); // 读取别的客户端发来的文件内容if(res != sizeof(filepack)){printf("发生分包\n");}int size = strlen(filepack.text);//printf("接受到文件信息\n");write(fd,filepack.text,size);// 将接受到的文件内容,写入文件中去readed_size += size;if(readed_size >= filesize){close(fd);break;}}break;}}}
}int main(int argc, const char *argv[])
{if(argc != 2){printf("请输入端口号\n");return 1;}// ./server 8888int port = atoi(argv[1]);// 将字符串 8888 转换成int类型portint client = socket(AF_INET,SOCK_STREAM,0);addr_in_t addr = {0};addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = inet_addr("192.168.60.77");if(connect(client,(addr_t*)&addr,sizeof(addr)) == -1){perror("connect");return 1;}pthread_t id;pthread_create(&id,0,thread_main,&client);pthread_detach(id);while(1){int ch = -1;printf("1:注册\n");printf("2:登录\n");printf("3:聊天\n");printf("4:发送文件\n");printf("0:退出\n");printf("请选择:");scanf("%d",&ch);while(getchar()!=10);switch(ch){case 1:{pack_t pack = {0};printf("请输入账号:");scanf("%s",pack.name);while(getchar()!=10);printf("请输入密码:");scanf("%s",pack.pswd);while(getchar()!=10);pack.type = TYPE_REGIST;write(client,&pack,sizeof(pack));break;}case 2:{pack_t pack = {0};printf("请输入账号:");scanf("%s",pack.name);while(getchar()!=10);printf("请输入密码:");scanf("%s",pack.pswd);while(getchar()!=10);pack.type = TYPE_LOGIN;write(client,&pack,sizeof(pack));break;}case 3:{// 聊天对象的姓名:聊天内容// 聊天对象的姓名放在pack.tarname里面// 聊天内容放在 pack.text 里面// 张三:你好pack_t pack = {0};pack.type = TYPE_CHAT;scanf("%s %s",pack.tarname,pack.text);printf("tarname = %19s\n",pack.tarname);while(getchar()!=10);write(client,&pack,sizeof(pack));break;}case 4:{pack_t pack = {0};pack.type = TYPE_FILE_UPLOAD_REQUEST;printf("请输入接受文件的用户名:");char tarname[20] = "";scanf("%19s",pack.tarname);strcpy(tarname,pack.tarname);while(getchar()!=10);printf("请输入想要发送的文件名:");scanf("%19s",pack.filename);while(getchar()!=10);int fd = open(pack.filename,O_RDONLY);if(fd == -1){printf("该文件不存在\n");break;}struct stat buf = {0};stat(pack.filename,&buf);pack.filesize = buf.st_size;write(client,&pack,sizeof(pack));while(1){pack_t pack = {0};pack.type = TYPE_FILE_UPLOAD_REQUEST;strcpy(pack.tarname,tarname);int res = read(fd,pack.text,1023);if(res == 0){break;}write(client,&pack,sizeof(pack));}close(fd);break;}case 0:{break;}}}return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com