select,poll和epoll,以及响应的代码

http://www.cnblogs.com/Anker/p/3265058.html
先了解IO的几种模型

http://blog.csdn.net/hguisu/article/details/7453390,这个讲的很好的,收藏
阻塞的IO模型:数据没到达之前,IO一直阻塞,如果数据到达,则会返回。典型的是recvfrom,一般的默认都是阻塞的。
非阻塞的IO模型:和阻塞相反,只要不能得到结果的时候,IO立刻返回。不会阻塞当前线程。

将阻塞的换成非阻塞的,windows下是ioctlsocket(),linux下是fcntl()

IO复用模型:也就是自己要学习的部分。多路复用的意思是,将多路信号合并到一路上进行处理,类似多个管道汇集到一个管道,与之相反的是多路分解。

IO复用模型主要是select,poll,epoll;对一个IO端口,两次调用,两次返回,比阻塞IO并没有什么优越性;关键是能实现同时对多个IO端口进行监听;函数也会使进程阻塞,但是和阻塞I/O所不同的的,这两个函数可以同时阻塞多个I/O操作。而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数。就类似让很多个检测人员去站岗,如果有情况,立刻来汇报,然后进行操作。

信号驱动:(暂时未接触到)首先开启套接口信号驱动I/O功能,并通过系统调用sigaction安装一个信号处理函数(此系统调用立即返回,进程继续工作,它是非阻塞的)。当数据报准备好被读时,就为该进程生成一个SIGIO信号。随即可以在信号处理程序中调用recvfrom来读数据报,井通知主循环数据已准备好被处理中。也可以通知主循环,让它来读数据报。理解为非阻塞的处理方式,通过信号作为命令处理。

异步的IO模型:告知内核启动某个操作,并让内核在整个操作完成后(包括将数据从内核拷贝到用户自己的缓冲区)通知我们。这种模型与信号驱动模型的主要区别是:
信号驱动I/O:由内核通知我们何时可以启动一个I/O操作,
异步I/O模型:由内核通知我们I/O操作何时完成。


epoll跟select都能提供多路I/O复用的解决方案。在现在的Linux内核里有都能够支持,其中epoll是Linux所特有,而select则应该是POSIX所规定,一般操作系统均有实现

http://www.cnblogs.com/Anker/archive/2013/08/14/3258674.html

int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout)
返回值:就绪描述符的数目,超时返回0,出错返回-1
函数参数介绍如下:

(1)第一个参数maxfdp1指定待测试的描述字个数,它的值是待测试的最大描述字加1(因此把该参数命名为maxfdp1),描述字0、1、2...maxfdp1-1均将被测试。

(2)中间的三个参数readset、writeset和exceptset指定我们要让内核测试读、写和异常条件的描述字。如果对某一个的条件不感兴趣,就可以把它设为空指针。struct fd_set可以理解为一个集合,这个集合中存放的是文件描述符,可通过以下四个宏进行设置:

void FD_ZERO(fd_set *fdset); //清空集合

void FD_SET(int fd, fd_set *fdset); //将一个给定的文件描述符加入集合之中

void FD_CLR(int fd, fd_set *fdset); //将一个给定的文件描述符从集合中删除

int FD_ISSET(int fd, fd_set *fdset); // 检查集合中指定的文件描述符是否可以读写

(3)timeout告知内核等待所指定描述字中的任何一个就绪可花多少时间。其timeval结构用于指定这段时间的秒数和微秒数。

struct timeval{

long tv_sec; //seconds

long tv_usec; //microseconds

};

这个参数有三种可能:

(1)永远等待下去:仅在有一个描述字准备好I/O时才返回。为此,把该参数设置为空指针NULL。

(2)等待一段固定时间:在有一个描述字准备好I/O时返回,但是不超过由该参数所指向的timeval结构中指定的秒数和微秒数。

(3)根本不等待:检查描述字后立即返回,这称为轮询。为此,该参数必须指向一个timeval结构,而且其中的定时器值必须为0。

这里有详细解释,主要是通过设置和检查相关的存放fd的数据结构进行下一步处理

缺点:fd的数量受限制,维护存放fd的数据结构,采取的是轮询的方案,效率低。

poll:本质上和select没有区别

poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。这个过程经历了多次无谓的遍历。

它没有最大连接数的限制,原因是它是基于链表来存储的,但是同样有一个缺点:

1、大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。 

2、poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。

epoll:
epoll支持水平触发和边缘触发,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就需态,并且只会通知一次。还有一个特点是,epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知
epoll的优点:
1、没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口);
2、效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;
即Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll。
3、 内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递;即epoll使用mmap减少复制开销。

select、poll、epoll 区别总结:

1、支持一个进程所能打开的最大连接数

select

单个进程所能打开的最大连接数有FD_SETSIZE宏定义,其大小是32个整数的大小(在32位的机器上,大小就是32*32,同理64位机器上FD_SETSIZE为32*64),当然我们可以对进行修改,然后重新编译内核,但是性能可能会受到影响,这需要进一步的测试。

poll

poll本质上和select没有区别,但是它没有最大连接数的限制,原因是它是基于链表来存储的

epoll

虽然连接数有上限,但是很大,1G内存的机器上可以打开10万左右的连接,2G内存的机器可以打开20万左右的连接

2、FD剧增后带来的IO效率问题

select

因为每次调用时都会对连接进行线性遍历,所以随着FD的增加会造成遍历速度慢的“线性下降性能问题”。

poll

同上

epoll

因为epoll内核中实现是根据每个fd上的callback函数来实现的,只有活跃的socket才会主动调用callback,所以在活跃socket较少的情况下,使用epoll没有前面两者的线性下降的性能问题,但是所有socket都很活跃的情况下,可能会有性能问题。

3、 消息传递方式

select

内核需要将消息传递到用户空间,都需要内核拷贝动作

poll

同上

epoll

epoll通过内核和用户空间共享一块内存来实现的。

总结:

综上,在选择select,poll,epoll时要根据具体的使用场合以及这三种方式的自身特点。

1、表面上看epoll的性能最好,但是在连接数少并且连接都十分活跃的情况下,select和poll的性能可能比epoll好,毕竟epoll的通知机制需要很多函数回调。

2、select低效是因为每次它都需要轮询。但低效也是相对的,视情况而定,也可通过良好的设计改善

下面是相关的select,poll,和epoll的代码(转)

服务器select

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <unistd.h>
#include <sys/types.h>

#define IPADDRESS   "127.0.0.1"
#define PORT        8787
#define MAXLINE     1024
#define LISTENQ     5

//函数声明
//创建套接字并进行绑定
static int socket_bind(const char* ip,int port);
//IO多路复用select
static void do_select(int listenfd);
//处理多个连接
static void handle_connection(int *connfds,int num,fd_set *prset,fd_set *pallset);

int main(int argc,char *argv[])
{
    int  listenfd,connfd,sockfd;
    struct sockaddr_in cliaddr;
    socklen_t cliaddrlen;
    listenfd = socket_bind(IPADDRESS,PORT);
    listen(listenfd,LISTENQ);
    do_select(listenfd);
    return 0;
}

static int socket_bind(const char* ip,int port)
{
    int  listenfd;
    struct sockaddr_in servaddr;
    listenfd = socket(AF_INET,SOCK_STREAM,0);
    if (listenfd == -1)
    {
        perror("socket error:");
        exit(1);
    }
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET,ip,&servaddr.sin_addr);
    servaddr.sin_port = htons(port);
    if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) == -1)
    {
        perror("bind error: ");
        exit(1);
    }
    return listenfd;
}

