多路复用I/O模型poll() 模型 代码实现

poll()机制和select()机制是相似的,都是对多个描述符进行轮询的方式。

不同的是poll()没有描述符数目的限制。

是通过struct pollfd结构体,对每个描述符进行轮询的

struct pollfd fdarray

{

  int fd;    /*文件描述符*/

  short events; /*表示等待的事件*/

  short revents;/*表示返回事件即实际发生的事件*/

};

每一个pollfd结构体指定了一个被监视的文件描述符,可以传递多个结构体,指示poll()监视多个文件描述符。每个结构体的events域是监视该文件描述符的事件掩码,由用户来设置这个域。revents域是文件描述符的操作结果事件掩码,内核在调用返回时设置这个域。events域中请求的任何事件都可能在revents域中返回。合法的事件如下:

  POLLIN         有数据可读。

  POLLRDNORM       有普通数据可读。

  POLLRDBAND      有优先数据可读。

  POLLPRI         有紧迫数据可读。

  POLLOUT            写数据不会导致阻塞。

  POLLWRNORM       写普通数据不会导致阻塞。

  POLLWRBAND        写优先数据不会导致阻塞。

  POLLMSGSIGPOLL     消息可用。

  此外,revents域中还可能返回下列事件:
  POLLER     指定的文件描述符发生错误。

  POLLHUP   指定的文件描述符挂起事件。

  POLLNVAL  指定的文件描述符非法。

这些事件在events域中无意义,因为它们在合适的时候总是会从revents中返回。

  使用poll()和select()不一样,你不需要显式地请求异常情况报告。
  POLLIN | POLLPRI等价于select()的读事件,POLLOUT |POLLWRBAND等价于select()的写事件。POLLIN等价于POLLRDNORM |POLLRDBAND,而POLLOUT则等价于POLLWRNORM。例如,要同时监视一个文件描述符是否可读和可写,我们可以设置 events为POLLIN |POLLOUT。在poll返回时,我们可以检查revents中的标志,对应于文件描述符请求的events结构体。如果POLLIN事件被设置,则文件描述符可以被读取而不阻塞。如果POLLOUT被设置,则文件描述符可以写入而不导致阻塞。这些标志并不是互斥的:它们可能被同时设置,表示这个文件描述符的读取和写入操作都会正常返回而不阻塞。

  timeout参数指定等待的毫秒数,无论I/O是否准备好,poll都会返回。timeout指定为负数值表示无限超时,使poll()一直挂起直到一个指定事件发生;timeout为0指示poll调用立即返回并列出准备好I/O的文件描述符,但并不等待其它的事件。这种情况下,poll()就像它的名字那样,一旦选举出来,立即返回。

  返回值和错误代码
  成功时,poll()返回结构体中revents域不为0的文件描述符个数;如果在超时前没有任何事件发生,poll()返回0;失败时,poll()返回-1,并设置errno为下列值之一:
  EBADF         一个或多个结构体中指定的文件描述符无效。

  EFAULTfds   指针指向的地址超出进程的地址空间。

  EINTR      请求的事件之前产生一个信号,调用可以重新发起。

  EINVALnfds  参数超出PLIMIT_NOFILE值。

  ENOMEM       可用内存不足,无法完成请求。

例子是从客户端发送信息,在服务器端显示并回射

data.h

 #ifndef DATA_H
#define DATA_H
#include <string.h>
#include <stdio.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <assert.h>
#include <unistd.h>
#define maxn 1100
#define MAXLINE 10
#define LISTEN 10
#define IP "127.0.0.1"
#define PORT 4578
#define BACKLOG 5
#define INFTIM -1
#endif

server.c

 #include "data.h"
