一 基础知识
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
其中参数fds指向一个结构体数组的第0个元素的指针,每个数组元素都是一个struct pollfd结构,用于指定测试某个给定的fd的条件;参数nfds用来指定第一个参数数组元素个数;timeout用于指定等待的毫秒数,无论I/O是否准备好,poll都会返回,如果timeout赋值为‒1则表示永远等待,直到事件发生;如果赋值为0,则表示立即返回;如果赋值为大于0的数,则表示等待指定数目的毫秒数。如果函数执行成功,则返回结构体中revents域不为0的文件描述符个数,如果在超时前没有任何事件发生,则函数返回0;如果函数执行失败,则返回‒1,并设置errno为下列值之一:
· EBADF:一个或多个结构体中指定的文件描述符无效。
· EFAULT:fds指针指向的地址超出进程的地址空间。
· EINTR:请求的事件之前产生一个信号,调用可以重新发起。
· EINVAL:nfds参数超出PLIMIT_NOFILE值。
· ENOMEM:可用内存不足,无法完成请求。
结构体pollfd定义如下:
struct pollfd{
int fd; //文件描述符
short events; //等待的事件
short revents; //实际发生的事件
};
其中字段fd表示每一个pollfd结构体指定了一个被监视的文件描述符,可以传递多个结构体,指示poll监视多个文件描述符;events指定监测fd的事件(输入、输出、错误),每一个事件有多个取值,如图所示。
测试代码:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
#include <sys/select.h>
// #include <sys/epoll.h>
#include <poll.h>
#include <errno.h>
#define DEBUG_INFO(format, ...) printf("%s:%d -- " format "\n", __func__, __LINE__,##__VA_ARGS__)
#define BUFFER_SIZE 1024
void set_nonblock(int fd){
int flag = fcntl(fd,F_GETFL);
if(flag == -1){
perror("set_nonblock");
exit(1);
}
flag |= O_NONBLOCK;
if(fcntl(fd,F_SETFL, flag) < 0){
perror("fcntl");
exit(1);
}
}
#define MAX_EVENT_NUMBER 100
struct pollfd pollfds[MAX_EVENT_NUMBER];
char buf[BUFFER_SIZE];
int init_fds(struct pollfd*fds,int count){
for(int i = 0; i < count; i++){
fds[i].fd = -1;
fds[i].events = 0;
fds[i].revents = 0;
}
}
int insert_fd(struct pollfd*fds,int count,int fd,int events){
for(int i = 0; i < count; i++){
if(fds[i].fd == -1){
fds[i].fd = fd;
fds[i].events = events;
fds[i].revents = 0;
DEBUG_INFO("insert ok,fd = %d,i = %d",fd,i);
return 0;
}
}
DEBUG_INFO("insert error");
return -1;
}
int delete_fd(struct pollfd*fds,int count,int fd){
for(int i = 0; i < count; i++){
if(fds[i].fd == fd){
fds[i].fd = -1;
fds[i].events = 0;
fds[i].revents = 0;
DEBUG_INFO("delete ok,fd = %d,i = %d",fd,i);
return 0;
}
}
DEBUG_INFO("delete error");
return -1;
}
void test_01(){
int listenfd;
int on = 1;
struct sockaddr_in server_addr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,&on,sizeof(on)) < 0){
perror("setsockopt");
exit(-1);
}
DEBUG_INFO("begin bing");
server_addr.sin_port = htons(9878);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
if(bind(listenfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){
perror("bind");
exit(0);
}
listen(listenfd,5);
set_nonblock(listenfd);
init_fds(pollfds,MAX_EVENT_NUMBER);
insert_fd(pollfds,MAX_EVENT_NUMBER,listenfd,POLLIN);
DEBUG_INFO("poll");
int fd_count = 1;
while(1){
int ret = poll(pollfds,MAX_EVENT_NUMBER,-1 );
if(ret == -1){
perror("poll");
exit(0);
}
for(int i = 0;i < MAX_EVENT_NUMBER;i++){
if(pollfds[i].fd == -1){
continue;
}
if(!(pollfds[i].revents & POLLIN)){
continue;
}
if(pollfds[i].fd == listenfd){
struct sockaddr_in client;
socklen_t addrlen = sizeof(client);
int clientfd = accept(listenfd, (struct sockaddr *)&client,&addrlen);
if(ret == -1){
exit(1);
}
DEBUG_INFO("new client = %d",clientfd);
insert_fd(pollfds,MAX_EVENT_NUMBER,clientfd,POLLIN);
continue;
}
if(pollfds[i].revents & POLLIN){
bzero(buf, sizeof(buf)/sizeof(buf[0]));
ret = recv(pollfds[i].fd,buf,sizeof(buf)/sizeof(buf[0]),0);
if(ret > 0){
DEBUG_INFO("ret = %d,buf = %s,i = %d,fd = %d",ret,buf,i,pollfds[i].fd);
send(pollfds[i].fd,buf,ret,0);
continue;
}
//close
if(ret == 0){
DEBUG_INFO("close i = %d fd = %d",i,pollfds[i].fd);
delete_fd(pollfds,MAX_EVENT_NUMBER,pollfds[i].fd);
continue;
}
if(ret == -1){
//暂时不判断
perror("recv");
exit(1);
}
}
}
}
exit(0);
}
int main(int argc, char **argv)
{
test_01();
}
测试
创建两个客户端:
然后反复连接,断开,然后发送数据,就会接收到刚刚发出去的数据。
test_01:125 -- ret = 11,buf = hello world,i = 1,fd = 6
test_01:131 -- close i = 2 fd = 8
delete_fd:61 -- delete ok,fd = 8,i = 2
test_01:117 -- new client = 9
insert_fd:48 -- insert ok,fd = 9,i = 2
test_01:131 -- close i = 2 fd = 9
delete_fd:61 -- delete ok,fd = 9,i = 2
test_01:117 -- new client = 10
insert_fd:48 -- insert ok,fd = 10,i = 2
test_01:131 -- close i = 2 fd = 10
delete_fd:61 -- delete ok,fd = 10,i = 2
test_01:117 -- new client = 11
insert_fd:48 -- insert ok,fd = 11,i = 2
test_01:131 -- close i = 2 fd = 11
delete_fd:61 -- delete ok,fd = 11,i = 2
test_01:117 -- new client = 12
insert_fd:48 -- insert ok,fd = 12,i = 2
test_01:131 -- close i = 2 fd = 12
delete_fd:61 -- delete ok,fd = 12,i = 2
test_01:117 -- new client = 13
insert_fd:48 -- insert ok,fd = 13,i = 2
test_01:131 -- close i = 2 fd = 13
delete_fd:61 -- delete ok,fd = 13,i = 2
test_01:117 -- new client = 14
insert_fd:48 -- insert ok,fd = 14,i = 2
test_01:125 -- ret = 4,buf = gulu,i = 2,fd = 14
test_01:125 -- ret = 4,buf = gulu,i = 2,fd = 14
test_01:125 -- ret = 4,buf = gulu,i = 2,fd = 14
test_01:125 -- ret = 4,buf = gulu,i = 2,fd = 14
小结
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)