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

epoll+线程池 Linux + C + Epoll实现高并发服务器,运用线程池技术。 立即下载
epoll是linux下高并发服务器的完美方案,因为是基于事件触发的,所以比select快的不只是一个数量级。
单线程epoll,触发量可达到15000,但是加上业务后,因为大多数业务都与数据库打交道,所以就会存在阻塞的情况,这个时候就必须用多线程来提速。
 
epoll在线程池内,测试结果2000个/s
增加了网络断线后的无效socket检测。
 
测试工具: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 <stdio.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>


//stl head

#include <ext/hash_map> //包含hash_map 的头文件

//#include 
//stl的map

using namespace std; //std 命名空间

using namespace __gnu_cxx; //而hash_map是在__gnu_cxx的命名空间里的



int init_thread_pool(int threadNum);
void *epoll_loop(void* para);
void *check_connect_timeout(void* para);


struct sockStruct
{
    time_t time;

    unsigned int* recvBuf;
};

//hash-map

//hash_map        sock_map;

hash_map<int, sockStruct>        sock_map;

 
#define MAXRECVBUF 4096
#define MAXBUF MAXRECVBUF+10 

int fd_Setnonblocking(int fd)
{
    int op;
 
    op=fcntl(fd,F_GETFL,0);
    fcntl(fd,F_SETFL,op|O_NONBLOCK);
 
    return op;
}
 
void on_sigint(int signal)
{
    exit(0);
}
 
/* 
handle_message - 处理每个 socket 上的消息收发 
*/
 
int handle_message(int new_fd) 
{ 
    char buf[MAXBUF + 1]; 
    char sendbuf[MAXBUF+1]; 
    int len; 
    /* 开始处理每个新连接上的数据收发 */ 
    bzero(buf, MAXBUF + 1); 
    /* 接收客户端的消息 */ 
    //len = recv(new_fd, buf, MAXBUF, 0);



    int nRecvBuf = MAXRECVBUF; //设置为32K 

    setsockopt(new_fd, SOL_SOCKET, SO_RCVBUF, ( const char* )&nRecvBuf, sizeof(int));
    len=recv(new_fd,&buf, MAXBUF,0);

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

    //这块为了使用ab测试

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

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


    if (len > 0){ 

        //printf ("%d接收消息成功:'%s',共%d个字节的数据\n", new_fd, buf, len); 


        //hash-map

        
        hash_map<int, sockStruct>::iterator it_find;
        it_find = sock_map.find(new_fd);
        if(it_find == sock_map.end()){
            //新的网络连接,申请新的接收缓冲区,并放入map中

            //printf("new socket %d\n", new_fd);


            sockStruct newSockStruct;
            newSockStruct.time = time((time_t*)0);
            newSockStruct.recvBuf = (unsigned int*)malloc(1000);
            memset(newSockStruct.recvBuf, 0, 1000);
            strcat((char*)newSockStruct.recvBuf, buf);
            sock_map.insert(pair<int,sockStruct>(new_fd, newSockStruct));
        }else{
            //网络连接已经存在,找到对应的数据缓冲区,将接收到的数据拼接到数据缓冲区中

            //printf("socket %d exist!\n", it_find->first);


            (it_find->second).time = time((time_t*)0);                //时间更改

            char* bufSockMap = (char*)(it_find->second).recvBuf;    //数据存储


            strcat(bufSockMap, buf);
            //printf("bufSockMap:%s\n", bufSockMap);

        }


    } 
    else { 
        if (len < 0) 
            printf ("消息接收失败!错误代码是%d,错误信息是'%s'\n", 
            errno, strerror(errno)); 
        else {
            //将socket从map中移除

            /*
            hash_map::iterator it_find;
            it_find = sock_map.find(new_fd);
            sock_map.erase(it_find);
            */

            printf("client %d quit!\n",new_fd); 
        }
        //close(new_fd); 

        return -1; 
    } 
    /* 处理每个新连接上的数据收发结束 */ 

    //关闭socket的时候,要释放接收缓冲区。

    hash_map<int, sockStruct>::iterator it_find;
    it_find = sock_map.find(new_fd);
    free((it_find->second).recvBuf);
    sock_map.erase(it_find);

    close(new_fd);
    return len; 
} 


    int listenfd;
    int sock_op=1;
    struct sockaddr_in address;
    struct epoll_event event;
    struct epoll_event events[1024];
    int epfd;
    int n;
    int i;
    char buf[512];
    int off;
    int result;
    char *p;

