【转】 高并发的epoll+线程池,业务在线程池内

epoll加线程池 #include<unistd.h> #include <cstdio> #include<sys/socket.h> #include<sys/epoll.h> #include<arpa/inet.h> #include<netinet/in.h> #include<fcntl.h> #include<pthread.h> #include<stdlib.h> #include<memory 阅读详情

原文地址:http://blog.chinaunix.net/uid-311680-id-2439722.html点击打开链接


epoll是linux下高并发服务器的完美方案,因为是基于事件触发的,所以比select快的不只是一个数量级。
单线程epoll,触发量可达到15000,但是加上业务后,因为大多数业务都与数据库打交道,所以就会存在阻塞的情况,这个时候就必须用多线程来提速。
 
业务在线程池内,这里要加锁才行。测试结果2300个/s
 
测试工具:stressmark
因为加了适用与ab的代码,所以也可以适用ab进行压力测试。
char buf[1000] = {0};
sprintf(buf,"HTTP/1.0 200 OK\r\nContent-type: text/plain\r\n\r\n%s","Hello world!\n");
send(socketfd,buf, strlen(buf),0);
 
 

#include <iostream>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>

#include <errno.h>
 
#define MAXLINE 10
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 8006
#define INFTIM 1000
 
//线程池任务队列结构体

struct task{
  int fd; //需要读写的文件描述符

  struct task *next; //下一个任务

};
 
//用于读写两个的两个方面传递参数

struct user_data{
  int fd;
  unsigned int n_size;
  char line[MAXLINE];
};
 
//线程的任务函数

void * readtask(void *args);
void * writetask(void *args);
 
 
//声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件

struct epoll_event ev,events[20];
int epfd;
pthread_mutex_t mutex;
pthread_cond_t cond1;
struct task *readhead=NULL,*readtail=NULL,*writehead=NULL;
 
void setnonblocking(int sock)
{
     int opts;
     opts=fcntl(sock,F_GETFL);
     if(opts<0)
     {
          perror("fcntl(sock,GETFL)");
          exit(1);
     }
    opts = opts|O_NONBLOCK;
     if(fcntl(sock,F_SETFL,opts)<0)
     {
          perror("fcntl(sock,SETFL,opts)");
          exit(1);
     } 
}
 
int main()
{
     int i, maxi, listenfd, connfd, sockfd,nfds;
     pthread_t tid1,tid2;
    
     struct task *new_task=NULL;
     struct user_data *rdata=NULL;
     socklen_t clilen;
    
     pthread_mutex_init(&mutex,NULL);
     pthread_cond_init(&cond1,NULL);
     //初始化用于读线程池的线程

     pthread_create(&tid1,NULL,readtask,NULL);
     pthread_create(&tid2,NULL,readtask,NULL);
    
     //生成用于处理accept的epoll专用的文件描述符 

     epfd=epoll_create(256);
 
     struct sockaddr_in clientaddr;
     struct sockaddr_in serveraddr;
     listenfd = socket(AF_INET, SOCK_STREAM, 0);
     //把socket设置为非阻塞方式

     setnonblocking(listenfd);
     //设置与要处理的事件相关的文件描述符

     ev.data.fd=listenfd;
     //设置要处理的事件类型

     ev.events=EPOLLIN|EPOLLET;
     //注册epoll事件

     epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
    
     bzero(&serveraddr, sizeof(serveraddr)); 
     serveraddr.sin_family = AF_INET; 
     serveraddr.sin_port=htons(SERV_PORT);
     serveraddr.sin_addr.s_addr = INADDR_ANY;
     bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));
     listen(listenfd, LISTENQ);
    
     maxi = 0;
     for ( ; ; ) {
          //等待epoll事件的发生

          nfds=epoll_wait(epfd,events,20,500);
          //处理所发生的所有事件 

        for(i=0;i<nfds;++i)
        {
               if(events[i].data.fd==listenfd)
               {
                   
                    connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);
                    if(connfd<0){
                      perror("connfd<0");
                      exit(1);
                   }
                    setnonblocking(connfd);
                   
                    char *str = inet_ntoa(clientaddr.sin_addr);
                    //std::cout<<"connec_ from >>"<<str<<std::endl;

                    //设置用于读操作的文件描述符

                    ev.data.fd=connfd;
                    //设置用于注测的读操作事件

                 ev.events=EPOLLIN|EPOLLET;
                    //注册ev

                 epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);
               }
            else if(events[i].events&EPOLLIN)
            {
                    //printf("reading!/n"); 

                    if ( (sockfd = events[i].data.fd) < 0) continue;
                    new_task=new task();
                    new_task->fd=sockfd;
                    new_task->next=NULL;
                    //添加新的读任务

                    pthread_mutex_lock(&mutex);
                    if(readhead==NULL)
                    {
                      readhead=new_task;
                      readtail=new_task;
                    } 
                    else
                    { 
                     readtail->next=new_task;
                      readtail=new_task;
                    } 
                   //唤醒所有等待cond1条件的线程

                    pthread_cond_broadcast(&cond1);
                    pthread_mutex_unlock(&mutex); 
              }
               else if(events[i].events&EPOLLOUT)
               { 
                 /*
              rdata=(struct user_data *)events[i].data.ptr;
                 sockfd = rdata->fd;
                 write(sockfd, rdata->line, rdata->n_size);
                 delete rdata;
                 //设置用于读操作的文件描述符
                 ev.data.fd=sockfd;
                 //设置用于注测的读操作事件
               ev.events=EPOLLIN|EPOLLET;
                 //修改sockfd上要处理的事件为EPOLIN
               epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
             */

               }
                             
          }
         
     }
}

