美食网站开发现状,个人跨境电商怎么做,搜索百度下载安装,网站开发相关技术发展目录
Server-Client
mutiplexingServer
mutiplexingClient
mutiplexing Server-Client 在Linux系统中#xff0c;IO多路复用是一种机制#xff0c;它允许一个进程能够监视多个文件描述符#xff08;sockets、pipes等#xff09;的可读、可写和异常等事件。这样#xf…目录
Server-Client
mutiplexingServer
mutiplexingClient
mutiplexing Server-Client 在Linux系统中IO多路复用是一种机制它允许一个进程能够监视多个文件描述符sockets、pipes等的可读、可写和异常等事件。这样一个进程就能够同时等待多个IO操作而不需要创建多个线程来处理每个IO操作。 常见的IO多路复用函数包括select、poll、epoll等。这些函数允许程序员编写高效的IO多路复用代码从而使得单个进程能够同时处理多个IO事件提高系统的并发性能。 使用IO多路复用的好处在于它可以避免创建大量的线程或进程来处理IO事件从而减少了系统资源的消耗并且降低了上下文切换的开销。这对于高性能的网络服务器等应用是非常重要的。 编写程序实现多个Client之间通过Server来传递消息从而实现client间的通信功能。要求如下
服务器创建3个众所周知的命名管道FIFO_1, FIFO_2, FIFO_3, 分别接收用户的注册请求、登录请求和聊天请求服务器等待任一管道来的请求收到时立即响应不同用户不允许使用同一用户名注册并设置密码。
每个用户都建立一个以自己用户名为名字的命名管道用户A发送给用户B的信息发送给服务器然后服务器通过B的专用FIFO发送给用户B。 基本思路是用select函数实现IO多路复用使得单个线程能够同时处理多个IO事件。
服务器能够处理多个用户的注册请求、登录请求和聊天请求不同用户之间可以通过服务器进行通信。
我们编写的代码文件有实现服务器的mutiplexingServer.c实现客户端的mutiplexingClient.c以及通信配置的mutiplexing.h。
首先是配置通信的头文件mutiplexing.h在这里我们定义了服务器众所周知的三个命名管道和规定了服务器可容纳用户的数目。 User结构体存储用户的命名管道信息以及用户名和密码。 Chat结构体存储聊天信息包括目标用户的命名管道信息和发送者的命名管道信息还有要发送的聊天信息。 还有一个Response结构体用来存储服务器返回客户端的响应信息由于操作不一定总是客户端所期望的所以我们除了正常的响应信息外还存储了一个ok值当ok值不为0时说明操作异常。 接下来我们来看服务器的实现。
首先定义了一个全局变量userNumber来记录当前用户的数量还有一个users数组存储所有用户的信息。 然后创建三个众所周知的命名管道文件并打开。 指定检查这三个文件描述符并获取最大的文件描述符。 关键用select监听这些文件描述符。 然后发现哪个文件描述符准备好可读的时候就调用我们写好的处理函数来处理。 下面逐个讲解我们写的处理函数。
首先是处理注册请求的函数。
我们拿到用户名判断现有的用户组中是否有相同的用户名如果有那么我们向客户端返回该用户名已经存在的信息。 如果没有用户名与它相同那么我们把这个用户的信息加到现有的用户组里面并向客户端返回注册成功的消息并且在服务器端打印该用户注册的信息。 然后看登录处理函数。
首先看看当前用户组里面有没有这个用户找到的话就比较密码是否相同相同就向客户端发送登录成功的信息并在服务器端打印该用户登录的信息密码不同就发送密码错误的信息如果没有找到这个用户就发送用户名错误的信息。 最后看聊天处理函数。
首先判断该用户要发生的目标用户存不存在存在的话就向目标用户发送聊天信息并向发送者反馈信息发送成功如果目标用户不存在向发送者反馈该用户不存在。 再看客户端实现。
主函数是创建命名管道然后进入功能页面显示函数。 在主功能页面我们首先提示用户输入r表示注册输入l表示登录输入q表示退出。如果是输入l或者r即注册或者登录我们就收集用户名和密码然后跳转到相应的请求发送函数如果收到其他字符则给出输入错误信息并重新展示主功能页面。 然后我们看注册请求发送函数。
打开众所周知的注册命名管道向其写入我们收集的用户名和密码等待服务器响应后打印响应信息并返回主页面因为不管注册的结果如何都需要返回主页面进行下一步的操作。 然后是登录请求函数。
同样我们打开众所周知的登录命名管道向其写入收集的用户名和密码如果登录成功那么进入聊天页面否则返回主页面。 最后看聊天请求函数。
先展示功能提示用户按下r表示接收消息按下s表示发送消息按下q表示退出当前页面。 如果是发送消息那么需要输入发送目标用户的用户名已经要发送的消息并打印服务器返回的发送结果。 如果是接收消息就从自己的命名管道中读取数据并打印。 如果用户按下的其他按键那么提示用户按错了重新展示聊天页面。 现在我们来展示运行结果。
首先编译运行服务器可以看到服务器已经启动。 再编译运行一个客户端可以看到功能展示页面。 然后我们输入r注册输入用户名yemaolin和密码2021155015可以看到服务器返回的注册成功的信息。 然后我们输入l登录输入刚刚注册的用户名和密码进行登录可以看到登录成功。 然后我们再开一个客户端注册一个game101密码是OpenGL并登录。 然后我们用game101给yemaolin发消息hello, I am game101。 然后我们用yemaolin接收消息。 然后yemaolin再给game101发一条消息I love C。 同样game101可以收到yemaolin发来的消息。 最后我们可以看一下服务器端打印的消息这展示了用户的状态。 圆满结束IO多路复用。
这个过程还是比较难顶的但是结果还是比较美好的。
首先不得不说IO多路复用真的是美妙。我大二曾经用Java写过多个客户端的聊天程序但是是用的多线程实现的。如今居然可以用单线程实现多用户访问服务器真是神奇。当然多路复用只能让服务器同时处理多个用户的请求轮到客户端本身发送和接受消息的时候在同一时间客户端只能选择发送消息或者是接收消息。如果要同时接收和发送的话那估计只有多线程可以实现了。
这次使用select实现的IO多路复用聊天程序除了能够处理正常的用户注册、用户登录和用户间通信之外还对一些异常情况做了处理例如用户重复注册登录用户名错误或者是密码错误已经发送消息时目标用户不存在等情况做了处理让我们的程序更加健壮。
除此之外为了之后的功能拓展以及便于修改我们将每个功能模块化并将一些基本的配置消息单独写在一个头文件这为我们之后的进一步完善做了比较坚实的基础。
mutiplexingServer
#include unistd.h
#include stdlib.h
#include stdio.h
#include string.h
#include sys/stat.h
#include fcntl.h
#include mutiplexing.h
#include sys/select.hint userNumber 0; // 当前用户量
User users[UserCapacity];void registerHandler(User*user) {char message[BuffSize];int ok 0;for (int i 0; i userNumber; i) {if (strcmp(user-username, users[i].username) 0) {sprintf(message, The username has already exited!);ok -1;break;}}if (ok 0) {strcpy(users[userNumber].username, user-username);strcpy(users[userNumber].password, user-password);sprintf(message, Register succeed!);printf(User %s register\n,user-username);userNumber;}int fd open(user-fifo, O_RDWR | O_NONBLOCK);write(fd, message, BuffSize);
}void loginHandler(User*user) {Response response;response.ok -1;for (int i 0; i userNumber; i) {if (strcmp(user-username, users[i].username) 0) {if (strcmp(user-password, users[i].password) 0) {strcpy(users[i].fifo, user-fifo);sprintf(response.message, Login succeed!);printf(User %s login\n,user-username);response.ok 0;break;} else {sprintf(response.message, Wrong password!);response.ok-2;break;}}}if (response.ok -1) {sprintf(response.message, Wrong username!);}int fd open(user-fifo, O_RDWR | O_NONBLOCK);write(fd, response, sizeof(Response));
}void chatHandler(Chat*chat) {char message[BuffSize];int ok -1;for (int i 0; i userNumber; i) {if (strcmp(chat-targetUser, users[i].username) 0) {int fd open(users[i].fifo, O_RDWR | O_NONBLOCK);write(fd, chat-message, BuffSize);sprintf(message, Send succeed!);ok 0;break;}}if (ok -1) {sprintf(message, User %s does not exit!, chat-targetUser);}int fd open(chat-fifo, O_RDWR | O_NONBLOCK);write(fd, message, BuffSize);
}int main() {fd_set fds, read_fds; // 文件描述符集合int max_fd;int register_fd, login_fd, chat_fd;// 创建或打开FIFO文件mkfifo(Register_FIFO, 0777);mkfifo(Login_FIFO, 0777);mkfifo(Chat_FIFO, 0777);// 打开FIFO文件 O_RDWR 可读写 O_NONBLOCK 非阻塞register_fd open(Register_FIFO, O_RDWR | O_NONBLOCK);login_fd open(Login_FIFO, O_RDWR | O_NONBLOCK);chat_fd open(Chat_FIFO, O_RDWR | O_NONBLOCK);// 指定要检查的文件描述符FD_ZERO(fds);FD_SET(register_fd, fds);FD_SET(login_fd, fds);FD_SET(chat_fd, fds);// 获取最大文件描述符max_fd register_fd login_fd ? register_fd : login_fd;max_fd max_fd chat_fd ? max_fd : chat_fd;printf(MutiplexingServer Listening\n);while (1) {read_fds fds;User registerData;User loginData;Chat chatData;// 使用select监听文件描述符if (select(max_fd 1, read_fds, NULL, NULL, NULL) -1) {perror(select);exit(EXIT_FAILURE);}// 检查哪些文件描述符已经准备好if (FD_ISSET(register_fd, read_fds)) {// 处理注册read(register_fd, registerData, sizeof(User));registerHandler(registerData);}if (FD_ISSET(login_fd, read_fds)) {// 处理登录read(login_fd, loginData, sizeof(User));loginHandler(loginData);}if (FD_ISSET(chat_fd, read_fds)) {// 处理聊天read(chat_fd, chatData, sizeof(Chat));chatHandler(chatData);}}
}mutiplexingClient
#includeunistd.h
#includestdio.h
#include stdlib.h
#includestring.h
#includesys/stat.h
#includefcntl.h
#includemutiplexing.hvoid showPage(User*user);void registerClient(User*user){int register_fd open(Register_FIFO, O_RDWR | O_NONBLOCK);write(register_fd, user, sizeof(User));int fdopen(user-fifo,O_RDWR | O_NONBLOCK);char message[BuffSize];while(1){int result read(fd,message,BuffSize);if(result0){printf(%s\n,message);break;}}showPage(user);
}
void chatClient(User*user){char what;printf(Chat Page:\npress r for receive | s for send | q for quit\n);while((whatgetchar())\n){}if (what q) {exit(0);} else if(what s) { // 发送信息Chat chat;strcpy(chat.fifo,user-fifo);printf(send username: );scanf(%s,chat.targetUser);getchar();printf(send data: );scanf(%[^\n],chat.message);int chat_fdopen(Chat_FIFO,O_RDWR | O_NONBLOCK);write(chat_fd,chat,sizeof(Chat));// 等待服务器响应int fdopen(user-fifo,O_RDWR | O_NONBLOCK);char message[BuffSize];while(1){int result read(fd,message,BuffSize);if(result0){printf(%s\n,message);break;}}} else if(whatr){ //接收消息int fdopen(user-fifo,O_RDWR | O_NONBLOCK);char message[BuffSize];while(1){int result read(fd,message,BuffSize);if(result0){printf(%s\n,message);break;}}}else{printf(Wrong press key, please try again!\n);}chatClient(user);
}
void loginClient(User*user){int login_fd open(Login_FIFO, O_RDWR | O_NONBLOCK);write(login_fd, user, sizeof(User));int fdopen(user-fifo,O_RDWR | O_NONBLOCK);Response response;while(1){int result read(fd,response,sizeof(Response));if(result0){printf(%s\n,response.message);break;}}if(response.ok!0){ // 登录失败showPage(user);}else{chatClient(user);}
}void showPage(User*user){char what;printf(Chat Client:\npress r for register | l for login | q for quit\n);while((whatgetchar())\n){}if (what q) {exit(0);} else if(whatr||whatl) {printf(username: );scanf(%s, user-username);printf(password: );scanf(%s, user-password);}else{printf(Wrong press key, please try again!\n);showPage(user);}if (what r) {registerClient(user);}else if(whatl){loginClient(user);}
}
int main() {User user;sprintf(user.fifo, client_fifo/client_fifo%d, getpid());mkfifo(user.fifo, 0777);showPage(user);exit(0);
}mutiplexing
#ifndef SYSTEMPROGRAM_MESSAGE_H
#define SYSTEMPROGRAM_MESSAGE_H
#define Register_FIFO register_fifo // 注册
#define Login_FIFO login_fifo // 登录
#define Chat_FIFO chat_fifo // 聊天
#define BuffSize 100
#define UserCapacity 10 // 可容纳用户量
typedef struct {char fifo[BuffSize]; //clients FIFO namechar username[20];char password[20];
} User;
typedef struct {char fifo[BuffSize]; //clients FIFO namechar targetUser[20]; // 向谁发送信息char message[BuffSize];
} Chat;
typedef struct{int ok;char message[BuffSize];
}Response;
#endif //SYSTEMPROGRAM_MESSAGE_H