select、poll、epoll程序实例

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 .\n");
                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]=‘\0‘;
                    printf("Socket %d said : %s\n",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! \n");
            }
            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]=‘\0‘;
                    printf("Socket %d said : %s\n",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]=‘\0‘;
                    printf("Socket %d said : %s\n",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;
}
时间: 2025-01-14 16:19:59

select、poll、epoll程序实例的相关文章

# 进程/线程/协程 # IO:同步/异步/阻塞/非阻塞 # greenlet gevent # 事件驱动与异步IO # Select\Poll\Epoll异步IO 以及selectors模块 # Python队列/RabbitMQ队列

1 # 进程/线程/协程 2 # IO:同步/异步/阻塞/非阻塞 3 # greenlet gevent 4 # 事件驱动与异步IO 5 # Select\Poll\Epoll异步IO 以及selectors模块 6 # Python队列/RabbitMQ队列 7 8 ############################################################################################## 9 1.什么是进程?进程和程序之间有什么

Linux内核中网络数据包的接收-第二部分 select/poll/epoll

和前面文章的第一部分一样,这些文字是为了帮别人或者自己理清思路的,而不是所谓的源码分析,想分析源码的,还是直接debug源码最好,看任何文档以及书都是下策.因此这类帮人理清思路的文章尽可能的记成流水的方式,尽可能的简单明了. Linux 2.6+内核的wakeup callback机制 Linux 内核通过睡眠队列来组织所有等待某个事件的task,而wakeup机制则可以异步唤醒整个睡眠队列上的task,每一个睡眠队列上的节点都拥有一个 callback,wakeup逻辑在唤醒睡眠队列时,会遍历

Linux统系统开发12 Socket API编程3 TCP状态转换 多路IO高并发select poll epoll udp组播 线程池

[本文谢绝转载原文来自http://990487026.blog.51cto.com] Linux统系统开发12 Socket API编程3 TCP状态转换 多路IO高并发select  poll  epoll udp组播 线程池 TCP 11种状态理解: 1,客户端正常发起关闭请求 2,客户端与服务端同时发起关闭请求 3,FIN_WAIT1直接转变TIME_WAIT 4,客户端接收来自服务器的关闭连接请求 多路IO转接服务器: select模型 poll模型 epoll模型 udp组播模型 线

多进程、协程、事件驱动及select poll epoll

目录 -多线程使用场景 -多进程 --简单的一个多进程例子 --进程间数据的交互实现方法 ---通过Queues和Pipe可以实现进程间数据的传递,但是不能实现数据的共享 ---Queues ---Pipe ---通过Manager可以不同进程间实现数据的共享 --进程同步,即进程锁 --进程池 -协程 --先用yield实现简单的协程 --Greenlet --Gevent --用协程gevent写一个简单并发爬网页 -事件驱动 --IO多路复用 ---用户空间和内核空间 ---文件描述符fd

select,poll,epoll用法

http://blog.csdn.net/sunboy_2050/article/details/6126712 select用法 #include <sys/time.h>       #include <sys/types.h>       #include <unistd.h> #include <sys/select.h> int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exc

Linux I/O复用中select poll epoll模型的介绍及其优缺点的比较

关于I/O多路复用: I/O多路复用(又被称为"事件驱动"),首先要理解的是,操作系统为你提供了一个功能,当你的某个socket可读或者可写的时候,它可以给你一个通知.这样当配合非阻塞的socket使用时,只有当系统通知我哪个描述符可读了,我才去执行read操作,可以保证每次read都能读到有效数据而不做纯返回-1和EAGAIN的无用功.写操作类似.操作系统的这个功能通过select/poll/epoll之类的系统调用来实现,这些函数都可以同时监视多个描述符的读写就绪状况,这样,**多

几种典型的服务器网络编程模型归纳(select poll epoll)

1.同步阻塞迭代模型 同步阻塞迭代模型是最简单的一种IO模型. 其核心代码如下: bind(srvfd); listen(srvfd); for(;;) { clifd = accept(srvfd,...); //开始接受客户端来的连接 read(clifd,buf,...); //从客户端读取数据 dosomthingonbuf(buf); write(clifd,buf)//发送数据到客户端 } 上面的程序存在如下一些弊端: 1)如果没有客户端的连接请求,进程会阻塞在accept系统调用处

IO复用之select poll epoll的总结

I/O复用使得程序能够同时监听多个文件描述符,对于提高程序性能至关重要.I/O复用不仅仅在网络程序中使用,但是我接触到的例子中,TCP网络编程那块使用I/O复用比较多,例如,TCP服务器同时处理监听socket和连接socket. 在了解I/O复用之前,我们需要先了解几个概念. 1,同步I/O与异步I/O 2,LT(水平触发)和ET(边缘触发) POSIX把两个术语定义如下: 同步I/O:导致请求进程阻塞,直到I/O操作完成 异步I/O:  不导致请求进程阻塞 阻塞是进程在等待某种资源,但是不能

Linux I/O复用中select poll epoll模型的介绍及其优缺点的比較

关于I/O多路复用: I/O多路复用(又被称为"事件驱动"),首先要理解的是.操作系统为你提供了一个功能.当你的某个socket可读或者可写的时候.它能够给你一个通知.这样当配合非堵塞的socket使用时,仅仅有当系统通知我哪个描写叙述符可读了,我才去运行read操作.能够保证每次read都能读到有效数据而不做纯返回-1和EAGAIN的无用功.写操作相似.操作系统的这个功能通过select/poll/epoll之类的系统调用来实现.这些函数都能够同一时候监视多个描写叙述符的读写就绪状况

Linux下select&amp;poll&amp;epoll的实现原理(一)

最近简单看了一把Linux linux-3.10.25 kernel中select/poll/epoll这个几个IO事件检测API的实现.此处做一些记录.其基本的原理是相同的,流程如下 先依次调用fd对应的struct file.f_op->poll()方法(如果有提供实现的话),尝试检查每个提供待检测IO的fd是否已经有IO事件就绪 如果已经有IO事件就绪,则直接所收集到的IO事件返回,本次调用结束 如果暂时没有IO事件就绪,则根据所给定的超时参数,选择性地进入等待 如果超时参数指示不等待,则