Linux高级文件操作 -3

使用select的多路传输

poll()系统调用最早是作为Unix书中System V部分被引入的,BSD 通过相似的办法引入seletct()系统调用,解决相同的问题。

定义:

       /* According to POSIX.1-2001 */
       #include <sys/select.h>

       /* According to earlier standards */
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

       void FD_CLR(int fd, fd_set *set);
       int  FD_ISSET(int fd, fd_set *set);
       void FD_SET(int fd, fd_set *set);
       void FD_ZERO(fd_set *set);

Three independent sets of file descriptors are watched. Those listed in readfds will be watched to see if characters become avail‐able for reading (more precisely, to see if a read will not block; in particular, a file descriptor is also ready on end-of-file), those in writefds will be watched to see if a write will not block, and those in exceptfds will be watched for exceptions. On exit, the sets are modified in place to indicate which file descriptors actually changed status. Each of the three file descriptor sets may be specified as NULL if no file descriptors are to be watched for the corresponding class of events.

Four macros are provided to manipulate the sets. FD_ZERO() clears a set. FD_SET() and FD_CLR() respectively add and remove a given file descriptor from a set. FD_ISSET() tests to see if a file descriptor is part of the set; this is useful after select() returns.

nfds is the highest-numbered file descriptor in any of the three sets, plus 1.

The timeout argument specifies the interval that select() should block waiting for a file descriptor to become ready. This interval will be rounded up to the system clock granularity, and kernel scheduling delays mean that the blocking interval may overrun by a small amount. If both fields of the timeval structure are zero, then select() returns immediately. (This is useful for polling.) If timeout is NULL (no timeout), select() can block indefinitely.

   The timeout The time structures involved are defined in <sys/time.h> and look like

           struct timeval {
               long    tv_sec;         /* seconds */
               long    tv_usec;        /* microseconds */
           };

       and

           struct timespec {
               long    tv_sec;         /* seconds */
               long    tv_nsec;        /* nanoseconds */
           };

select()调用返回这三个fd_set中所有被设置的项目总数,如果调用超时则返回0,如果有错误发生则返回-1。
用select可以实现的延时操作:

#include <sys/select.h>
#include <sys/stdlib.h>

int usecsleep(int usecs) {
   strcut timeval tv;
   tv.tv_sec = 0;
   tv.tv_usec = usecs;

   return select(0, NULL, NULL, NULL, &tv);
}

这样就实现了短于1秒的延时,
usecsleep(500000)引起一个半秒的暂停。

最后再用select解决”Linux高级文件操作 -2”中的多路输入问题:

/* mpx-select.c - Displays input from two pipes using \codefn{select()} */

#include <fcntl.h>
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>

int main(void) {
    int fds[2];
    char buf[4096];
    int i, rc, maxfd;
    fd_set watchset;       /* fds to read from */
    fd_set inset;          /* updated by select() */

    /* open both pipes */
    if ((fds[0] = open("p1", O_RDONLY | O_NONBLOCK)) < 0) {
        perror("open p1");
        return 1;
    }

    if ((fds[1] = open("p2", O_RDONLY | O_NONBLOCK)) < 0) {
        perror("open p2");
        return 1;
    }

    /* start off reading from both file descriptors */
    FD_ZERO(&watchset);
    FD_SET(fds[0], &watchset);
    FD_SET(fds[1], &watchset);

    /* find the maximum file descriptor */
    maxfd = fds[0] > fds[1] ? fds[0] : fds[1];

    /* while we're watching one of fds[0] or fds[1] */
    while (FD_ISSET(fds[0], &watchset) || 
           FD_ISSET(fds[1], &watchset)) {
        /* we copy watchset here because select() updates it */
        inset = watchset;
        if (select(maxfd + 1, &inset, NULL, NULL, NULL) < 0) {
            perror("select");
            return 1;
        } 

        /* check to see which file descriptors are ready to be
           read from */
        for (i = 0; i < 2; i++) {
            if (FD_ISSET(fds[i], &inset)) {
                /* fds[i] is ready for reading, go ahead... */
                rc = read(fds[i], buf, sizeof(buf) - 1);
                if (rc < 0) {
                    perror("read");
                    return 1;
                } else if (!rc) {
                    /* this pipe has been closed, don't try
                       to read from it again */
                    close(fds[i]);
                    FD_CLR(fds[i], &watchset);
                } else {
                    buf[rc] = '\0';
                    printf("read: %s", buf);
                }
            }
        } 
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值