C语言多路复用技术

上传人:ji****72 文档编号:37509408 上传时间:2018-04-17 格式:DOCX 页数:12 大小:32.19KB
返回 下载 相关 举报
C语言多路复用技术_第1页
第1页 / 共12页
C语言多路复用技术_第2页
第2页 / 共12页
C语言多路复用技术_第3页
第3页 / 共12页
C语言多路复用技术_第4页
第4页 / 共12页
C语言多路复用技术_第5页
第5页 / 共12页
点击查看更多>>
资源描述

《C语言多路复用技术》由会员分享,可在线阅读,更多相关《C语言多路复用技术(12页珍藏版)》请在金锄头文库上搜索。

1、linux 下的常见多路复用技术下的常见多路复用技术C 语言post by 陈俊生 / 2012-1-4 9:25 Wednesday 要实现 I/O 多路复用有很多的方式,其中可以用进程或者是线程等来实现,也 可以用 select/poll /epoll/port 等来实现。在相比两者之间,利用 select/poll /epoll/port 等来实现复用效率更快,实现更容易,在底层的需要的资源更少, 效率更快。 下面就介绍一下 select/poll /epoll/port 等的具体用法。 Select 的用法的用法。select 原型:int select(int n, fd_set *

2、readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);其中参数 n 表示监控的所有 fd 中最大值1。和 select 模型紧密结合的四个宏,含义不解释了:FD_CLR(int fd, fd_set *set);FD_ISSET(int fd, fd_set *set);FD_SET(int fd, fd_set *set);FD_ZERO(fd_set *set);理解 select 模型的关键在于理解 fd_set,为说明方便,取 fd_set 长度为 1 字节,fd_set 中的每一 bit 可以对应