static void do_select(int listenfd)
{
    int  connfd,sockfd;
    struct sockaddr_in cliaddr;
    socklen_t cliaddrlen;
    fd_set  rset,allset;
    int maxfd,maxi;
    int i;
    int clientfds[FD_SETSIZE];  //保存客户连接描述符
    int nready;
    //初始化客户连接描述符
    for (i = 0;i < FD_SETSIZE;i++)
        clientfds[i] = -1;
    maxi = -1;
    FD_ZERO(&allset);
    //添加监听描述符
    FD_SET(listenfd,&allset);
    maxfd = listenfd;
    //循环处理
    for ( ; ; )
    {
        rset = allset;
        //获取可用描述符的个数
        nready = select(maxfd+1,&rset,NULL,NULL,NULL);
        if (nready == -1)
        {
            perror("select error:");
            exit(1);
        }
        //测试监听描述符是否准备好
        if (FD_ISSET(listenfd,&rset))
        {
            cliaddrlen = sizeof(cliaddr);
            //接受新的连接
            if ((connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddrlen)) == -1)
            {
                if (errno == EINTR)
                    continue;
                else
                {
                   perror("accept error:");
                   exit(1);
                }
            }
            fprintf(stdout,"accept a new client: %s:%d\n", inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port);
            //将新的连接描述符添加到数组中
            for (i = 0;i <FD_SETSIZE;i++)
            {
                if (clientfds[i] < 0)
                {
                    clientfds[i] = connfd;
                    break;
                }
            }
            if (i == FD_SETSIZE)
            {
                fprintf(stderr,"too many clients.\n");
                exit(1);
            }
            //将新的描述符添加到读描述符集合中
            FD_SET(connfd,&allset);
            //描述符个数
            maxfd = (connfd > maxfd ? connfd : maxfd);
            //记录客户连接套接字的个数
            maxi = (i > maxi ? i : maxi);
            if (--nready <= 0)
                continue;
        }
        //处理客户连接
        handle_connection(clientfds,maxi,&rset,&allset);
    }
}

static void handle_connection(int *connfds,int num,fd_set *prset,fd_set *pallset)
{
    int i,n;
    char buf[MAXLINE];
    memset(buf,0,MAXLINE);
    for (i = 0;i <= num;i++)
    {
        if (connfds[i] < 0)
            continue;
        //测试客户描述符是否准备好
        if (FD_ISSET(connfds[i],prset))
        {
            //接收客户端发送的信息
            n = read(connfds[i],buf,MAXLINE);
            if (n == 0)
            {
                close(connfds[i]);
                FD_CLR(connfds[i],pallset);
                connfds[i] = -1;
                continue;
            }
            printf("read msg is: ");
            write(STDOUT_FILENO,buf,n);
            //向客户端发送buf
            write(connfds[i],buf,n);
        }
    }
}
客户端 select

#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/select.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>

#define MAXLINE     1024
#define IPADDRESS   "127.0.0.1"
#define SERV_PORT   8787

#define max(a,b) (a > b) ? a : b

static void handle_connection(int sockfd);

int main(int argc,char *argv[])
{
    int                 sockfd;
    struct sockaddr_in  servaddr;
    sockfd = socket(AF_INET,SOCK_STREAM,0);
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    inet_pton(AF_INET,IPADDRESS,&servaddr.sin_addr);
    connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
    //处理连接描述符
    handle_connection(sockfd);
    return 0;
}

static void handle_connection(int sockfd)
{
    char    sendline[MAXLINE],recvline[MAXLINE];
    int     maxfdp,stdineof;
    fd_set  rset;
    int n;
    FD_ZERO(&rset);
    for (; ;)
    {
        //添加标准输入描述符
        FD_SET(STDIN_FILENO,&rset);
        //添加连接描述符
        FD_SET(sockfd,&rset);
        maxfdp = max(STDIN_FILENO,sockfd);
        //进行轮询
        select(maxfdp+1,&rset,NULL,NULL,NULL);
        //测试连接套接字是否准备好
        if (FD_ISSET(sockfd,&rset))
        {
            n = read(sockfd,recvline,MAXLINE);
            if (n == 0)
            {
                    fprintf(stderr,"client: server is closed.\n");
                    close(sockfd);
                    FD_CLR(sockfd,&rset);
            }
            write(STDOUT_FILENO,recvline,n);
        }
        //测试标准输入是否准备好
        if (FD_ISSET(STDIN_FILENO,&rset))
        {
            n = read(STDIN_FILENO,sendline,MAXLINE);
            if (n  == 0)
            {
                FD_CLR(STDIN_FILENO,&rset);
                continue;
            }
            write(sockfd,sendline,n);
        }
    }
}
poll的例子

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

http://man7.org/linux/man-pages/man2/poll.2.html

和select 差不多,下列代码,转

/*
 * Pollserver.c
 *
 *  Created on: 2012-9-9
 *      Author: sangerhoo
 */


