select、poll、epoll程序实例

三个函数的基本用法如下:

select
  创建
      fd_set rset , allset;
      FD_ZERO(&allset);
      FD_SET(listenfd, &allset);
  监听
      /*只select出用于读的描述字,阻塞无timeout*/
      nready = select(maxfd+1 , &rset , NULL , NULL , NULL);
  获取
      if(FD_ISSET(listenfd,&rset))


poll:

  创建
      struct pollfd client[OPEN_MAX];
      client[0].fd = listenfd;
      client[0].events = POLLRDNORM;
      for(i=1;i<OPEN_MAX;i++)
      {
        client[i].fd = -1;
      }
      maxi = 0;
  监听
       nready = poll(client,maxi+1,INFTIM);
  获取
      sockfd = client[i].fd;
      if(client[i].revents & (POLLRDNORM|POLLERR))


epoll:

  创建
      int epfd;
      struct epoll_event ev, events[20];
      epfd = epoll_create(256);
      ev.data.fd=listenfd;
      ev.events=EPOLLIN|EPOLLET;
      epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
  监听
      nfds=epoll_wait(epfd,events,20,500);
  获取
      if (events[i].events & EPOLLIN)

IO复用,说得粗鄙一点,就是不用开多线程也能发送和接收消息。不多说,看代码:(select和poll是别人写的。引用一下,别见怪。)

select:

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/select.h>

const static int MAXLINE = 1024;
const static int SERV_PORT = 10001;