int main(int argc,char* argv[])
{

    init_thread_pool(1);

    signal(SIGPIPE,SIG_IGN);
    signal(SIGCHLD,SIG_IGN);
    signal(SIGINT,&on_sigint);
    listenfd=socket(AF_INET,SOCK_STREAM,0);
    setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&sock_op,sizeof(sock_op));
 
    memset(&address,0,sizeof(address));
    address.sin_addr.s_addr=htonl(INADDR_ANY);
    address.sin_port=htons(8006);
    bind(listenfd,(struct sockaddr*)&address,sizeof(address));
    listen(listenfd,1024);
    fd_Setnonblocking(listenfd);
 
    epfd=epoll_create(65535);
    memset(&event,0,sizeof(event));
    event.data.fd=listenfd;
    event.events=EPOLLIN|EPOLLET;
    epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&event);

    while(1){
        sleep(1000);
    }
    return 0;
}

/*************************************************
* Function: * init_thread_pool
* Description: * 初始化线程
* Input: * threadNum:用于处理epoll的线程数
* Output: * 
* Others: * 此函数为静态static函数,
*************************************************/

int init_thread_pool(int threadNum)
{
    int i,ret;

    pthread_t threadId;

    //初始化epoll线程池

    for ( i = 0; i < threadNum; i++)
    {

        ret = pthread_create(&threadId, 0, epoll_loop, (void *)0);
        if (ret != 0)
        {
            printf("pthread create failed!\n");
            return(-1);
        }
    }

    ret = pthread_create(&threadId, 0, check_connect_timeout, (void *)0);

    return(0);
}
/*************************************************
* Function: * epoll_loop
* Description: * epoll检测循环
* Input: * 
* Output: * 
* Others: * 
*************************************************/

static int count111 = 0;
static time_t oldtime = 0, nowtime = 0;
void *epoll_loop(void* para)
{
        while(1)
    {
        n=epoll_wait(epfd,events,4096,-1);
        //printf("n = %d\n", n);

        if(n>0)
        {
            for(i=0;i<n;++i)
            {
                if(events[i].data.fd==listenfd)
                {
                    while(1)
                    {
                        event.data.fd=accept(listenfd,NULL,NULL);
                        if(event.data.fd>0)
                        {
                            fd_Setnonblocking(event.data.fd);
                            event.events=EPOLLIN|EPOLLET;
                            epoll_ctl(epfd,EPOLL_CTL_ADD,event.data.fd,&event);
                        }
                        else
                        {
                            if(errno==EAGAIN)
                            break;
                        }
                    }
                }
                else
                {
                    if(events[i].events&EPOLLIN)
                    {
                        //handle_message(events[i].data.fd);


                        char recvBuf[1024] = {0}; 

                        int ret = 999;

                        int rs = 1;


                        while(rs)
                        {
                            ret = recv(events[n].data.fd,recvBuf,1024,0);// 接受客户端消息

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

                                if(errno == EAGAIN)
                                {
                                    printf("EAGAIN\n");
                                    break;
                                }
                                else{
                                    printf("recv error!\n");
                                    epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, &event);
                                    close(events[i].data.fd);
                                    break;
                                }
                            }
                            else if(ret == 0)
                            {
                                // 这里表示对端的socket已正常关闭. 

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

                            else
                                rs = 0;
                        }




                        if(ret>0){

                            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(events[i].data.fd,buf,strlen(buf),0);


                            //    CGelsServer Gelsserver;

                            //    Gelsserver.handle_message(events[i].data.fd);

                        }


                        epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, &event);
                        close(events[i].data.fd);

                    }
                    else if(events[i].events&EPOLLOUT)
                    {
                        sprintf(buf,"HTTP/1.0 200 OK\r\nContent-type: text/plain\r\n\r\n%s","Hello world!\n");
                        send(events[i].data.fd,buf,strlen(buf),0);
                        /*
                        if(p!=NULL)
                        {
                            free(p);
                            p=NULL;
                        }
                        */

                        close(events[i].data.fd);
                    }
                    else
                    {
                        close(events[i].data.fd);
                    }
                }
            }
        }
    }

}
/*************************************************
* Function: * check_connect_timeout
* Description: * 检测长时间没反应的网络连接,并关闭删除
* Input: * 
* Output: * 
* Others: * 
*************************************************/