static int count111 = 0;
static time_t oldtime = 0, nowtime = 0;
void * readtask(void *args)
{
   
   int fd=-1;
   unsigned int n;
   //用于把读出来的数据传递出去

   struct user_data *data = NULL;
   while(1){
        
        pthread_mutex_lock(&mutex);
        //等待到任务队列不为空

        while(readhead==NULL)
             pthread_cond_wait(&cond1,&mutex);
        
        fd=readhead->fd;
        //从任务队列取出一个读任务

        struct task *tmp=readhead;
        readhead = readhead->next;
        delete tmp;
        pthread_mutex_unlock(&mutex);
        data = new user_data();
        data->fd=fd;
        

        char recvBuf[1024] = {0}; 
        int ret = 999;
        int rs = 1;

        while(rs)
        {
            ret = recv(fd,recvBuf,1024,0);// 接受客户端消息

            if(ret < 0)
            {
                //由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可//读在这里就当作是该次事件已处理过。

                if(errno == EAGAIN)
                {
                    printf("EAGAIN\n");
                    break;
                }
                else{
                    printf("recv error!\n");
        
                    close(fd);
                    break;
                }
            }
            else if(ret == 0)
            {
                // 这里表示对端的socket已正常关闭. 

                rs = 0;
            }
            if(ret == sizeof(recvBuf))
                rs = 1; // 需要再次读取

            else
                rs = 0;
        }
        if(ret>0){

        //-------------------------------------------------------------------------------


            data->n_size=n;


            count111 ++;

            struct tm *today;
            time_t ltime;
            time( &nowtime );

            if(nowtime != oldtime){
                printf("%d\n", count111);
                oldtime = nowtime;
                count111 = 0;
            }

            char buf[1000] = {0};
            sprintf(buf,"HTTP/1.0 200 OK\r\nContent-type: text/plain\r\n\r\n%s","Hello world!\n");
            send(fd,buf,strlen(buf),0);
            close(fd);


       }
   }
}


(UE5 5.2)HISM Mobile DrawInstance在渲染层的实现浅分析 在 (UE4 4.27) UHierarchicalInstancedStaticMesh(HISM)原理分析 这篇博客大致介绍HISM组件从游戏线程到渲染线程的重建KD-Tree和剔除并提交DrawCall逻辑,但是没有分析渲染层的大致数据结构和实现. 可以看出FHierarchicalStaticMeshSceneProxy 实际存储Instance数组数据来自于FInstancedStaticMeshSceneProxy FHierarchicalStaticMeshSceneProxy只是以FClu 阅读详情

相关推荐

别只刷题了!我用834分经验告诉你,华为HCIP大数据考试(H13-723)这样准备更高效