int main()
{
    int i , maxi , maxfd, listenfd , connfd , sockfd ;
    /*nready 描述字的数量*/
    int nready ,client[FD_SETSIZE];
    int n ;
    /*创建描述字集合,由于select函数会把未有事件发生的描述字清零,所以我们设置两个集合*/
    fd_set rset , allset;
    char buf[MAXLINE];
    socklen_t clilen;
    struct sockaddr_in cliaddr , servaddr;
    /*创建socket*/
    listenfd = socket(AF_INET , SOCK_STREAM , 0);
    /*定义sockaddr_in*/
    memset(&servaddr , 0 ,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(listenfd, (struct sockaddr *) & servaddr , sizeof(servaddr));
    listen(listenfd , 100);
    /*listenfd 是第一个描述字*/
    /*最大的描述字,用于select函数的第一个参数*/
    maxfd = listenfd;
    /*client的数量,用于轮询*/
    maxi = -1;
    /*init*/
    for(i=0 ;i<FD_SETSIZE ; i++)
        client[i] = -1;
    FD_ZERO(&allset);
    FD_SET(listenfd, &allset);

    for (;;)
    {
        rset = allset;
        /*只select出用于读的描述字,阻塞无timeout*/
        nready = select(maxfd+1 , &rset , NULL , NULL , NULL);
        if(FD_ISSET(listenfd,&rset))
        {
            clilen = sizeof(cliaddr);
            connfd = accept(listenfd , (struct sockaddr *) & cliaddr , &clilen);
            /*寻找第一个能放置新的描述字的位置*/
            for (i=0;i<FD_SETSIZE;i++)
            {
                if(client[i]<0)
                {
                    client[i] = connfd;
                    break;
                }
            }
            /*找不到,说明client已经满了*/
            if(i==FD_SETSIZE)
            {
                printf("Too many clients , over stack .
");
                return -1;
            }
            FD_SET(connfd,&allset);//设置fd
            /*更新相关参数*/
            if(connfd > maxfd) maxfd = connfd;
            if(i>maxi) maxi = i;
            if(nready<=1) continue;
            else nready --;
        }

        for(i=0 ; i<=maxi ; i++)
        {
            if (client[i]<0) continue;
            sockfd = client[i];
            if(FD_ISSET(sockfd,&rset))
            {
                n = read(sockfd , buf , MAXLINE);
                if (n==0)
                {
                    /*当对方关闭的时候,server关闭描述字,并将set的sockfd清空*/
                    close(sockfd);
                    FD_CLR(sockfd,&allset);
                    client[i] = -1;
                }
                else
                {
                    buf[n]='';
                    printf("Socket %d said : %s
",sockfd,buf);
                    write(sockfd,buf,n); //Write back to client
                }
                nready --;
                if(nready<=0) break;
            }
        }

    }
    return 0;
}

poll:

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <poll.h>
 
/*环境为ubuntu10.04自带c环境,无法自动引入下列宏,所以自己写在前面了*/
#define INFTIM -1
#define POLLRDNORM  0x040       /* Normal data may be read.  */
#define POLLRDBAND  0x080       /* Priority data may be read.  */
#define POLLWRNORM  0x100       /* Writing now will not block.  */
#define POLLWRBAND  0x200       /* Priority data may be written.  */
 
#define MAXLINE  1024
#define OPEN_MAX  16 //一些系统会定义这些宏
#define SERV_PORT  10001
 
int main()
{
    int i , maxi ,listenfd , connfd , sockfd ;
    int nready;
    int n;
    char buf[MAXLINE];
    socklen_t clilen;
    struct pollfd client[OPEN_MAX];
 
    struct sockaddr_in cliaddr , servaddr;
    listenfd = socket(AF_INET , SOCK_STREAM , 0);
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
 
    bind(listenfd , (struct sockaddr *) & servaddr, sizeof(servaddr));
    listen(listenfd,10);
    client[0].fd = listenfd;
    client[0].events = POLLRDNORM;
    for(i=1;i<OPEN_MAX;i++)
    {
        client[i].fd = -1;
    }
    maxi = 0;
 
    for(;;)
    {
        nready = poll(client,maxi+1,INFTIM);
        if (client[0].revents & POLLRDNORM)
        {
            clilen = sizeof(cliaddr);
            connfd = accept(listenfd , (struct sockaddr *)&cliaddr, &clilen);
            for(i=1;i<OPEN_MAX;i++)
            {
                if(client[i].fd<0)
                {
                    client[i].fd = connfd;
                    client[i].events = POLLRDNORM;
                    break;
                }
            }
            if(i==OPEN_MAX)
            {
                printf("too many clients! 
");
            }
            if(i>maxi) maxi = i;
            nready--;
            if(nready<=0) continue;
        }
 
        for(i=1;i<=maxi;i++)
        {
            if(client[i].fd<0) continue;
            sockfd = client[i].fd;
            if(client[i].revents & (POLLRDNORM|POLLERR))
            {
                n = read(client[i].fd,buf,MAXLINE);
                if(n<=0)
                {
                    close(client[i].fd);
                    client[i].fd = -1;
                }
                else
                {
                    buf[n]='';
                    printf("Socket %d said : %s
",sockfd,buf);
                    write(sockfd,buf,n); //Write back to client
                }
                nready--;
                if(nready<=0) break; //no more readable descriptors
            }
        }
    }
    return 0;
}

epoll:

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <poll.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <sys/resource.h>
 
#define MAXLINE  1024
#define OPEN_MAX  16 //一些系统会定义这些宏
#define SERV_PORT  10001
 
int main()
{
    int i , maxi ,listenfd , connfd , sockfd ,epfd, nfds;
    int n;
    char buf[MAXLINE];
    struct epoll_event ev, events[20];  
    socklen_t clilen;
    struct pollfd client[OPEN_MAX];
 
    struct sockaddr_in cliaddr , servaddr;
    listenfd = socket(AF_INET , SOCK_STREAM , 0);
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
 
    bind(listenfd , (struct sockaddr *) & servaddr, sizeof(servaddr));
    listen(listenfd,10);
    
    epfd = epoll_create(256);
    ev.data.fd=listenfd; 
    ev.events=EPOLLIN|EPOLLET;
    epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
    
    for(;;)
    {
        nfds=epoll_wait(epfd,events,20,500); 
        for(i=0; i<nfds; i++)
        {
            if (listenfd == events[i].data.fd)
            {
                clilen = sizeof(cliaddr);
                connfd = accept(listenfd , (struct sockaddr *)&cliaddr, &clilen);
                if(connfd < 0)  
                {  
                    perror("connfd < 0");  
                    exit(1);  
                }
                ev.data.fd=connfd; 
                ev.events=EPOLLIN|EPOLLET;
                epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);                
            }
            else if (events[i].events & EPOLLIN)
            {
                if ( (sockfd = events[i].data.fd) < 0)  
                    continue;  
                n = recv(sockfd,buf,MAXLINE,0);
                if (n <= 0)   
                {    
                    close(sockfd);  
                    events[i].data.fd = -1;  
                }
                else
                {
                    buf[n]='';
                    printf("Socket %d said : %s
",sockfd,buf);
                    ev.data.fd=sockfd; 
                    ev.events=EPOLLOUT|EPOLLET;
                    epoll_ctl(epfd,EPOLL_CTL_MOD,connfd,&ev);
                }
            }
            else if( events[i].events&EPOLLOUT )
            {
                sockfd = events[i].data.fd;  
                send(sockfd, "Hello!", 7, 0);  
                  
                ev.data.fd=sockfd;  
                ev.events=EPOLLIN|EPOLLET;  
                epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); 
            }
            else 
            {
                printf("This is not avaible!");
            }
        }
    }
    close(epfd);  
    return 0;
}
原文地址:https://www.cnblogs.com/bugutian/p/4816764.html