系统编程之高并发服务器(epoll和select)

本文详细介绍了Linux系统编程中的epoll和select机制。epoll在处理高并发服务器方面具有显著优势,例如避免了文件描述符复制开销,采用事件通知方式,并支持边缘触发和水平触发模式。文章通过epoll_create(), epoll_ctl(), epoll_wait()等函数的讲解,阐述了epoll的基本操作流程。相比之下,select虽然简单,但在大量文件描述符时效率较低,但其select()函数和fd_set系列函数的使用方法也在文中进行了说明。" 115052472,9938209,PHP与Xdebug配置详解,"['PHP', '配置', '调试工具', '性能优化', '开发环境']
摘要由CSDN通过智能技术生成

1.epoll原理

epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了这些文件描述符在系统调用时复制的开销。

另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。

优点:
1.支持一个进程打开大数目的socket描述符(FD)
2.IO效率不随FD数目增加而线性下降
3.使用mmap加速内核与用户空间的消息传递
4.内核微调

2.epoll基本操作

  1. 在监听之后用epoll_create( max)函数创建epoll,返回值为标识符epfd;其中max为epoll所支持的最大柄数;在用完后记得用close()来关闭这个句柄

  2. 创建struct epoll_event 类型的ev和events[MAX_EVENTS];
    ev.events = EPOLLIN(可读);ev.data.fd = sockfd;

  3. 在循环里面,用epoll_wait(int epfd, epoll_event events, int maxevents, int timeout)来查询所有网络接口,看哪个可读/可写,
    events是一个epoll_events*指针,当epoll_wait函数操作成功后,epoll_events里面将存储所有的读写事件,最后一个参数是epoll_wait超时的话,参数为0马上返回,参数为-1表示一直等下去。

  4. epoll_wait之后是一个循环,遍历所有事件;

常用框架:

for (;;)
{
   
    nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
    if (nfds == -1)
    {
   
    perror("epoll_pwait");
    exit(EXIT_FAILURE);
    }
    for (n = 0; n < nfds; ++n)
    {
   
        if (events[n].data.fd == listenfd)      //有新的连接
        {
   
            connfd = accept(listenfd,(struct sockaddr *) &clientaddr, &clilen);    //accept这个连接
            if (confd == -1)
            {
   
                perror("accept");
                exit(EXIT_FAILURE);
            }
            ev.events = EPOLLIN | EPOLLET;
            ev.data.fd = connfd;
            epoll_ctl(epfd, EPOLL_CTL_ADD, connfd,&ev)  //将新fd添加到epoll监听队列中
            else if(events[i].events & EPOLLIN)    //接收到可读数据,读socket
            {
   
                    ret = recv(events[i].data.fd, buf, sizeof(buf), 0);
                    if(-1 == ret)
                    {
   
                        perror("recv");
                        exit(1);
                    }
                    else if(0 == ret)
                    {
   
                        ev.data.fd = events[i].data.fd;
                        ev.events = EPOLLIN;
                        epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, &ev);    //客户端退出, 注销事件
                         close(events[i].data.fd);
                    }
                    else
                    {
   
                        printf("收到%d客户端的消息%s\n", events[i].data.fd, buf);
                    }
            }
            else if(events[i].events & EPOLLOUT)   //接收到可写数据,写socket
            {
   
                        ....
            }
         }
    }
}

具体代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#define MAXSIZE 256
int main()
{
   
    //创建socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值