#include<sys/types.h>
#include<ctype.h>
#include<strings.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<arpa/inet.h>
#include<ctype.h>
#include<errno.h>
#include<sys/time.h>
#include<stdio.h>
#include<string.h>
#include<sys/poll.h>
#include<stdlib.h>

#define LISTEN_QUEUE_NUM 5
#define MAX_CONNECT 1024

#define BUFFER_SIZE 256
#define ECHO_PORT 2029

static struct pollfd clipoll[MAX_CONNECT];
int max = 0;

/*initialize poll struct*/
static void poll_init()
{
	int i;
	for (i = 0; i < MAX_CONNECT; i++)
		clipoll[i].fd = -1;
}

/*
 find a unused pollfd struct
 if found then return its index
 else return -1
*/
static int poll_alloc()
{
	int i;
	for (i = 0; i < MAX_CONNECT; i++)
	{
		if (clipoll[i].fd < 0)
			return i;
	}
	return -1;
}

/*find used max index in pllfd*/
static void update_max()
{
	int i;
	max = 0;
	for (i = 0; i < MAX_CONNECT; i++)
	{
		if (clipoll[i].fd > 0)
		max = i;
	}
}

/*free a pollfd when unused*/
static int poll_free(int i)
{
	close(clipoll[i].fd);
	clipoll[i].fd = -1;
	clipoll[i].events = 0;
	clipoll[i].revents = 0;
	update_max();
}

/*
  fill up pollfd with file descriptable
  and event
*/
static int poll_set_item(int fd, uint32_t events)
{
	int i;
	if ((i = poll_alloc()) < 0)
		return -1;
	clipoll[i].fd = fd;
	clipoll[i].events = events;
	clipoll[i].revents = 0;
	if (i > max)
		max = i;
	return 0;
}

int main(int argc, char **argv)
{
	struct sockaddr_in servaddr, remote;
	int request_sock, new_sock;
	int nfound, i, bytesread;
	uint32_t addrlen;
	char buf[BUFFER_SIZE];
	/*setup socket*/
	if ((request_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("socket");
		return -1;
	}
	/*fill up ip address structure*/
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = INADDR_ANY;
	servaddr.sin_port = htons(ECHO_PORT);
	/*bind server ip address structure*/
	if (bind(request_sock, (struct sockaddr *) &servaddr, sizeof(servaddr)) <	0)
	{
		perror("bind");
		return -1;
	}
	/*listen client*/
	if (listen(request_sock, LISTEN_QUEUE_NUM) < 0)
	{
		perror("listen");
		return -1;
	}
	poll_init();
	poll_set_item(request_sock, POLLIN);
	while (1)
	{
	/*check whether ready file exist ?*/
		if ((nfound = poll(clipoll, max + 1, 500)) < 0)
		{
			if (errno == EINTR)
			{
				printf("interruptedb system call\n");
				continue;
			}
			perror("poll");
			return -1;
		}else if(nfound == 0)
		{
			printf(".");
			fflush(stdout);
			continue;
		}
		/*check listen socket if ready or not ?*/
		if (clipoll[0].revents & (POLLIN | POLLERR))
		{
			addrlen = sizeof(remote);
			if ((new_sock =	accept(request_sock, (struct sockaddr *) &remote,	&addrlen)) < 0)
			{
				perror("accept");
				return -1;
			}
			printf("connection fromm host %s,port %d, socket %d\r\n",
					inet_ntoa(remote.sin_addr), ntohs(remote.sin_port), new_sock);
			if (poll_set_item(new_sock, POLLIN) < 0)
				fprintf(stderr, "Too many connects\r\n");
			nfound--;
		}
		/*check communicating socket if ready or not ? */
		for (i = 1; i <= max && nfound > 0; i++)
		{
			if (clipoll[i].fd >= 0 && clipoll[i].revents & (POLLIN | POLLERR))
			{
				nfound--;
				if((bytesread = read(clipoll[i].fd, buf, sizeof(buf) - 1)) < 0)
				{
					perror("read");
					poll_free(i);
					continue;
				}
				if(bytesread == 0)
				{
					fprintf(stderr, "server: end of file on %d\r\n", clipoll[i].fd);
					poll_free(i);
					continue;
				}
				buf[bytesread] = 0;
				printf("%s:%d bytes from %d :%s\n", argv[0], bytesread,
				clipoll[i].fd, buf);
				if (write(clipoll[i].fd, buf, bytesread) != bytesread)
				{
					perror("echo");
					poll_free(i);
					continue;
				}
			}
		}
	}
	return 0;
}

epoll:

epoll只有epoll_create,epoll_ctl,epoll_wait 3个系统调用。

http://man7.org/linux/man-pages/man7/epoll.7.html

http://blog.csdn.net/xiajun07061225/article/details/9250579

epoll的三个函数

[cpp]  view plain copy
  1. int epoll_creae(int size);  
功能:该函数生成一个epoll专用的文件描述符

参数:size为epoll上能关注的最大描述符数

[cpp]  view plain copy
  1. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);  