本文分享了华为HCIP大数据认证(H13-723)834分通关的高效备考经验。通过分析考试动态、题库验证技巧和章节优先级策略,帮助考生超越单纯刷题,系统化掌握核心知识点。特别强调实时流处理和离线批处理等重点章节,提供黄金90分钟临场发挥策略,助力考生一次性通过考试。

weixin_38168786的博客 459

高并发的epoll+线程池,业务在线程池内

epoll是linux下高并发服务器的完美方案,因为是基于事件触发的,所以比select快的不只是一个数量级。 单线程epoll,触发量可达到15000,但是加上业务后,因为大多数业务都与数据库打交道,所以就会存在阻塞的情况,这个时候就必须用多线程来提速。   业务在线程池内,这里要加锁才行。测试结果2300个/s   测试工具:stressmark 因为加了适用与ab的代码,所以

guoduhua的专栏 1007

机器人手眼标定快速精度验证方法

机器人手眼标定快速精度验证方法

laoli_的博客 1万+

Linux——网络编程(epoll、epoll反应堆、心跳、线程池)

1,epoll函数 epoll是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率,因为它会复用文件描述符集合来传递结果而不用迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的...

一个小孩 4496

stm32f407等芯片(HAL库)时钟频率修改(乱码)

其他片子及库文件未知、未验证,只是在使用stm32f407ZG配置串口打印的时候,出现乱码,就从以下几方面定位问题: 1. 确认串口GPIO相关配置; 2. 确认波特率等参数; 3. 确认时钟频率; 结果这次使用YH的串口打印程序在ZDYZ的开发板调试项目工程(有点另类...),做功能验证,就出现了以上问题,出于好奇开始调试,最终发现是时钟频率问题。 看到下图这个配置,因为ZDYZ开发板使用的是8MHz外部晶振(好像默认的是25MHz,如图2),所以他这里PLL_M是25,不是推荐值,感...

bulefire2009的博客 5516

DC竞赛 国能日新功率预测题 rank21 解决方案(适合新手)

DataCastle国能日新光伏功率预测 数据异常处 本题在测试集中提供了时间、辐照度、风速、风向、温度、压强、湿度、实发辐照度8个特征,以及标签**实际功率**。 而在训练集中只有前七个特征,无实发辐照度。 策略 在观察了数据之后,我们确定实发辐照度是一个强力特征,于是我们采取了stacking的策略: 1. 第一次训练以实发辐照度为标签,预测 测试集的实发辐照度 2....

yyhhlancelot的博客 7294

Linux- C语言服务器简单模型(epoll+线程池)

使用epoll的缘由: 当多个任务到来时需要对其进行及时响应,并将任务下发给特定的处理线程,完成对应的任务。如果只用单线程进行listen轮询监听的话,那效率上实在是太低。而我们借助epoll的话就会很完美的解决这个问题(epoll详细太过复杂,而且这里主要目的是使用epoll,所以就不再赘述)。 使用线程池的缘由: 当实现高并发服务器时,当然需要实现多线程并发工作来处理多个客户端的连接。那么方法有如下两种 每当客户端发送一个请求,服务器创建一个线程来处理客户端的连接请求。 先预先创建若干个线程,并让.

四年rain的博客 2619

7、布尔网络的基础定义

本文介绍了布尔网络的基础定义及其在系统生物学中的应用。布尔网络是一种描述复杂系统动态行为的数学模型,由布尔变量和布尔函数组成,能够模拟生物系统中基因调控、信号传导和细胞代谢等过程。文章详细阐述了布尔网络的基本结构、动力学特征(如状态转移图和吸引子),以及其在生物建模中的重要价值,并探讨了优化和简化技术(如Backward Boolean Equivalence)如何提升其计算效率。

yhn45678901的博客 263

基于线程池+Epoll(IO多路复用)的高并发服务器(附C++源码)

简介:这是一个基于线程池+Epoll的IO多路复用、非阻塞IO技术,的高并发服务器框架。称它为框架是因为服务器功能非常简单且无意义,使用时应该把这个功能替换掉。但它可以直接拿来使用,很方便,所以也算半个项目。服务器的默认功能:客户端输入什么内容,服务器就返回什么内容。后续想实现什么功能,修改功能函数就可以。语言标准:C++11。

