ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【Linux高性能服务器编程】——高性能服务器框架 [打印本页]

作者: 乌市泽哥    时间: 2024-7-18 11:57
标题: 【Linux高性能服务器编程】——高性能服务器框架
 

  hello !大家好呀! 接待大家来到我的Linux高性能服务器编程系列之高性能服务器框架先容,在这篇文章中,你将会学习到高效的创建本身的高性能服务器,而且我会给出源码举行剖析,以及手绘UML图来帮助大家来明白,希望能让大家更能了解网络编程技能!!!
  希望这篇文章能对你有所帮助
,大家要是觉得我写的不错的话,那就点点免费的小爱心吧!
(注:这章对于高性能服务器的架构非常紧张哟!!!)
  
         
  目录
 一.服务器模型
    1.1 C/S模型
C/S模型的组成
C/S模型的通信过程
1.2 P2P模型
Linux 中的服务器 P2P 模型
二. 两种高效的服务器事件处理
2.1 Reactor模式
Linux 中的 Reactor 模式
2.2. Proactor模式
Linux 中的 Proactor 模式
 一.服务器模型

    1.1 C/S模型


C/S模型,即客户端/服务器模型(Client/Server Model),是一种网络盘算模型,它将任务和工作负载分配到客户端和服务器两个差别的盘算情况中。在这种模型中,客户端负责发送请求,而服务器负责处理请求并返回相应。
如图:
 

C/S模型的组成

C/S模型的通信过程

我们可以使用多线程来举行实现,一个连接的业务处理分配一个线程:

核心代码如下:
线程处理函数:
  1. // 定义线程函数
  2. void *handle_client(void *socket_desc) {
  3.     int sock = *(int*)socket_desc;
  4.     char *message;
  5.     int len;
  6.     // 接收客户端数据
  7.     while((len = read(sock, message, 1024)) > 0) {
  8.         printf("收到数据:%s\n", message);
  9.         // 发送响应
  10.         write(sock, "Hello, Client!", 14);
  11.         memset(message, 0, 1024);
  12.     }
  13.     // 关闭套接字
  14.     close(sock);
  15.     return 0;
  16. }
复制代码
 主函数:
  1. int main() {
  2.     int sock, newsock, clilen;
  3.     struct sockaddr_in serv_addr, cli_addr;
  4.     int *new_sock;
  5.     pthread_t thread_id;
  6.     // 创建套接字
  7.     sock = socket(AF_INET, SOCK_STREAM, 0);
  8.     if (sock == -1) {
  9.         printf("Could not create socket");
  10.     }
  11.     // 填充服务器地址结构
  12.     serv_addr.sin_family = AF_INET;
  13.     serv_addr.sin_addr.s_addr = INADDR_ANY;
  14.     serv_addr.sin_port = htons(8080);
  15.     // 绑定套接字到地址
  16.     if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
  17.         perror("bind failed");
  18.         return -1;
  19.     }
  20.     // 监听套接字
  21.     listen(sock, 3);
  22.     printf("Listening...\n");
  23.     clilen = sizeof(cli_addr);
  24.     // 接受客户端连接
  25.     while((newsock = accept(sock, (struct sockaddr *)&cli_addr, (socklen_t*)&clilen)) > 0) {
  26.         // 创建新线程
  27.         new_sock = malloc(1);
  28.         *new_sock = newsock;
  29.         if (pthread_create(&thread_id, NULL, handle_client, (void*)new_sock) < 0) {
  30.             perror("could not create thread");
  31.             return -1;
  32.         }
  33.         pthread_detach(thread_id);
  34.     }
  35.     // 关闭套接字
  36.     if (newsock < 0) {
  37.         perror("accept failed");
  38.         return -1;
  39.     }
  40.     return 0;
  41. }
复制代码

1.2 P2P模型

在 Linux 情况中,P2P(点对点)模型是一种直接连接两个或多个盘算机的网络通信方式,其中没有中心服务器参与数据传输。在 P2P 模型中,每个节点既是客户端也是服务器,可以相互发送和吸收数据。
Linux 中的服务器 P2P 模型

如图:

代码和C/S相似,大家可以去网上自行探求资料,这里就不再重复了哦!

二. 两种高效的服务器事件处理

2.1 Reactor模式

Reactor 模式是一种事件驱动的网络编程模式,用于处理高并发网络服务。在 Reactor 模式中,一个或多个线程负责监听网络事件,当事件发生时,例如新的连接请求、数据到达等,Reactor 模式会触发相应的处理函数来处理这些事件。
Linux 中的 Reactor 模式