功能:用于控制某个epoll文件描述符时间,可以注册、修改、删除

epoll事件注册函数,它不同于select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。

参数:epfd由epoll_create生成的epoll专用描述符

    op操作:EPOLL_CTL_ADD 注册   EPOLL_CTL_MOD修改  EPOLL_DEL删除

            fd:关联的文件描述符

    evnet告诉内核要监听什么事件

[cpp]  view plain copy
  1. int epoll_wait(int epfd,struct epoll_event*events,int maxevents,int timeout);  
功能:该函数等待i/o事件的发生。

参数:epfd要检测的句柄

     events:用于回传待处理时间的数组

     maxevents:告诉内核这个events有多大,不能超过之前的size

     timeout:为超时时间,-1阻塞,0为立刻返回。

返回值是需要读写的fd的个数


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <errno.h>

#define MAXEVENTS 64

static int
make_socket_non_blocking (int sfd)
{
  int flags, s;

  flags = fcntl (sfd, F_GETFL, 0);
  if (flags == -1)
    {
      perror ("fcntl");
      return -1;
    }

  flags |= O_NONBLOCK;
  s = fcntl (sfd, F_SETFL, flags);
  if (s == -1)
    {
      perror ("fcntl");
      return -1;
    }

  return 0;
}

static int
create_and_bind (char *port)
{
  struct addrinfo hints;
  struct addrinfo *result, *rp;
  int s, sfd;

  memset (&hints, 0, sizeof (struct addrinfo));
  hints.ai_family = AF_UNSPEC;     /* Return IPv4 and IPv6 choices */
  hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */
  hints.ai_flags = AI_PASSIVE;     /* All interfaces */

  s = getaddrinfo (NULL, port, &hints, &result);
  if (s != 0)
    {
      fprintf (stderr, "getaddrinfo: %s\n", gai_strerror (s));
      return -1;
    }

  for (rp = result; rp != NULL; rp = rp->ai_next)
    {
      sfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);
      if (sfd == -1)
        continue;

      s = bind (sfd, rp->ai_addr, rp->ai_addrlen);
      if (s == 0)
        {
          /* We managed to bind successfully! */
          break;
        }

      close (sfd);
    }

  if (rp == NULL)
    {
      fprintf (stderr, "Could not bind\n");
      return -1;
    }

  freeaddrinfo (result);

  return sfd;
}

