linux poll用法
相对于select来说,poll 也是在指定时间内论询一定数量的文件描述符,来测试其中是否有就绪的,不过,poll 提供了一个易用的方法,来实现 i/o 复用。
声明如下:
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
其中,struct pollfd 定义为:
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
fd 为文件描述符,events 告诉poll 监听fd 上哪些事件,它是一系列事件按位或。revents 由内核修改,来通知应用程序fd 上实际上发生了哪些事件。
nfds 为监听事件集合fds的大小
timeout 为poll的超时时间,单位毫秒。timeout 为-1时,poll永远阻塞,直到有事件发生。timeout为0时,poll立即返回。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <errno.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h> #include <map>
#include <string> using namespace std; #define BUFSIZE 10
#define CLIENTSIZE 100 int createSocket()
{
struct sockaddr_in servaddr;
int listenfd = -1; if (-1 == (listenfd = socket(PF_INET, SOCK_STREAM, 0)))
{
fprintf(stderr, "socket: %d, %s\n", errno, strerror(errno));
exit(1);
} int reuseaddr = 1;
if (-1 == setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)))
{
fprintf(stderr, "setsockopt: %d, %s\n", errno, strerror(errno));
exit(1);
} memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = PF_INET;
servaddr.sin_port = htons(8008);
inet_pton(PF_INET, "0.0.0.0", &servaddr.sin_addr); if (-1 == bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)))
{
fprintf(stderr, "bind: %d, %s\n", errno, strerror(errno));
exit(1);
} if (-1 == listen(listenfd, 5))
{
fprintf(stderr, "listen: %d, %s\n", errno, strerror(errno));
exit(1);
} return listenfd;
} int setnoblock(int fd)
{
int oldopt = fcntl(fd, F_GETFL);
int newopt = oldopt | O_NONBLOCK;
fcntl(fd, F_SETFL, newopt);
return oldopt;
} int main()
{
struct pollfd fds[CLIENTSIZE];
int listenfd = createSocket(); map<int, string> mapdata; fds[0].fd = listenfd;
fds[0].events = POLLIN | POLLERR;
fds[0].revents = 0;
int conncount = 0; while (1)
{
int ret = poll(fds, conncount + 1, -1);
if (ret < 0)
{
fprintf(stderr, "poll: %d, %s\n", errno, strerror(errno));
exit(1);
} for (int i = 0; i < conncount + 1; i++)
{
// 客户端关闭,或者错误。错误的原因是由于客户端关闭导致的,这里一并处理
if ((fds[i].revents & POLLRDHUP) || (fds[i].revents & POLLERR))
{
int fd = fds[i].fd;
fds[i] = fds[conncount];
i--;
conncount--;
mapdata.erase(fd);
close(fd);
printf("delete connection: %d\n", fd);
}
// 新的连接
else if ((fds[i].fd == listenfd) && (fds[i].revents & POLLIN))
{
struct sockaddr_in client;
socklen_t lenaddr = sizeof(client);
int conn = -1; if (-1 == (conn = accept(listenfd, (struct sockaddr*)&client, &lenaddr)))
{
fprintf(stderr, "accept: %d, %s\n", errno, strerror(errno));
exit(1);
}
printf("get connection %d from %s:%d\n", conn, inet_ntoa(client.sin_addr), client.sin_port);
conncount++;
setnoblock(conn);
fds[conncount].fd = conn;
fds[conncount].events = POLLIN | POLLRDHUP | POLLERR;
fds[conncount].revents = 0;
}
// 有可读数据
else if (fds[i].revents & POLLIN)
{
char buf[BUFSIZE] = {0}; int lenrecv = recv(fds[i].fd, buf, BUFSIZE-1, 0);
if (lenrecv > 0)
{
mapdata[fds[i].fd] = buf;
fds[i].events &= (~POLLIN);
fds[i].events |= POLLOUT;
}
else if (lenrecv == 0)
{
printf("------- client %d exit (not print) --------\n", fds[i].fd);
}
else
{
fprintf(stderr, "recv: %d, %s\n", errno, strerror(errno));
exit(1);
}
}
// 可写数据
else if (fds[i].revents & POLLOUT)
{
if (send(fds[i].fd, mapdata[fds[i].fd].c_str(), mapdata[fds[i].fd].size(), 0) < 0)
{
if (ECONNRESET == errno)
{
continue;
}
fprintf(stderr, "send: %d, %s\n", errno, strerror(errno));
exit(1);
}
fds[i].events &= (~POLLOUT);
fds[i].events |= POLLIN;
}
}
}
}
linux poll用法的更多相关文章
- linux curl用法详解
linux curl用法详解 curl的应用方式,一是可以直接通过命令行工具,另一种是利用libcurl库做上层的开发.本篇主要总结一下命令行工具的http相关的应用, 尤其是http下载方面 ...
- [转载]expect spawn、linux expect 用法小记
原文地址:expect spawn.linux expect 用法小记作者:悟世 使用expect实现自动登录的脚本,网上有很多,可是都没有一个明白的说明,初学者一般都是照抄.收藏.可是为什么要这么写 ...
- Linux poll机制
1.用户空间调用(参考 poll(2) - Linux man page) int poll(struct pollfd *fds, nfds_t nfds, int timeout); it wai ...
- [转帖]linux lsof 用法简介
linux lsof 用法简介 https://www.cnblogs.com/saneri/p/5333333.html 1.简介: lsof(list open files)是一个列出当前系统打开 ...
- linux poll 和 select
使用非阻塞 I/O 的应用程序常常使用 poll, select, 和 epoll 系统调用. poll, select 和 epoll 本质上有相同的功能: 每个允许一个进程来决定它是否可读或者写一 ...
- Linux find 用法示例
Linux中find常见用法示例 ·find path -option [ -print ] [ -exec -ok command ] {} \; find命令的参数 ...
- linux poll 学习
一.poll介绍 函数原型: #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout); struc ...
- linux gksu用法
apt-get install gksu gksu是linux下图形化的su/sudo工具 sudo 用来执行命令行(CLI)程序 gksu 用来执行图形的(GUI)程序 GUI = Graphica ...
- linux exec用法总结
Linux中exec的用法总结 先总结一个表: exec命令 作用 exec ls 在shell中执行ls,ls结果显示结束后不返回原来的的目录中,而是/(根目录) exec <file 将fi ...
随机推荐
- 一张图看懂offsetX, clientX, pageX, screenX的区别
1.具体含义见下图1 2.浏览器的兼任情况
- 跨平台图表控件TeeChart使用教程:导入XML数据
TeeChart的最新版中包含了一个自动加载XML数据的新组件.这个组件的名字叫做TTeeXMLSource,用户可以在TeeXML.pas unit中找到这个组件. 加载XML图表所需的最小属性是& ...
- iphone 微信下浏览器中数字去除下划线
在开发iphone应用程序的时候,safari下手机号码默认是有下划线的,通过下面的方法就可以去掉: <meta name="format-detection" conten ...
- MVC 默认路由 Areas
1.使用重名controller 在asp.net mvc2以后的版本里面,有了area(区域的概念),这为我们开发中提供了不少方便的地方,但是很不凑巧,若是存在多个重名的controller就会发生 ...
- struts2 中使用DMI(动态调用方法)方式配置action
1.使用 "!"方式,即 action名称 ! 方法名称 struts.xml 配置 <package name="user" namespace=&qu ...
- SharePoint 2010 VS.net 2010 断点调试
当IE打开之后 1在代码的项目:右键:重新生成 2用WSPBuilder的Copy to GAC 3IE要调试的页面:刷新 4用WSPBuilder的Attach to IIS Worker Proc ...
- [转]Android中Spinner下拉列表(使用ArrayAdapter和自定义Adapter实现)
今天学习了Spinner组件,使用Spinner相当于从下拉列表中选择项目,下面演示一下Spinner的使用(分别使用ArrayAdapter和自定义Adapter实现) (一):使用ArrayAda ...
- NFS笔记(二)NFS服务器配置实例
一.NFS服务器配置实例实验拓扑 二.实验要求及环境 2.1实验环境 NFS服务器 IP:192.168.8.5环境:[root@server7 ~]# uname -aLinux server7.c ...
- 笨办法学Python(二十四)
习题 24: 更多练习 你离这本书第一部分的结尾已经不远了,你应该已经具备了足够的 Python 基础知识,可以继续学习一些编程的原理了,但你应该做更多的练习.这个练习的内容比较长,它的目的是锻炼你的 ...
- IOS http协议 总结
HTTP协议1.面试题常见:聊一下HTTP协议(协议的完整的通信过程) ============================================================ 一.一 ...