流程图如下:
  
   使用的是同步I/O模型。
  1) 主线程往epol l 内核事件表中注册socket上的读停当事件。
  2) 主线程调用epol l _ wait等待 socket 上有数据可读。 
  3)当socket 上有数据可读时, epoll _ wait关照主线程。主线程则将socket 可读事件放入请求队列。  
  4)就寝在请求队列上的某个工作线程被唤醒,它从 socket 读取数据,并处理客户请求,然后往epol l内核事件表中注册该socket 上的写停当事件。
  5) 主线程调用epoll _ wait等待 socket 可写。
  6)当socket 可写时, epoll wait关照主线程。主线程将socket 可写事件放入请求队列。 
  7)就寝在请求队列上的某个工作线程被唤醒,它往socket上写入服务器处理客户请求的效果。
 
  
2.2. Proactor模式

Proactor 模式是一种事件驱动的网络编程模式,与 Reactor 模式雷同,但它使用异步 I/O 操作来处理网络事件。在 Proactor 模式中,一个或多个线程负责监听网络事件,当事件发生时,例如新的连接请求、数据到达等,Proactor 模式会触发相应的处理函数来处理这些事件。
Linux 中的 Proactor 模式

 详细流程图如下:

   1)主线程调用aio _ read 函数向内核注册socket 上的读完成事件, 并告诉内核用户读缓冲区的位置,以及读操作完成时如何关照应用程序(这里以信号为例,详情请参考sigevent的man手册)。
  2)主线程继续处理其他逻辑。 
  3)当socket上的数据被读入用户缓冲区后,内核将向应用程序发送一个信号,以关照应用程序数据已经可用。  
  4)应用程序预先界说好的信号处理函数选择一个工作线程来处理客户请求。工作线程处理完客户请求之后,调用aio _ write函数向内核注册 socket上的写完成事件, 并告诉内核用户写缓冲区的位置,以及写操作完成时如何关照应用程序(仍然以信号为例)。
  5)主线程继续处理其他逻辑。  
  6)当用户缓冲区的数据被写入socket之后,内核将向应用程序发送一个信号,以关照应用程序数据已经发送完毕。  
  7)应用程序预先界说好的信号处理函数选择一个工作线程来做善后处理,好比决定是否关闭 socket。
   这里给出一个代码例子:
事件处理函数:
  1. // 事件处理函数
  2. void *handle_connection(void *socket_desc) {
  3.     int sock = *(int*)socket_desc;
  4.     char *message;
  5.     int len;
  6.     // 接收客户端数据
  7.     while((len = read(sock, message, 1024)) > 0) {
  8.         printf("收到数据:%s\n", message);
  9.         // 发送响应
  10.         write(sock, "Hello, Client!", 14);
  11.         memset(message, 0, 1024);
  12.     }
  13.     // 关闭套接字
  14.     close(sock);
  15.     return 0;
  16. }
复制代码
循环逻辑:
  1. while(1) {
  2.         activity = epoll_wait(epollfd, events, MAX_EVENTS, -1);
  3.         if ((activity < 0) && (errno != EINTR)) {
  4.             printf("epoll_wait error");
  5.             return -1;
  6.         }
  7.         for (i = 0; i < activity; i++) {
  8.             if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) {
  9.                 // 处理错误情况
  10.                 close(events[i].data.fd);
  11.                 continue;
  12.             }
  13.             if (events[i].data.fd == sock) {
  14.                 // 有新的客户端连接
  15.                 newsock = accept(sock, (struct sockaddr *)&cli_addr, (socklen_t*)&clilen);
  16.                 printf("新的客户端连接:%s\n", inet_ntoa(cli_addr.sin_addr));
  17.                 client_sockets[i] = newsock;
  18.                 event.events = EPOLLIN;
  19.                 event.data.fd = newsock;
  20.                 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, newsock, &event) == -1) {
  21.                     perror("epoll_ctl failed");
  22.                     return -1;
  23.                 }
  24.             } else {
  25.                 // 处理客户端数据
  26.                 new_sock = malloc(1);
  27.                 *new_sock = events[i].data.fd;
  28.                 if (pthread_create(&thread_id, NULL, handle_connection, (void*)new_sock) < 0) {
  29.                     perror("could not create thread");
  30.                     return -1;
  31.                 }
  32.                 pthread_detach(thread_id);
  33.             }
  34.         }
  35.     }
  36.     // 关闭 epoll 实例
  37.     close(epollfd);
  38.     return 0;
  39. }
复制代码
在这个例子中,服务器端使用 epoll 函数来实现 Proactor 模式,创建一个简朴的服务器。服务器使用 pthread 库来创建多线程来处理多个客户端的连接,每个连接都由一个单独的线程处理。服务器收到客户端的请求后,发送一个相应,并关闭与客户端的连接。(不是完备代码哦!)
      好啦!到这里这篇文章就结束啦,关于实例代码中我写了很多解释,如果大家还有不懂得,可以批评区或者私信我都可以哦
!! 感谢大家的阅读,我还会持续创造网络编程相干内容的,记得点点小爱心和关注哟!
     

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4