int
main (int argc, char *argv[])
{
  int sfd, s;
  int efd;
  struct epoll_event event;
  struct epoll_event *events;

  if (argc != 2)
    {
      fprintf (stderr, "Usage: %s [port]\n", argv[0]);
      exit (EXIT_FAILURE);
    }

  sfd = create_and_bind (argv[1]);
  if (sfd == -1)
    abort ();

  s = make_socket_non_blocking (sfd);
  if (s == -1)
    abort ();

  s = listen (sfd, SOMAXCONN);
  if (s == -1)
    {
      perror ("listen");
      abort ();
    }

  efd = epoll_create1 (0);
  if (efd == -1)
    {
      perror ("epoll_create");
      abort ();
    }

  event.data.fd = sfd;
  event.events = EPOLLIN | EPOLLET;
  s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event);
  if (s == -1)
    {
      perror ("epoll_ctl");
      abort ();
    }

  /* Buffer where events are returned */
  events = calloc (MAXEVENTS, sizeof event);

  /* The event loop */
  while (1)
  {
      int n, i;

    n = epoll_wait (efd, events, MAXEVENTS, -1);
    for (i = 0; i < n; i++)
	{
	  if ((events[i].events & EPOLLERR) ||
              (events[i].events & EPOLLHUP) ||
              (!(events[i].events & EPOLLIN)))
	    {
              /* An error has occured on this fd, or the socket is not
                 ready for reading (why were we notified then?) */
	      fprintf (stderr, "epoll error\n");
	      close (events[i].data.fd);
	      continue;
	    }

	  else if (sfd == events[i].data.fd)
	    {
              /* We have a notification on the listening socket, which
                 means one or more incoming connections. */
              while (1)
                {
                  struct sockaddr in_addr;
                  socklen_t in_len;
                  int infd;
                  char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];

                  in_len = sizeof in_addr;
                  infd = accept (sfd, &in_addr, &in_len);
                  if (infd == -1)
                    {
                      if ((errno == EAGAIN) ||
                          (errno == EWOULDBLOCK))
                        {
                          /* We have processed all incoming
                             connections. */
                          break;
                        }
                      else
                        {
                          perror ("accept");
                          break;
                        }
                    }

                  s = getnameinfo (&in_addr, in_len,
                                   hbuf, sizeof hbuf,
                                   sbuf, sizeof sbuf,
                                   NI_NUMERICHOST | NI_NUMERICSERV);
                  if (s == 0)
                    {
                      printf("Accepted connection on descriptor %d "
                             "(host=%s, port=%s)\n", infd, hbuf, sbuf);
                    }

                  /* Make the incoming socket non-blocking and add it to the
                     list of fds to monitor. */
                  s = make_socket_non_blocking (infd);
                  if (s == -1)
                    abort ();

                  event.data.fd = infd;
                  event.events = EPOLLIN | EPOLLET;
                  s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event);
                  if (s == -1)
                    {
                      perror ("epoll_ctl");
                      abort ();
                    }
                }
              continue;
            }
          else
            {
              /* We have data on the fd waiting to be read. Read and
                 display it. We must read whatever data is available
                 completely, as we are running in edge-triggered mode
                 and won't get a notification again for the same
                 data. */
              int done = 0;

              while (1)
                {
                  ssize_t count;
                  char buf[512];

                  count = read (events[i].data.fd, buf, sizeof buf);
                  if (count == -1)
					{
					  /* If errno == EAGAIN, that means we have read all
						 data. So go back to the main loop. */
					  if (errno != EAGAIN)
						{
						  perror ("read");
						  done = 1;
						}
					  break;
					}
                  else if (count == 0)
                    {
                      /* End of file. The remote has closed the
                         connection. */
                      done = 1;
                      break;
                    }

                  /* Write the buffer to standard output */
                  s = write (1, buf, count);
                  if (s == -1)
                    {
                      perror ("write");
                      abort ();
                    }
                }

              if (done)
                {
                  printf ("Closed connection on descriptor %d\n",
                          events[i].data.fd);

                  /* Closing the descriptor will make epoll remove it
                     from the set of descriptors which are monitored. */
                  close (events[i].data.fd);
                }
         }
	}
  }

  free (events);

  close (sfd);

  return EXIT_SUCCESS;
}

EPOLLIN = 0x001,
#define EPOLLIN EPOLLIN
    EPOLLPRI = 0x002,
#define EPOLLPRI EPOLLPRI
    EPOLLOUT = 0x004,
#define EPOLLOUT EPOLLOUT
    EPOLLRDNORM = 0x040,
#define EPOLLRDNORM EPOLLRDNORM
    EPOLLRDBAND = 0x080,
#define EPOLLRDBAND EPOLLRDBAND
    EPOLLWRNORM = 0x100,
#define EPOLLWRNORM EPOLLWRNORM
    EPOLLWRBAND = 0x200,
#define EPOLLWRBAND EPOLLWRBAND
    EPOLLMSG = 0x400,
#define EPOLLMSG EPOLLMSG
    EPOLLERR = 0x008,
#define EPOLLERR EPOLLERR
    EPOLLHUP = 0x010,
#define EPOLLHUP EPOLLHUP
    EPOLLET = (1 << 31)
#define EPOLLET EPOLLET
相关的值,只是一些位置上的num





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值