1. 程式人生 > >select 和 epoll的區別

select 和 epoll的區別

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上發生事件時,會呼叫對應的回撥函式。這樣,在連線很多,少數事件發生的情況下,依舊會效率很高。當然,如果連線很多,大部分連線都有事件時,兩者的效率應該是差不多的。