3、一个文件描述符 fd。则 1 字节长的 fd_set 最大可以对应 8 个 fd。(1)执行 fd_set set; FD_ZERO(则 set 用位表示是 0000,0000。(2)若 fd5,执行 FD_SET(fd,后 set 变为 0001,0000(第 5 位置为 1)(3)若再加入 fd2,fd=1,则 set 变为 0001,0011(4)执行 select(6,nSock=0;arraynSock+=listen_fd;(之前 listen port 已绑定并 listen)maxfd=listen_fd;while FD_ZERO(foreach (fd in array)

4、fd 大于 maxfd,则 maxfd=fdFD_SET(fd,arraynsock+=newfd;if(-res int poll (struct pollfd *fds, unsigned int nfds, int timeout);和 select()不一样,poll()没有使用低效的三个基于位的文件描述符 set,而 是采用了一个单独的结构体 pollfd 数组,由 fds 指针指向这个组。pollfd 结 构体定义如下:#include struct pollfd int fd; short events; short revents; ;每一个 pollfd 结构体指定了一个被监

5、视的文件描述符,可以传递多个结构体, 指示 poll()监视多个文件描述符。每个结构体的 events 域是监视该文件描述 符的事件掩码,由用户来设置这个域。revents 域是文件描述符的操作结果事 件掩码。内核在调用返回时设置这个域。events 域中请求的任何事件都可能在 revents 域中返回。合法的事件如下: POLLIN 有数据可读。 POLLRDNORM 有普通数据可读。 POLLRDBAND 有优先数据可读。 POLLPRI 有紧迫数据可读。 POLLOUT 写数据不会导致阻塞。 POLLWRNORM 写普通数据不会导致阻塞。 POLLWRBAND 写优先数据不会导致阻塞。

6、POLLMSG SIGPOLL 消息可用。此外,revents 域中还可能返回下列事件: POLLER指定的文件描述符发生错误。 POLLHUP 指定的文件描述符挂起事件。 POLLNVAL 指定的文件描述符非法。这些事件在 events 域中无意义,因为它们在合适的时候总是会从 revents 中返 回。使用 poll()和 select()不一样,你不需要显式地请求异常情况报告。 POLLIN | POLLPRI 等价于 select()的读事件,POLLOUT | POLLWRBAND 等价于 select()的写事件。POLLIN 等价于 POLLRDNORM | POLLRDBAND

7、,而 POLLOUT 则 等价于 POLLWRNORM。 例如,要同时监视一个文件描述符是否可读和可写,我们可以设置 events 为 POLLIN | POLLOUT。在 poll 返回时,我们可以检查 revents 中的标志,对应于 文件描述符请求的 events 结构体。如果 POLLIN 事件被设置,则文件描述符可 以被读取而不阻塞。如果 POLLOUT 被设置,则文件描述符可以写入而不导致阻 塞。这些标志并不是互斥的:它们可能被同时设置,表示这个文件描述符的读 取和写入操作都会正常返回而不阻塞。 timeout 参数指定等待的毫秒数,无论 I/O 是否准备好,poll 都会返回。

8、timeout 指定为负数值表示无限超时;timeout 为 0 指示 poll 调用立即返回并 列出准备好 I/O 的文件描述符,但并不等待其它的事件。这种情况下,poll() 就像它的名字那样,一旦选举出来,立即返回。 返回值和错误代码 成功时,poll()返回结构体中 revents 域不为 0 的文件描述符个数;如果在超 时前没有任何事件发生,poll()返回 0;失败时,poll()返回-1,并设置 errno 为下列值之一: EBADF 一个或多个结构体中指定的文件描述符无效。 EFAULT fds 指针指向的地址超出进程的地址空间。 EINTR 请求的事件之前产生一个信号,调用可

9、以重新发起。 EINVAL nfds 参数超出 PLIMIT_NOFILE 值。 ENOMEM 可用内存不足,无法完成请求。poll 的服务器模型伪码:struct pollfd fdsPOLL_LEN;unsigned int nfds=0;fds0.fd=server_sockfd;fds0.events=POLLIN|POLLPRI;nfds+;while res=poll(fds,nfds,-1);if(fds0.revents / 已经完成的操作事件的队列。 struct rb_root rbr; / 保存 epoll 监视的文件描述符 ; 这个结构体保存了 epoll 文件描述符的

10、扩展信息,它被保存在 file 结构体的 private_data 中。它与 epoll 文件节点一一对应。通常一个 epoll 文件节点对 应多个被监视的文件描述符。所以一个 eventpoll 结构体会对应多个 epitem 结 构体。那么,epoll 中的等待事件放在哪里呢?见下面/ Wait structure used by the poll hooks struct eppoll_entry struct list_head llink; / List header used to link this structure to the “struct epitem“ void *b

11、ase; / The “base“ pointer is set to the container “struct epitem“ wait_queue_t wait; / Wait queue item that will be linked to the target file wait queue head. wait_queue_head_t *whead; / The wait queue head that linked the “wait“ wait queue item ; 与 select/poll 的 struct poll_table_entry 相比,epoll 的表示

12、等待队列节 点的结构体只是稍有不同,与 struct poll_table_entry 比较一下。struct poll_table_entry struct file * filp; wait_queue_t wait; wait_queue_head_t * wait_address; ; 由于 epitem 对应一个被监视的文件,所以通过 base 可以方便地得到被监视的 文件信息。又因为一个文件可能有多个事件发生,所以用 llink 链接这些事件。(3)epoll_create 的实现epoll_create()的功能是创建一个 eventpollfs 文件系统的 inode 节点。具

13、体 由 ep_getfd()完成。ep_getfd()先调用 ep_eventpoll_inode()创建一个 inode 节点,然后调用 d_alloc()为 inode 分配一个 dentry。最后把 file,dentry,inode 三者关联起来。在执行了 ep_getfd()之后,它又调用了 ep_file_init(),分配了 eventpoll 结构体,并把 eventpoll 的指针赋给 file 结构体,这样 eventpoll 就与 file 结构体关联起来了。 需要注意的是 epoll_create()的参数 size 实际上只是起参考作用,只要它不 小于等于 0,就并不

14、限制这个 epoll inode 关联的文件描述符数量。(4)epoll_ctl 的实现epoll_ctl 的功能是实现一系列操作,如把文件与 eventpollfs 文件系统的 inode 节点关联起来。这里要介绍一下 eventpoll 结构体,它保存在 file- f_private 中,记录了 eventpollfs 文件系统的 inode 节点的重要信息,其中 成员 rbr 保存了该 epoll 文件节点监视的所有文件描述符。组织的方式是一棵 红黑树,这种结构体在查找节点时非常高效。首先它调用 ep_find()从 eventpoll 中的红黑树获得 epitem 结构体。然后根据

15、op 参数的不同而选择不 同的操作。如果 op 为 EPOLL_CTL_ADD,那么正常情况下 epitem 是不可能在 eventpoll 的红黑树中找到的,所以调用 ep_insert 创建一个 epitem 结构体并 插入到对应的红黑树中。 ep_insert()首先分配一个 epitem 对象,对它初始化 后,把它放入对应的红黑树。此外,这个函数还要作一个操作,就是把当前进 程放入对应文件操作的等待队列。这一步是由下面的代码完成的。 init_poll_funcptr( 。 revents = tfile-f_op-poll(tfile, 函数先调用 init_poll_funcptr

16、 注册了一个回调函数 ep_ptable_queue_proc, 这个函数会在调用 f_op-poll 时被执行。该函数分配一个 epoll 等待队列结点 eppoll_entry:一方面把它挂到文件操作的等待队列中,另一方面把它挂到 epitem 的队列中。此外,它还注册了一个等待队列的回调函数 ep_poll_callback。当文件操作完成,唤醒当前进程之前,会调用 ep_poll_callback(),把 eventpoll 放到 epitem 的完成队列中,并唤醒等待进 程。 如果在执行 f_op-poll 以后,发现被监视的文件操作已经完成了,那么 把它放在完成队列中了,并立即把等待操作的那些进程唤醒。(5)epoll_wait 的实现epoll_wait 的工作是等待文件操作完成并返回。 它的主体是 ep_poll(),该函数在 for 循环中检查 epitem 中有没有已经完成的 事件,有的话就把结果返回。没有的话调用 schedule_timeout

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号