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 ...
随机推荐
- hdu 4123 树形DP+单调队列
http://acm.hust.edu.cn/vjudge/problem/25790 这题基本同poj 3162 要注意mx,mx2,vx,vx2每次都要初始化 #include <iostr ...
- F12 chrome开发者工具
1.Network详解篇 : https://blog.csdn.net/qq_39208536/article/details/79304148 2.sources: js调试篇 http://b ...
- (一)Hybrid app混合开发模式
hybrid app是什么? 这里我们先看一下词条上的定义 Hybrid App:Hybrid App is a mobile application that is coded in both br ...
- js 关系运算符
1.大于 > (小于 效果一样) > //true > //false //false,如果有一个字符串,字符串转换成数值在比较 ' //true,如果两个都是字符串,则比较第 ...
- github设置添加SSH(转载自:破男孩)
注:本文来源于 破男孩 博客(http://www.cnblogs.com/ayseeing/p/3572582.html)能切实解决问题. 很多朋友在用github管理项目的时候,都是直接使用htt ...
- C4C Product Price List的模型中和有效期相关的两个字段
SAP C4C的price list实例可以在工作中心Products,视图Price Lists里看到. 我们点开第二个名为TEST的实例: 我写这篇文章的日期是2018年10月27日, 我现在把这 ...
- 【转载】#402 - Value Equality vs. Reference Equality
When we normally think of "equality",we're thinking of value equality - the idea that the ...
- IOS 公司标示和方向域名
1. 公司标示使用反向域名========================================正向域名 www.baidu.com 用来标示一台网络主机反向域名 cn.itcast.Myd ...
- nodejs的一些概念
上一节我们几乎是扫通http请求和响应的整个闭环,包括请求时候的头信息和服务器返回时候的头信息和状态码等等,这些在node的http中都能获取到,并且有相应都接口组装这些信息和返回它们,同时这些htt ...
- 2017.9.21 HTML学习总结---多媒体播放系统设计
1.题目:整个页面被划分三个子窗口,上面窗口为页面功能提示区, 下左部分为不同类型播放的功能选项,下右部分为播放系统显示播放信息窗口. (1)网页设计框架: <html> <head ...