一、poll系统调用
poll和select采用的都是轮询的方式,即每次调用都要扫描整个注册文件描述符的集合,并将其中就绪的文件描述符返回给用户程序,因此他们检测就绪事件的算法的时间复杂度为O(n)。但是poll描述fd集合的方式与select不同,poll使用pollfd结构而不是select的fd_set结构。并且poll没有最大连接数的限制,原因是它是基于链表来存储的。
二、poll原型及参数
#include<poll.h>
int poll(struct pollfd* fds,nfds_t nfds,int timeout);
- fds参数是一个poll结构类型的数组,它指定所有我们感兴趣的文件描述符上发生的可读,可写和异常等事件。
struct pollfd
{
int fd; //文件描述符
short events; //注册的事件
short revents; //实际发生的事件,由内核填充
}
poll支持的事件类型如下表:
通常,应用程序需要根据recv调用的返回值来区别socket上接收到的时有效数据还是对方关闭连接的请求,并作相应的处理。不过,自Linux内核2.6.17开始,GUN为poll系统调用增加了一个POLLRDHUP事件。它在socket上接收到对方关必连接的请求之后触发。这为我们区分上述两种情况提供了一种更简单的方式,但使用POLLRDHUP事件时,我们需要在代码最开始处定义_GUN_SOURCE。
- nfds参数指定被监听事件集合fds的大小,其类型nfds_t的定义如下:
typedef unsigned long int nfds_t;
- timeout参数指定了poll的超时值,单位是毫秒。当timeout返回-1时,poll调用将永远阻塞,直到某个事件发生;当timeout为0时,poll调用将立即返回。
poll调用的返回值含义与select相同。
三、select示例:Client向Server发送消息,Server接收消息并原样发送给Client,Client再把消息输出到终端。
服务器端:
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<poll.h>
#include<sys/ioctl.h>
#include<sys/time.h>
#include<iostream>
#include<vector>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
#define BUFFER_SIZE 1024
#define MAX_FD 1000
struct PACKET_HEAD
{
int length;
};
class Server
{
private:
struct sockaddr_in server_addr;
socklen_t server_addr_len;
int listen_fd; //监听的fd
struct pollfd fds[MAX_FD]