I/O多路复用之poll

来源:互联网 发布:老外中国快递知乎 编辑:程序博客网 时间:2024/05/22 04:48

I/O多路复用之poll

在select()函数中,对象集合不允许为非法值,而poll()函数对于对象的集合没有限制,其操作与select略有不同。

A、管理对象及事件

structpollfd {

   int  fd;         /* 等待的对象file descriptor */

   short events;     /* 等待的事件requested events*/

   short revents;    /* 返回事件结果returned events*/

};

读事件:POLLIN

写事件:POLLOUT

 

B、通知内核要等谁等什么事件,并等,直到事件发生返回结果

功能:通知内核并等待事件的发生

 参数:

   struct pollfd *fds - 指向管理结构体的首地址

   nfds_t nfds        - 成员数量(监测对象数量)

   int timeout - 超时时间(单位:毫秒)

         0:非阻塞

         合理一个值:时间到即超时

         -1:阻塞(-1的补码即是最大的整数,等待时间最长即为阻塞)

 

返回值:

   -1 :失败

   0 :超时

   >0: 有事件发生

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

 

C、轮询(是谁是什么事情)

for(inti = 0; i < nfds; i++){

   D、测试是谁是什么事情

   if(POLLIN & fds[i].revents){

      E、完成读

      read(fds[i].fd,...);

   }

   if(POLLOUT & fds[i].revents){

      E、完成写

      write(fds[i].fd,...);

   }

}

 

 

 

利用poll()构建一个模拟并发服务器(实现多连接):

#include <stdio.h>#include <string.h>#include <sys/types.h>         #include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <poll.h>#define MAX 1024#define FDMAX 1024int init_server(const char *ipstr, unsigned short port, int backlog){int s = socket(AF_INET, SOCK_STREAM, 0);if(0 > s){perror("socket");return -1;}struct sockaddr_in addr = {.sin_family = AF_INET,.sin_port   = htons(port),.sin_addr = {.s_addr = (NULL == ipstr ? INADDR_ANY : inet_addr(ipstr)),},};memset(addr.sin_zero, 0, sizeof(addr.sin_zero));socklen_t len = sizeof(addr);if(0 > bind(s, (struct sockaddr *)&addr, len)){perror("bind");return -1;}if(0 > listen(s, backlog)){perror("listen");return -1;}return s;}int main(){int s = init_server(NULL, 8888, 1);if(0 > s){return -1;}int i;/*pfd[0]用于监听网络连接,其余用于等待事件的发生。*/struct pollfd pfd[FDMAX];  for(i = 1; i < FDMAX; i++){pfd[i].fd = -1;pfd[i].events = POLLIN;pfd[i].revents= 0;}pfd[0].fd = s;pfd[0].events = POLLIN;pfd[0].revents= 0;while(1){int ret = poll(pfd, FDMAX, -1);if(0 > ret){    //失败perror("select");break;}else if(0 == ret){ //超时printf("Timeout\n");continue;}if(POLLIN & pfd[0].revents){ //监听网络连接请求struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));socklen_t len = sizeof(addr);int rws = accept(s, (struct sockaddr*)&addr, &len);if(0 > rws){perror("accept");return -1;}printf("a nen comming [%s:%u] \n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));/*文件描述符是依次递增的,每个进程运行时系统会为进程打开stdin(0)、stdout(1)、stderr(2)3个文件描述符,之后为socket创建一个文件描述符(3),pfd[0]存储socket创建的描述符,所以请求连接的文件描述符应从pfd[1]开始,请求连接的文件描述符 - socket文件描述符即为请求连接的文件描述符的位置*/int id = rws - s; if(id == FDMAX){close(rws);printf("No more space.\n");}else{pfd[id].fd = rws;}}for(i = 1; i < FDMAX; i++){    //轮询if(POLLIN & pfd[i].revents){ //是否有事件发生char buf[MAX];memset(buf, 0, MAX);int len = read(pfd[i].fd, buf, MAX-1);if(0 >= len){printf("read [%d] fail .\n", pfd[i].fd);close(pfd[i].fd);pfd[i].fd = -1;}else{printf("sock[%d], RECV[%dbytes]:%s\n", pfd[i].fd, len, buf);}}}}close(s);}


0 0
原创粉丝点击