Linux poll详解(2)
导读:Linux,与 select 相比具有如下优点: poll 不要求开发者计算最大文件描述符加 1 的大小; 相比于 select , poll 在处理大数目的文件描述符的时候速度更快; poll 没
Linux
与select相比具有如下优点:- poll不要求开发者计算最大文件描述符加 1 的大小;
- 相比于select,poll在处理大数目的文件描述符的时候速度更快;
- poll没有最大连接数的限制,原因是它是基于链表来存储的;
- 在调用poll函数时,只需要对参数进行一次设置就好了。
我们来看一个具体的例子:
/**
* 演示 poll 函数的用法,poll_server.cpp
* zhangxf 2019.03.16
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <iostream>
#include <string.h>
#include <vector>
#include <errno.h>
//无效fd标记
#define INVALID_FD -1
int main(int argc, char *argv[])
{
//创建一个侦听socket
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd == INVALID_FD)
{
std::cout << "create listen socket error." << std::endl;
return -1;
}
//将侦听socket设置为非阻塞的
int oldSocketFlag = fcntl(listenfd, F_GETFL, 0);
int newSocketFlag = oldSocketFlag | O_NONBLOCK;
if (fcntl(listenfd, F_SETFL, newSocketFlag) == -1)
{
close(listenfd);
std::cout << "set listenfd to nonblock error." << std::endl;
return -1;
}
//复用地址和端口号
int on = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, (char *) &on, sizeof(on));
//初始化服务器地址
struct sockaddr_in bindaddr;
bindaddr.sin_family = AF_INET;
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bindaddr.sin_port = htons(3000);
if (bind(listenfd, (struct sockaddr *) &bindaddr, sizeof(bindaddr)) == -1)
{
std::cout << "bind listen socket error." << std::endl;
close(listenfd);
return -1;
}
//启动侦听
if (listen(listenfd, SOMAXCONN) == -1)
{
std::cout << "listen error." << std::endl;
close(listenfd);
return -1;
}
std::vector<pollfd> fds;
pollfd listen_fd_info;
listen_fd_info.fd = listenfd;
listen_fd_info.events = POLLIN;
listen_fd_info.revents = 0;
fds.push_back(listen_fd_info);
//是否存在无效的fd标志
bool exist_invalid_fd;
int n;
while (true)
{
exist_invalid_fd = false;
n = poll(&fds[0], fds.size(), 1000);
if (n < 0)
{
//被信号中断
if (errno == EINTR)
continue;
//出错,退出
break;
}
else if (n == 0)
{
//超时,继续
continue;
}
for (size_t i = 0; i < fds.size(); ++i)
{
// 事件可读
if (fds[i].revents & POLLIN)
{
if (fds[i].fd == listenfd)
{
//侦听socket,接受新连接
struct sockaddr_in clientaddr;
socklen_t clientaddrlen = sizeof(clientaddr);
//接受客户端连接, 并加入到fds集合中
int clientfd = accept(listenfd, (struct sockaddr *) &clientaddr, &clientaddrlen);
if (clientfd != -1)
{
//将客户端socket设置为非阻塞的
int oldSocketFlag = fcntl(clientfd, F_GETFL, 0);
int newSocketFlag = oldSocketFlag | O_NONBLOCK;
if (fcntl(clientfd, F_SETFL, newSocketFlag) == -1)
{
close(clientfd);
std::cout << "set clientfd to nonblock error." << std::endl;
}
else
{
struct pollfd client_fd_info;
client_fd_info.fd = clientfd;
client_fd_info.events = POLLIN;
client_fd_info.revents = 0;
fds.push_back(client_fd_info);
std::cout << "new client accepted, clientfd: " << clientfd << std::endl;
}
}
}
else
{
//普通clientfd,收取数据
char buf[64] = {0};
int m = recv(fds[i].fd, buf, 64, 0);
if (m <= 0)
{
if (errno != EINTR && errno != EWOULDBLOCK)
{
//出错或对端关闭了连接,关闭对应的clientfd,并设置无效标志位
for (std::vector<pollfd>::iterator iter = fds.begin(); iter != fds.end(); ++iter)
{
if (iter->fd == fds[i].fd)
{
std::cout << "client disconnected, clientfd: " << fds[i].fd << std::endl;
close(fds[i].fd);
iter->fd = INVALID_FD;
exist_invalid_fd = true;
break;
}
}
}
}
else
{
std::cout << "recv from client: " << buf << ", clientfd: " << fds[i].fd << std::endl;
}
}
} else if (fds[i].revents & POLLERR)
{
//TODO: 暂且不处理
}
}// end outer-for-loop
if (exist_invalid_fd)
{
//统一清理无效的fd
for (std::vector<pollfd>::iterator iter = fds.begin(); iter != fds.end();)
{
if (iter->fd == INVALID_FD)
iter = fds.erase(iter);
else
++iter;
}
}
}// end while-loop
//关闭所有socket
for (std::vector<pollfd>::iterator iter = fds.begin(); iter != fds.end(); ++iter)
close(iter->fd);
return 0;
}
相关阅读
-
win10旗舰版一键还原步骤 关于win10系统备份及还原方法
为大家分享win10旗舰版一键还原步骤和关于win10系统备份及还原方法的电脑小知识,一定能解决您的问题的,一起来了解吧! 在备份后担心别人对现在的系统进行随意还原而导致系统文件丢失等
-
win10电脑输入法打字不显示选字框 电脑没有输入法调不出来的原因
今天小编介绍win10电脑输入法打字不显示选字框方面的介绍,下面小编为您详细解答 有的小伙伴可能会遇到以下这样的问题: 中文模式没有选词框示例图 明明已经切换到中文模式了,但是打出
-
优麒麟安装方法详细介绍 优麒麟怎么安装windows系统
一个电脑小知识,为大家介绍优麒麟安装方法详细介绍的教程内容,关于优麒麟安装方法详细介绍 优麒麟怎么安装windows系统,接下来一起来看看吧。 优麒麟是一款非常不错的Linux系统,不过相
-
win7连不上网络怎么办 win7无法连接网络怎么办
相对于大多数人win7无法连接网络怎么办方面的内容,关于win7连不上网络怎么办 win7无法连接网络怎么办,下面小编为您详细解答 今天小编要为大家带来的就是如何解决win7无法连接网络怎么办


