select 和 epoll的区别

来源:互联网 发布:sql%20server 编辑:程序博客网 时间:2024/05/16 15:02

select epoll的区别

select epoll都是用来监听套接字上是否有事件发生,简单来讲,select是轮询方式,而epoll是触发方式的,用回调把信息赋给event结构体。

select:轮询检查文件描述符集合,实现方法如下:

fd_set    fdRead;

//将文件描述符集合清零

FD_ZERO(&fdRead);

//在文件描述rd中增加文件描述符iSocket,可以加多个

FD_SET(iSocket,&fdRead);

//select ,设置recv超时时间,写的类似

int iRet = select(iSocket+ 1, &fdRead, NULL, NULL, &tvTimeOut);

switch(iRet)

{

       case 0:

              printf("Time out \n");

              return -1;

       case -1:

              printf("Select Error\n");

              return -2;

       default:

              if (FD_ISSET(iSocket,&fdRead))//测试iSocket是否在描述符集合中

              {

                     iRecvLen = recv(iSocket,pcRecvBuf, iBufLen, 0);

                     if (iRecvLen == -1)

                     {

                            printf("Recverror\n");

                            return -3;

                     }

                     else if(0 == iRecvLen)

                     {

                            printf("Socketclose \n");

                            return -4;

                     }

                     else

                     {

                            break;

                     }

              }

}

如果文件描述符中有多个socket,便会轮询检查。

 

epoll:epoll的使用,首先通过epoll_create创建一个epoll对象,得到一个epoll的描述符,我们需要监听哪个fd上的事件通过epoll_ctl,最后 epoll_wait会返回发生了事件的数目,具体的事件在参数events中。

#include<stdio.h>

#include<sys/socket.h>

#include<sys/types.h>

#include<unistd.h>

#include<netinet/in.h>

#include<stdlib.h>

#include<sys/ioctl.h>

#include<sys/epoll.h>

 

#define MAX_EVENTS10

#define  LISTENQ    12

 

int main()

{

       int n = 0;

       int listen_sock;

       int conn_sock;

       int nfds;

       int epollfd;

       int iRet = -1;

       socklen_t len;

       struct epoll_event ev;

       struct epoll_event events[MAX_EVENTS];

       char buf[32] = "tongzhilin";

 

       /*create listen socket */

       listen_sock = socket(AF_INET,SOCK_STREAM, 0);

       int   iSocketOpt= 1;

       setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,(void *)&iSocketOpt, sizeof(int));

 

       /*bind*/

       struct     sockaddr_instServerAddrIn;

       stServerAddrIn.sin_family = AF_INET;

       stServerAddrIn.sin_port = htons(6666);

       stServerAddrIn.sin_addr.s_addr =htonl(INADDR_ANY);

       iRet = bind(listen_sock,(structsockaddr*)&stServerAddrIn, sizeof(stServerAddrIn));

       if(iRet < 0)

       {

              printf("bind error\n");

              return -3;

       }

 

       /*listen*/

       iRet = listen(listen_sock, LISTENQ);

       if(iRet < 0)

       {

              printf("listenerror\n");

              return -3;

       }

 

       /*epoll*/

       epollfd = epoll_create(10);

       if(epollfd == -1)

       {

              perror("epoll_create");

              return -1;

       }

      

       ev.events = EPOLLIN;

       ev.data.fd = listen_sock;

 

       //EPOLL_CTL_ADD:注册;EPOLL_CTL_MOD修改;EPOLL_CTL_DEL:删除

       if(epoll_ctl(epollfd, EPOLL_CTL_ADD,listen_sock, &ev) == -1)

       {

              perror("epoll_ctl:listen_sock");

              return -1;

       }

 

       while(1)

       {

              printf("Wait..\n");

              nfds = epoll_wait(epollfd, events,MAX_EVENTS, -1);

              if(nfds == -1)

              {

                     perror("epoll_pwait");

                     return -1;

              }

 

              for (n = 0; n < nfds; ++n)

              {

                     if(events[n].data.fd ==listen_sock)

                     {

                            conn_sock =accept(listen_sock, (struct sockaddr *)&stServerAddrIn, &len);

                            if(conn_sock == -1)

                            {

                                   perror("accept");

                                   return -1;

                            }

                           

                            //非阻塞

                            int ulflag = 1;

                            ioctl(listen_sock,FIONBIO, &ulflag);

                            ev.events = EPOLLIN| EPOLLET;

                            ev.data.fd =conn_sock;

                            //EPOLL_CTL_ADD:注册;EPOLL_CTL_MOD修改;EPOLL_CTL_DEL:删除

                            if(epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1)

                            {

                                   perror("epoll_ctl:conn_sock");

                                   return -1;

                            }

                    }

                     else

                     {

                            send(events[n].data.fd,buf, sizeof(buf), 0);

                     }

               }

       }

      

       return 0;

}

总结:select如果同时建立的连接很多,但是只有少数的有事件发生,这种情况下,效率就会很低。epoll的实现中就避免了该问题,对于要监管的每个fd都会有回调函数,当该fd上发生事件时,会调用对应的回调函数。这样,在连接很多,少数事件发生的情况下,依旧会效率很高。当然,如果连接很多,大部分连接都有事件时,两者的效率应该是差不多的。

原创粉丝点击