void *check_connect_timeout(void* para)
{
    hash_map<int, sockStruct>::iterator it_find;
    for(it_find = sock_map.begin(); it_find!=sock_map.end(); ++it_find){
        if( time((time_t*)0) - (it_find->second).time > 120){                //时间更改


            free((it_find->second).recvBuf);
            sock_map.erase(it_find);

            close(it_find->first);
        }
    }

}

新手必看:如何用PhaGCN2和vConTACT2搞定宏病毒组注释(附避坑指南) 本文为宏病毒组研究新手提供了使用PhaGCN2和vConTACT2进行病毒注释的完整实战指南。内容涵盖从Conda环境配置、软件安装、参数解析到结果解读的全流程,并重点分享了整合双工具进行交叉验证的策略与常见报错解决方案,旨在帮助研究者高效、准确地完成病毒分类注释工作。 阅读详情

相关推荐

集成电路设计笔记(七)UVLO设计

1. 什么是UVLO 欠压锁定(Undervoltage-Lockout)简称UVLO,是电子设备中在电源电压低于正常工程准位时,切断电源的电路。在嵌入式系统中常会用UVLO监控电池电压,若电压低于一定值,会直接切断电源,保护嵌入式系统的电路。 许多电子设备中都有UVLO的功能,例如在镇流器中就有UVLO电路,若电压过低时直接切断电源。 UVLO就是低电压锁定; 低压关断. 欠压关断模式是当供电电压低于IC的开启门限电压时的一种保护模式。欠压关断模式可保证IC在供电电压不足时不致于被损坏。一个低电压锁定(

ccbirds 2万+

来说说epoll+线程池

最近在作学习epoll,也看了很多的资料,关于epoll的原理就不多说了,很简单,需要注意的是,如果仅仅的采用epoll来处理网络服务器的话,感觉性能不会提高太大,毕竟io的处理相对于epoll或者poll的检测来说,时间消耗是比较多的。这个话说得可能比较的绕口,简单说就是你每次的epoll_wait所花费的时间,相对于你得到事件后所作的read,write==花费的时间要少狠多,至少我感觉是这样...

关中刀客的博客 565

FoundationPose实战:从零部署到Demo运行全记录

本文详细记录了FoundationPose从零部署到Demo运行的全过程,包括Ubuntu环境配置、项目部署、依赖安装及常见问题解决方案。特别针对复现过程中的关键步骤如CUDA版本选择、Eigen3安装等提供了实用技巧,帮助开发者高效完成FoundationPose的部署与调试。

weixin_27102543的博客 269

常用服务器架构实现

常用服务器架构实现(多线程/多进程 & select模型 & 完成端口/EPOLL)   RT,常用的服务器架构原理如上面所示三种,虽然出现的时间不同,但即使到今天也仍然是各有侧重的,没有绝对的优劣之分 1)多线程/多进程 适用于多个连接间共享数据较少的情况,对于每一个客户端连接都会fork一个子进程,APACH是典型的代表。源码如下: struct stClien

