Chinaunix首页 | 论坛 | 博客
  • 博客访问: 519865
  • 博文数量: 184
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1172
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-21 13:40
个人简介

技术改变命运

文章分类

全部博文(184)

文章存档

2020年(16)

2017年(12)

2016年(156)

我的朋友

分类: LINUX

2016-07-29 16:56:26

select系统调用:
select系统调用的用途是:在一段时间内,监听用户感兴趣的文件描述符上的可读,可写和异常等事件。
select系统调用的原型如下:
int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);
(1)nfds指定被监控的文件描述符的总数。
(2)readfds,writefds,exceptfds参数分别指向可读,可写和异常等时间对应的文件描述符集合。
(3)timeout参数用来设置select函数的超时时间.
select成功时返回就绪(可读,可写和异常)文件描述符的总数。若果在超时时间内没用任何文件描述符就绪,select将返回0,select失败时返回-1并设置errno。如果在 select等待时间内,程序接受到信号,则select立即-1,并设置errno为EINTER。
fd_set结构的定义如下:
#include
#define __FD_SETSIZE 1024
#include
#define FD_SETSIZE __FD_SETSIZE
typedef long int __fd_mask;
#undef  __NFDBITS
#dfine NFDBITS (8 * (int)sizeof(__fd_mask)
typedef sruct 
{
    #ifdef __use_xopen
           __fd_mask fds_bits[__FD_SETSIZE /__NFDBITS];
     #define __FDS_BITS(set)    ((set)->fds_bits)
    #else
         __fd_mask    __fds_bits[__FD_SETSIZE/__NFDBITS]
     #define __FDS_BITS(set)     ((set)->__fds_bits);
    #endif
} fd_set;
用以上定义可见,fd_set结构体仅包含一个整形数组,该数组的每个元素的每一位标记一个文件描述符。fd_set能容纳的文件描述符数量由FD_SETSIZE指定,这就限制了select能同时处理的文件描述符的总量。
poll系统调用:
poll系统调用和select类似,也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪者。poll的原型如下:

点击(此处)折叠或打开

  1. #include<poll.h>
  2. int poll(struct pollfd *fds,nfds_t nfds,int timeout)
1)fds参数是一个pollfd结构类型的数组,它指定所有我们感兴趣的文件描述符上发生的可读,可写和异常等事件。pollfd结构体定义如下:
struct pollfd
{
    int fd;//文件描述符
    short events;//注册的事件
    short revents;//实际发生的事件,由内核填充
};
poll事件类型 POLLIN POLLOUT POLLERR POLLRDHUP等。 
2)nfds参数指定被监听事件集合fds的大小。 
typedef unsigned long nfds_t;
3)timeout参数指定poll的超时值,单位是毫秒。timeout为-1,poll调用将永远阻塞,直到某个事件发生;当timeout为0时,poll 调用将立即返回。
返回值含义与select相同。
poll的一个简单应用:

在/root/pro/fd1 /root/pro/fd2中分别有内容,

1234

5678

1122

3344

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <errno.h>
  5. #include <sys/types.h>
  6. #include <stropts.h>
  7. #include <sys/poll.h>
  8. #include <sys/stropts.h>
  9. #include <string.h>
  10. #include <sys/stat.h>
  11. #include <fcntl.h>
  12. #include <poll.h>

  13. #define BUFSIZE 1024

  14. int main(int argc, char *argv[])
  15. {
  16.     char buf[BUFSIZE];
  17.     int bytes;
  18.     struct pollfd *pollfd;
  19.     int i=0;
  20.     int nummonitor=0;
  21.     int numready;
  22.     int errno;
  23.     char *str;
  24.     if(argc != 3)
  25.     {
  26.         fprintf(stderr,"Usage:the argc num error\n");
  27.         exit(1);
  28.     }


  29.     if((pollfd = (struct pollfd*)calloc(2, sizeof(struct pollfd))) == NULL) //为struct pollfd分配空间
  30.            exit(1);
  31.          for(i; i<2; i++) //初始化化struct pollfd结构
  32.     {
  33.         str = (char*)malloc(14*sizeof(char));
  34.         memcpy(str,"/root/pro/",14);
  35.         strcat(str,argv[i+1]);//注意,需要把路劲信息放到str中,否则opne("/root/pro/argv[i]",O_RDONLY)会出错
  36.         printf("str=%s\n",str);//原因在于,在” “之中的argv[i]是字符串,不会用变量代替argv[i].
  37.         (pollfd+i)->fd = open(str,O_RDONLY);
  38.         if((pollfd+i)->fd >= 0)
  39.             fprintf(stderr, "open (pollfd+%d)->fd:%s\n", i, argv[i+1]);
  40.         nummonitor++;
  41.         (pollfd+i)->events = POLLIN;//与下面的pollfd->revent对应
  42.     }
  43.     printf("nummonitor=%d\n",nummonitor);
  44.       
  45.     while(nummonitor > 0)
  46.     {
  47.         numready = poll(pollfd, 2, -1);
  48.         if ((numready == -1) && (errno == EINTR))
  49.             continue; //被信号中断,继续等待
  50.         else if (numready == -1)
  51.             break; //poll真正错误,推出
  52.         printf("numready=%d\n",numready);
  53.         for (i=0;nummonitor>0 && numready>0; i++)
  54.         {
  55.             if((pollfd+i)->revents & POLLIN)
  56.             {
  57.                 
  58.                  bytes = read(pollfd[i].fd, buf, BUFSIZE);
  59.                 numready--;
  60.                 printf("pollfd[%d]->fd read buf:\n%s \n", i, buf);
  61.                 nummonitor--;
  62.             }
  63.         }
  64.     }
  65.     for(i=0; i<nummonitor; i++)
  66.         close(pollfd[i].fd);
  67.     free(pollfd);
  68.     return 0;
  69. }
运行结果如下:

epoll是linux特有的I/O复用函数。它在实现上和使用上与select,poll有很大区别。首先epoll用一组函数来完成任务,而不是单个函数,其次epoll把用户关心的文件描述符上的事件放在内核里的一个事件表中。
epoll需要使用一个额外的文件描述符,来唯一标识内核中的这个事件表。这个文件描述符使用如下函数创建:

点击(此处)折叠或打开

  1. #include<sys/epoll.h>
  2. int epoll_create(int size);
size参数只是给内核一个提示,告诉它事件表有多大。
下面的函数用来操作epoll的内核事件表

点击(此处)折叠或打开

  1. #include<sys/epoll.h>
  2. int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);
fd参数是要操作的文件描述符,op参数指定操作类型,event参数指定事件。
epoll_event定义如下:
struct epoll_event
{
    __uint32_t events;    /*epoll事件*/
    epoll_data_t data;    //用户数据
};
typedef union epoll_data
{
    void *ptr;
    int fd;//使用做多的
    uint32_t u32;
    uint64_t u64;
}epoll_data_t;
epoll_ctl成功时返回0,失败则返回-1并设置errno。
epoll系统调用的主要接口是epoll_wait函数,它在一段超时时间内等待一组文件描述符上的事件,其原型如下:

点击(此处)折叠或打开

  1. #icnldue<sys/epoll.h>
  2. int epoll_event(int epfd,struct epoll_event *events,int maxevents,int timeout);
成功时返回就绪的文件描述符个数,失败时返回-1并设置errno的值。
maxevents参数指定最多监听多少个事件。
epoll_wait函数如果检测到事件,就将所有的就绪事件从内核事件表中复制到它的第二个参数events指向的数组中。这个数组只用于输出epoll检测到的就绪事件。
阅读(766) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~