当前位置: 首页 > news >正文

扁平化网站导航ui模板电子商务网站建设与管理理解

扁平化网站导航ui模板,电子商务网站建设与管理理解,网站后台 批量上传,做网站找谁在高并发场景下,传统的“一请求一线程”模型面临着线程开销大、上下文切换频繁的问题。为了解决这个瓶颈,本文介绍一个基于 epoll 的 TCP 服务器实现。它通过 I/O 多路复用机制 同时监听多个连接 socket,从而实现轻量级并发处理,显…

在高并发场景下,传统的“一请求一线程”模型面临着线程开销大、上下文切换频繁的问题。为了解决这个瓶颈,本文介绍一个基于 epoll 的 TCP 服务器实现。它通过 I/O 多路复用机制 同时监听多个连接 socket,从而实现轻量级并发处理,显著提升服务器性能。

一、epoll 是什么?

epoll 是 Linux 内核提供的 高效 I/O 多路复用机制,用于同时监听多个文件描述符(通常是 socket),并在某个描述符“就绪”时通知应用程序进行处理。

epoll 的优势:

  • 边沿触发水平触发模式灵活高效;

  • 内核维护事件队列,避免重复遍历(相比 select/poll);

  • 支持上万级别连接,适合高并发服务器场景。

二、TCP epoll 服务器流程图

启动程序↓
创建监听 socket 并绑定端口↓
创建 epoll 实例并注册监听 socket↓
========= 循环开始 =========↓
epoll_wait 等待事件发生↓
├── 如果是监听 socket ⇒ accept 新连接并加入 epoll
└── 如果是客户端 fd ⇒ recv 接收数据 or 关闭连接↓
========= 循环继续 =========

三、epoll 高并发模型原理

在高并发 TCP 网络服务器中,epoll 允许程序通过一个线程同时监听多个连接,一旦某个连接有数据可读或断开,系统立即通知应用程序处理,无需为每个连接分配线程或进程,从而节省了系统资源,提高了性能。

四、核心代码讲解

模块一:服务端 socket 初始化与监听

int sockfd = socket(AF_INET, SOCK_STREAM, 0);       // 创建 TCP socketstruct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));                     // 清零地址结构
addr.sin_family = AF_INET;                          // IPv4
addr.sin_port = htons(port);                        // 端口号(主机转网络字节序)
addr.sin_addr.s_addr = INADDR_ANY;                  // 接收任意地址bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)); // 绑定地址和端口
listen(sockfd, 5);                                   // 启动监听,最大队列为 5

模块二:epoll 初始化与监听 socket 注册

int epfd = epoll_create(1);                          // 创建 epoll 实例
struct epoll_event events[EPOLL_SIZE] = {0};         // 存储就绪事件数组struct epoll_event ev;
ev.events = EPOLLIN;                                 // 监听“可读事件”
ev.data.fd = sockfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);         // 注册监听 socket
  • 创建 epoll 文件描述符

  • 将监听 socket 注册到 epoll,用于接收客户端连接

模块三:主事件循环(accept 与数据处理)

while(1) {int nready = epoll_wait(epfd, events, EPOLL_SIZE, -1);  // 等待事件if(nready == -1) continue;for(int i = 0; i < nready; i++) {if(events[i].data.fd == sockfd) {  // 有新连接struct sockaddr_in client_addr;socklen_t client_len = sizeof(client_addr);int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);ev.events = EPOLLIN | EPOLLET;            // 边沿触发,提高效率ev.data.fd = clientfd;epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev);} else {int clientfd = events[i].data.fd;char buffer[BUFFER_LENGTH] = {0};int len = recv(clientfd, buffer, BUFFER_LENGTH, 0);if(len <= 0) { // 客户端断开close(clientfd);epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, NULL);} else {printf("Recv: %s, %d byte(s)\n", buffer, len);}}}
}
  • epoll_wait 是 epoll 的核心,它阻塞等待多个 fd 的“事件就绪”通知。

  • 监听 socket 触发时,说明有新的客户端请求,此时使用 accept() 获取新连接并加入 epoll 监听。

    • 已连接的客户端 socket 触发时,调用 recv() 读取数据,如果返回值 <= 0 表示客户端关闭或异常断开,需清除 fd。

    • 否则,就正常处理客户端发送的数据。

通过循环处理所有 events[i],服务器可同时服务多个客户端,无需为每个连接分配线程。