Jchn lau 1382

centos7部署mysql8.0.35,主从复制,主主集群

centos7 linux部署mysql,主从复制,主主模式

zaixiaqin的博客 1990

手把手教你用Cadence Virtuoso仿真一个5GHz CMOS分频器:从原理图到后仿,避开那些教科书上没写的坑

本文详细介绍了在Cadence Virtuoso环境中设计5GHz CMOS分频器的完整流程,从原理图设计到后仿真优化,特别关注实际工程中容易被忽视的关键问题。内容涵盖分频器核心指标解析、锁存器拓扑选择、接口设计匹配以及后仿真优化策略,为射频集成电路设计提供实用避坑指南。

weixin_26934905的博客 262

Windows下完成端口移植Linux下的epoll

Windows下完成端口移植Linux下的epoll 先来说说Windows下的完成端口。完成端口号称是Windows下面最复杂的异步IO操作。但是如果你想开发出具有高性能的、支持大量连接的网络服务程序的话,就必须将它拿下。这里假设你已经对完成端口有一定的了解了。        下面引用一下幽默讲解Windows支持的五种Socket I/O模型的例子来通俗的说一下完成端口究

quasiceo 959

从生成到检测:全面解析Deepfake技术的演进与对抗策略

本文全面解析了Deepfake技术的演进与对抗策略,从GAN生成技术到先进的检测手段,探讨了其在娱乐与安全领域的双重影响。文章详细介绍了Deepfake的核心原理、技术迭代关键节点以及最新的检测方法,揭示了AI生成与识别的激烈博弈。同时,展望了量子计算和生物特征认证在未来攻防战中的潜在应用。

jenkins8butler的博客 255

【Epoll】epoll+线程池实现高并发(C++)--编辑中

在epoll编程中,有三个非常重要的函数: 1. int epoll_create(int size):创建epoll 句柄, 入参是表示监听的数目是多大。 2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event): 事件注册函数, @param1:epoll句柄,epoli_create()的返回值, @param2: 表示注册的行为, 有ADD事件 、MOD事件、DEL事件,...

我的笔记本 2940

CTP高频Tick数据:五档期货Level2深度解析20241224

高频Tick五档期货Level2数据,作为一种先进的金融市场分析工具,以其一秒四次的高频更新,为投资者揭示了市场的微观结构。本文将深入探讨这一数据如何帮助投资者洞察市场动态,优化交易策略,实现投资收益的最大化。

level2Tick的博客 1218

drm 之modes

#define _GNU_SOURCE #include <errno.h> #include <fcntl.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <time.h&...

u012794472的专栏 3718

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

我们知道,服务器并发模型通常可分为单线程和多线程模型,这里的线程通常是指“I/O线程”,即负责I/O操作,协调分配任务的“管理线程”,而实际的请求和任务通常交由所谓“工作者线程”处理。通常多线程模型下,每个线程既是I/O线程又是工作者线程。所以这里讨论的是,单I/O线程+多工作者线程的模型,这也是最常用的一种服务器并发模型。我所在的项目中的server代码中,这种模型随处可见。它还有个名字,叫“半...

yangzai187的专栏 262

【图像去噪】基于梯度为0法实现图像去噪附matlab代码

近几年,徐立提出的 L0 梯度最小化模型在图像平滑领域得到了广泛的应用和发展[11]. 和以往的局部滤波模型不同的是该模型可以全局的估计图像的像素值,因此,L0 梯度最小化模型在处理图像的同时能够很好的保护图像的边缘.​。

qq_59747472的博客 185

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

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

215

Devexpress16.2.6破解工具

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

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

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

上一篇: 高并发的epoll+线程池,业务在线程池内
下一篇: epoll经验
Watson2016
博客等级 码龄11年 342粉丝 88原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值