您的位置:首页 > 运维架构 > Linux

Linux高级文件操作 -2

2016-10-15 23:34 253 查看

用poll实现多路传输

系统调用poll(), 允许进程在多个文件描述符之间同时阻塞。

进程不再不断地检查每个它所关心的文件描述符,而是通过一个系统调用来指定读取或者写入哪个文件描述符。当有一个或者多个文件有数据可以读取或者可以写入时,poll()调用返回,应用程序就可以读写这些文件描述符而不用担心阻塞。

一旦应用程序处理了这些文件,进程就可以发起另一个poll()调用,一直阻塞,直到有一个文件做好了被读取或者写入的准备。

poll()系统调用:

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);


nfds指定了第一个参数所指向的数组中的元素数目;

timeout指定了poll()用多长时间来等待一个事件发生,如果是0被当做超时,poll()系统调用将永远超时(即永远轮询下去)。

第一个参数fds描述了哪些文件描述符以及哪种类型的I/O需要被监控,它是一个指向pollfd的结构的数组指针:

struct pollfd {
int   fd;         /* file descriptor */
short events;     /* requested events */
short revents;    /* returned events */
};


The caller should specify the number of items in the fds array in nfds.

The field fd contains a file descriptor for an open file. If this field is negative, then the corresponding events field is ignored and the revents field returns zero. (This provides an easy way of ignoring a file descriptor for a single poll() call: simply negate the fd field.)

The field events is an input parameter, a bit mask specifying the events the application is interested in for the file descriptor fd. If this field is specified as zero, then all events are ignored for fd and revents returns zero.

The field revents is an output parameter, filled by the kernel with the events that actually occurred. The bits returned in revents can include any of those specified in events, or one of the values POLLERR, POLLHUP, or POLLNVAL. (These three bits are meaningless in the events field, and will be set in the revents field whenever the corresponding condition is true.)

If none of the events requested (and no error) has occurred for any of the file descriptors, then poll() blocks until one of the events occurs.

The timeout argument specifies the number of milliseconds that poll() 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. Specifying a negative value in timeout means an infinite timeout. Specifying a timeout of zero causes poll() to return immediately, even if no file descriptors are ready.

The bits that may be set/returned in events and revents are defined in poll.h:

POLLIN There is data to read.

POLLPRI There is urgent data to read (e.g., out-of-band data on TCP socket; pseudoterminal master in packet mode has seen state change in slave).

POLLOUT Writing now will not block.

POLLRDHUP (since Linux 2.6.17) Stream socket peer closed connection, or shut down writing half of connection. The _GNU_SOURCE feature test macro must be defined (before including any header files) in order to obtain this definition.

有一些位由内核在revents中设置,但对于events没有意义:

POLLERR Error condition (output only). 这个时候errno被设置适当的值。

POLLHUP Hang up (output only).

POLLNVAL Invalid request: fd not open (output only).

如果超时poll()调用返回0,如果发生了错误就返回-1(例如fds不是一个合法的指针,或者文件本身的错误使得POLLERR被设置)。如果正确,则返回一个正整数,返回用非零的revents成员描述文件数量。

还是“Linux高级文件操作 -1”中描述的多路输入问题,当poll()调用返回的时候,就可以直到一个管道数据已经准备好可以被读,或者是一个管道已经被关闭。

然后通过检查这两个文件描述符对应的revents成员决定采取哪种行动,在行动完成后又回到poll()调用。

所以用poll模式绝大多数时间都阻塞在了poll()调用,而不是连续不断地检查使用了非阻塞I/O的文件描述符,这样就很大成都上降低了系统负载。

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

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

int main(void) {
struct pollfd fds[2];
char buf[4096];
int i, rc;

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

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

/* start off reading from both file descriptors */
fds[0].events = POLLIN;
fds[1].events = POLLIN;

/* while we're watching one of fds[0] or fds[1] */
while (fds[0].events || fds[1].events) {
if (poll(fds, 2, 0) < 0) {
perror("poll");
return 1;
}

/* check to see which file descriptors are ready to be
read from */
for (i = 0; i < 2; i++) {
if (fds[i].revents) {
/* fds[i] is ready for reading, go ahead... */
rc = read(fds[i].fd, 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 */
fds[i].events = 0;
} else {
buf[rc] = '\0';
printf("read: %s", buf);
}
}
}
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux poll