五、完整代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>#include <errno.h>
#include <fcntl.h>#include <sys/epoll.h>#define BUFFER_LENGTH       1024      // 接收缓冲区大小
#define EPOLL_SIZE          1024      // epoll 同时监听的最大事件数// 线程函数(旧线程模型中使用)
void *client_routine(void *arg){int clientfd = *(int *)arg;       // 客户端 socket 描述符while (1){char buffer[BUFFER_LENGTH] = {0};                      // 接收缓冲区清零int len = recv(clientfd, buffer, BUFFER_LENGTH, 0);    // 接收数据if(len < 0){                                           // 接收出错close(clientfd);                                   // 关闭连接break;} else if(len == 0){                                   // 客户端关闭连接close(clientfd);                                   // 关闭 socketbreak;} else {printf("Recv: %s, %d byte(s)\n", buffer, len);     // 正常接收到数据}}
}// ./tcp_server 8888
int main(int argc,char *argv[]){if (argc < 2){                      // 参数不足printf("Param Error\n");return -1;}int port = atoi(argv[1]);           // 将字符串端口号转换为整数int sockfd = socket(AF_INET, SOCK_STREAM, 0);  // 创建 TCP socketstruct sockaddr_in addr;memset(&addr, 0, sizeof(struct sockaddr_in));  // 地址结构清零addr.sin_family = AF_INET;                     // 使用 IPv4 协议addr.sin_port = htons(port);                   // 设置端口(转换为网络字节序)addr.sin_addr.s_addr = INADDR_ANY;             // 接收任意 IP 地址连接if(bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0){perror("bind");                 // 绑定地址失败return 2;}if(listen(sockfd, 5) < 0){          // 启动监听,最多允许5个等待连接perror("listen");return 3;}#if 0// ================= 旧的一请求一线程模型 =================while (1){struct sockaddr_in client_addr;memset(&client_addr, 0, sizeof(struct sockaddr_in));socklen_t client_len = sizeof(client_addr);int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len); // 接受连接pthread_t thread_id;pthread_create(&thread_id, NULL, client_routine, &clientfd); // 为每个连接开一个线程}
#else// ================= epoll 多路复用模型 =================int epfd = epoll_create(1);                          // 创建 epoll 实例struct epoll_event events[EPOLL_SIZE] = {0};         // 事件数组用于存储就绪事件struct epoll_event ev;ev.events = EPOLLIN;                                 // 设置为输入事件(可读)ev.data.fd = sockfd;                                 // 监听主 socketepoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);         // 将监听 socket 添加到 epoll 监听列表中while(1){int nready = epoll_wait(epfd, events, EPOLL_SIZE, -1); // 等待就绪事件,阻塞直到事件发生if(nready == -1) continue;                              // 错误继续下一轮for(int i = 0; i < nready; i++){if(events[i].data.fd == sockfd){   // 如果是监听 socket,有新连接struct sockaddr_in client_addr;memset(&client_addr, 0, sizeof(struct sockaddr_in));socklen_t client_len = sizeof(client_addr);int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len); // 接受连接ev.events = EPOLLIN | EPOLLET;     // 设置为边沿触发 + 可读事件ev.data.fd = clientfd;epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev); // 新连接加入 epoll 监听} else {int clientfd = events[i].data.fd;   // 就绪的客户端 fdchar buffer[BUFFER_LENGTH] = {0};int len = recv(clientfd, buffer, BUFFER_LENGTH, 0); // 接收数据if(len < 0){                         // 读取失败,关闭连接close(clientfd);ev.events = EPOLLIN;ev.data.fd = clientfd;epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev); // 从 epoll 删除} else if(len == 0){                 // 客户端断开close(clientfd);ev.events = EPOLLIN;ev.data.fd = clientfd;epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev); // 删除监听} else {printf("Recv: %s, %d byte(s)\n", buffer, len); // 输出收到的数据}}}}
#endifreturn 0;
}

https://github.com/0voice

http://www.dtcms.com/a/554761.html

相关文章:

  • 有什么网站可以做毕业影像页面设计源代码
  • 金泽通 打造数字金融与商业融合新模式
  • 【算法专题训练】29、树的深度优先遍历
  • Rust + WebAssembly 实现多人在线共享白板:从设计到性能验证
  • 电脑什么网站可以做长图攻略阳光家园广州网站
  • 新网站建设平台上海做网站运维的公司
  • javan
  • 在VSCode+Guider基础上 运行Button圆角demo
  • 【更新至 91 个】分子动力学模拟 + 数据处理程序
  • LIBTORCH 再配置总结
  • element-ui源码阅读-样式
  • 重生归来,我要成功 Python 高手--day31 线性回归
  • 网站开发python和c 哪个好住房和城乡建设部科技发展促进中心网站
  • 黑彩网站建设立即优化在哪里
  • 怎么在网上建网站啊东莞网站优化方案
  • 图片做网站连接在线切图网站
  • 模拟 1576. 替换所有的问号
  • 通辽网站开发0475seo做网站卖赚钱吗
  • 品牌营销网站建设流程一学一做短视频网站
  • 养殖网站 模板谷歌搜索引擎seo
  • 智能课堂课程系统源码 – 多端自适应_支持讲师课程
  • 杰理芯片SDK开发-开发环境搭建Code::Blocks
  • redis实战day2(秒杀)
  • 网站建设企划书网站配置系统
  • 深圳做网站优化报价网站增加导航栏
  • STM32H743 cubemx配置 LL库 ADC3 调试笔记
  • 江苏中益建设官方网站工信部网站备案审核
  • 门户网站前期网络采集商家信息免费发布做宣传的网站
  • svg图片做网站背景网站报价单模板
  • 济南 制作网站 公司吗室内装修设计书籍