static void deal_message(struct pollfd *fd_array,int num);
static void poll_accept(int sockfd); static int init()
{
struct sockaddr_in server_in;
int sockfd;
if((sockfd = socket(AF_INET,SOCK_STREAM,)) == -)
{
fprintf(stderr,"socket fail,error :%s\n",strerror(errno));
return -;
}
bzero(&server_in,sizeof(server_in));
server_in.sin_family = AF_INET;
server_in.sin_port = htons(PORT);
inet_pton(AF_INET,IP,&server_in.sin_addr);
if(bind(sockfd,(struct sockaddr*)&server_in,sizeof(struct sockaddr)) == -)
{
fprintf(stderr,"bind fail,error:%s\n",strerror(errno));
return -;
}
listen(sockfd,BACKLOG);
return sockfd;
} static void poll_accept(int sockfd)
{
struct pollfd fd_array[maxn];
int afd;
int pollfd;
struct sockaddr_in client_in;
bzero(&client_in,sizeof(client_in));
int i = ;
fd_array[].fd = sockfd;
fd_array[].events = POLLIN;
for(i=;i<maxn;i++)
{
fd_array[i].fd = -;
}
int num = ;
int len = sizeof(client_in);
for(;;)
{
pollfd = poll(fd_array,num+,INFTIM); //无限等待
if(pollfd == -)
{
fprintf(stderr,"poll fail,error %s\n",strerror(errno));
return;
}
if(pollfd == )
{
continue;
}
if(fd_array[].revents & POLLIN) //判断实际发生的事件是否为普通或优先级带数据可读
{
if((afd = accept(sockfd,(struct sockaddr*)&client_in,&len)) == -)
{
if(afd == EINTR)
{
continue;
}
else
{
perror("accept error!");
return ;
}
} fprintf(stdout,"accept a new client: %s:%d\n", inet_ntoa(client_in.sin_addr),client_in.sin_port);
for(i =;i<maxn;i++)
{
if(fd_array[i].fd < )
{
fd_array[i].fd = afd;
break;
}
}
if(i == maxn)
{
printf("too many to server!\n");
close(afd);
return ;
}
fd_array[i].events = POLLIN;
if(i > num )
num = i;
--pollfd;
}
deal_message(fd_array,num);
}
} static void deal_message(struct pollfd *fd_array,int num)
{
int i,n;
char buf[maxn+];
char bbuf[maxn];
memset(buf,'\0',sizeof(buf));
memset(bbuf,'\0',sizeof(bbuf));
for(i=;i<=num;i++) //轮询的方式
{
if(fd_array[i].fd < )
continue;
if(fd_array[i].revents&POLLIN)
{
n = read(fd_array[i].fd,bbuf,maxn);
if(n == )
{
close(fd_array[i].fd);
fd_array[i].fd = -;
continue;
}
sprintf(buf,"client %d say %s",i,bbuf);
n += ;
write(STDOUT_FILENO,buf,n);
write(fd_array[i].fd,buf,n);
}
}
}
int main()
{
int sockfd = init();
poll_accept(sockfd);
close(sockfd);
return ;
}

client.c

 #include "data.h"

 static int  init()
{
int sockfd;
struct sockaddr_in client_in;
if((sockfd = socket(AF_INET,SOCK_STREAM,)) == -)
{
fprintf(stderr, "socket fail, errno %s\n",strerror(errno));
return -;
}
bzero(&client_in,sizeof(client_in));
client_in.sin_family = AF_INET;
client_in.sin_port = htons(PORT);
inet_pton(AF_INET,IP,&client_in.sin_addr);
connect(sockfd,(struct sockaddr*)&client_in,sizeof(client_in));
return sockfd;
}
static void poll_conn(int sockfd)
{
struct pollfd fdarray[];
char buf[maxn];
int n;
fdarray[].fd = sockfd;
fdarray[].events = POLLIN;
fdarray[].fd = STDIN_FILENO;
fdarray[].events = POLLIN;
for(;;)
{
printf("please input message:\n");
poll(fdarray,,-);
if(fdarray[].revents & POLLIN)
{
n = read(sockfd,buf,maxn);
if(n == )
{
fprintf(stderr,"server closed.\n");
close(sockfd);
return;
}
write(STDOUT_FILENO,buf,n); }
if(fdarray[].revents & POLLIN)
{
n = read(STDIN_FILENO,buf,maxn);
if(n == )
{
shutdown(sockfd,SHUT_WR);
continue;
}
write(sockfd,buf,n);
}
}
}
int main()
{
int sockfd = init();
poll_conn(sockfd);
close(sockfd);
return ;
}

结果:

多路复用I/O模型poll() 模型 代码实现的更多相关文章

  1. 多路复用I/O模型select() 模型 代码实现

    多路复用I/O:  socket编程之select(),poll(),epoll() 代码: client.c #include <stdio.h> #include <sys/ty ...

  2. 网络编程中select模型和poll模型学习(linux)

    一.概述 并发的网络编程中不管是阻塞式IO还是非阻塞式IO,都不能很好的解决同时处理多个socket的问题.操作系统提供了复用IO模型:select和poll,帮助我们解决了这个问题.这两个函数都能够 ...

  3. 32网络通信之Poll模型

    多路复用并发模型  -- poll #include<poll.h> int  poll(struct pollfd *fds,  unsigned int nfds, int timeo ...

  4. c++ 网络编程(十) LINUX/windows 异步通知I/O模型与重叠I/O模型 附带示例代码

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9662931.html 一.异步IO模型(asynchronous IO) (1)什么是异步I/ ...

  5. FreeMarker之根据模型生成HTML代码

    FreeMarker之根据模型生成HTML代码与FreeMarker根据模型生成Java代码,本质上是一样的,关于生成Java代码可以参考我的这篇文章:FreeMarker之根据模板生成Java代码 ...

  6. raycaster选取捕获obj模型&&选中高亮代码

    目录 raycaster选取捕获obj模型&&选中高亮代码 raycaster关键代码 选中高亮代码 obj整体上色 raycaster选取捕获obj模型&&选中高亮代 ...

  7. iOS 自定义对象及子类及模型套模型的拷贝、归档存储的通用代码

    一.runtime实现通用copy 如果自定义类的子类,模型套模型你真的会copy吗,小心有坑. copy需要自定义类继承NSCopying协议 #import <objc/runtime.h& ...

  8. IO多路复用之select、poll、epoll

    本文转载自IO多路复用之select.poll.epoll 导语 IO多路复用:通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. ...

  9. 精通css 高级web标准解决方案——可视化格式模型-盒模型

    1-盒模型的两种标准: IE :width 和 height属性 是包括padding和border在内的. w3c:width 和 height 属性,就是单纯的内容的宽高,padding 是内容之 ...

随机推荐

  1. BZOJ3172 & 洛谷3966 [Tjoi2013]单词 【fail树】

    3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 4293  Solved: 2083 [Submit][Stat ...

  2. UVA.357 Let Me Count The Ways (DP 完全背包)

    UVA.357 Let Me Count The Ways (DP 完全背包) 题意分析 与UVA.UVA.674 Coin Change是一模一样的题.需要注意的是,此题的数据量较大,dp数组需要使 ...

  3. Mac添加锁屏快捷键

    Mac要想添加锁屏快捷键,必须使用Automator. 1. 打开Automator,创建一个新的服务. 2. 在左侧栏中找到 启动屏幕保护 ,将其拖曳到右侧窗口内,并且修改 服务收到改为" ...

  4. pushViewController:animated:的问题

    1.在AppDelegate.m中: 2.在SecondViewController.h中: 3.在FirstViewController.m中: 4.在SecondViewController.m中 ...

  5. ConvexScore

    题目描述 You are given N points (xi,yi) located on a two-dimensional plane. Consider a subset S of the N ...

  6. js中的true和false

    1.false undefined.NaN.0.null和空字符串''均被视为false 2.true 除上述以外的其它情况一律被视作true

  7. pandas中DataFrame使用

    切片选择 #显示第一行数据print(df.head(1)) #显示倒数三行数据 print(df.tail(3)) loc  df.loc[row_index,col_index]  注意loc是根 ...

  8. 【shell】shell编程(六)-shell函数的应用

    linux shell 可以用户定义函数,然后在shell脚本中可以随便调用. shell中函数的定义格式如下: [ function ] funname [()] { action; [return ...

  9. Python阶段复习 - part 3 - Python函数

    利用函数打印9*9乘法表 def cheng(num): for i in range(1,num+1): for j in range(1,i+1): print('{0} * {1} = {2}' ...

  10. in_device结构和in_ifaddr结构

    /* ip配置块 */ struct in_device { /* 二层设备 */ struct net_device *dev; /* 引用计数 */ atomic_t refcnt; /* 是否正 ...