iuu77的博客 6241

UG NX二次开发(C++)-UIStyler-指定平面的对象和参数获取

在采用NXOpen C++进行二次开发时,采用Menu/UIStyler是一种很常见的方式,这样可以制作精美的界面,而且常用的块对象也集成了快速编程的代码,我们可以快速的利用这些块来定制我们需要的界面。但是,对于很多初学者可能对选择对象的获取不是很熟悉,我们本文以选择“指定平面”来讲一下如何获取选择的对象和对象的参数。另外,由于我们的UG NX二次开发学习讨论群QQ一群已满,有希望参与学习的有志之士加入我们的QQ二群:683566590。

GimiGimmy 1091

AIGC游戏本地化:用AI实现多语言自动翻译

游戏本地化是游戏全球化战略的关键环节,传统人工翻译方式成本高、周期长。本文旨在探讨如何利用AIGC技术实现高效、准确、低成本的游戏多语言自动翻译解决方案。我们将覆盖从文本翻译到语音合成的完整本地化流程,重点关注AI技术在游戏特定语境下的应用优化。文章首先介绍游戏本地化的核心挑战和AI解决方案,然后深入讲解关键技术原理,接着通过实战项目演示具体实现,最后讨论应用场景和未来趋势。AIGC:人工智能生成内容,指利用AI技术自动生成文本、图像、音频等内容本地化(Localization)

AI 领航者的博客 1339

高并发的epoll+线程池,epoll在线程池内

转载自:http://blog.chinaunix.net/uid-311680-id-2439723.html epoll是linux下高并发服务器的完美方案,因为是基于事件触发的,所以比select快的不只是一个数量级。 单线程epoll,触发量可达到15000,但是加上业务后,因为大多数业务都与数据库打交道,所以就会存在阻塞的情况,这个时候就必须用多线程来提速。   ep

LH806732的专栏 1万+

基于simulink 的不间断电源ups的项目实例

UPS系统的核心组件包括整流器、逆变器、电池管理系统和控制系统。- **Three-Phase Controlled Rectifier**:设置触发角为0度,用于控制整流器的输出电压。- **Three-Phase Inverter**:设置逆变器的输出频率为60Hz,用于将直流电转换为交流电。- **Control System**:编写MATLAB函数,用于监测市电状态并控制各模块的工作模式。- **Step**:设置阶跃时间,例如0.05秒,阶跃前后的值分别为0和1,用于模拟市电中断。

xiaoheshang_123的博客 711

那些业务会用到线程池_高并发的epoll+线程池,业务在线程池内

#include #include #include #include #include #include #include #include #include #include #define MAXLINE 10#define OPEN_MAX 100#define LISTENQ 20#define SERV_PORT 8006#define INFTIM 1000//线程池任务队列结构体s...

weixin_33502035的博客 132

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

高并发的epoll+线程池,epoll在线程池内-ehyyngp-ChinaUnix博客

高并发的epoll+线程池,epoll在线程池内-ehyyngp-ChinaUnix博客 高并发的epoll+线程池,epoll在线程池内-ehyyngp-ChinaUnix博客高并发的epoll+线程池,epoll在线程池内 2011-08-29 21:53:38...

215

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

python epoll 并发_高并发的epoll+线程池,epoll在线程池内

#include #include #include #include #include #include #include #include #include #include #include #include #include //stl head#include //包含hash_map 的头文件//#include //stl的mapusing namespace std; //std...

weixin_39540315的博客 242

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

【转】高并发的epoll+线程池,epoll在线程池内

原文地址:http://blog.chinaunix.net/uid-311680-id-2439723.html点击打开链接 epoll是linux下高并发服务器的完美方案,因为是基于事件触发的,所以比select快的不只是一个数量级。 单线程epoll,触发量可达到15000,但是加上业务后,因为大多数业务都与数据库打交道,所以就会存在阻塞的情况,这个时候就必须用多线程来提速。

labrary的专栏 776
上一篇: 【转】高并发的epoll+线程池,epoll在线程池内
下一篇: 高性能网络编程3----TCP消息的接收
labrary
博客等级 码龄15年 8粉丝 2原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值