select&epoll问题

如果select或epoll检测到描述符可读,之后并不读取数据,那么下次调用select或epoll_wait时是否还会触发描述符可读事件

1. select

select函数结论:只要文件描述符可读或可写,select就会一直检测到事件并返回
select测试:

#include <sys/socket.h>
#include <string.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

 
#define TRUE  1
#define FALSE 0
 
int main(int argc, char *argv[])
{
    
    
    int i, len, rc;
    int listen_sd, new_sd = 0;
    char buffer[80];
    struct sockaddr_in server_addr;
    fd_set master_set;
 
    // Listen
    listen_sd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sd < 0)
    {
    
    
        perror("socket() failed");
        exit(-1);
    }
	
    // Bind
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(atoi(argv[1]));
    rc = bind(listen_sd, (struct sockaddr *) &server_addr, sizeof(server_addr));
    if (rc < 0)
    {
    
    
        perror("bind() failed\n");
        close(listen_sd);
        exit(-1);
    }
 
    // Listen
    rc = listen(listen_sd, 32);
    if (rc < 0)
    {
    
    
        perror("listen() failed\n");
        close(listen_sd);
        exit(-1);
    }
	
	new_sd = accept(listen_sd, NULL, NULL);
	
    // Intialize sd set
    FD_ZERO(&master_set);
    FD_SET(new_sd, &master_set);
 
    do
    {
    
    
        printf("Waiting on select()...\n");
        rc = select(new_sd + 1, &master_set, NULL, NULL, NULL);
        if (rc < 0)
        {
    
    
            perror("  select() failed\n");
            break;
        }
        if (rc == 0)
        {
    
    
            printf("  select() timed out. End program.\n");
            break;
        }
		
		printf("recv select\n");
		if (FD_ISSET(new_sd, &master_set))
		{
    
    
		#if 0
			rc = recv(new_sd, buffer, sizeof(buffer), 0);
			if (rc < 0)
			{
    
    
				perror("  recv() failed\n");
				break;
			}

			// The connection has been closed by the client
			if (rc == 0)
			{
    
    
				printf("  Connection closed\n");
				break;
			}
			printf("recv:%s\n", buffer);
		#else
			printf("do nothing...\n");
		#endif
		}
    }
    while(1);
 
    return 0;
}
结果为会一直触发
Waiting on select()...
recv select
do nothing...
Waiting on select()...
recv select
do nothing...
Waiting on select()...
recv select
do nothing...
Waiting on select()...
recv select
do nothing...
Waiting on select()...
recv select
do nothing...
Waiting on select()...
recv select

2. epoll

说明: epoll 对文件描述符的操作有两种模式:LT(level trigger)和 ET(edge trigger)。LT 模式是默认模式,LT 模式与 ET 模式的区别如下:
  LT模式: 电平触发,当 epoll_wait 检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用 epoll_wait 时,会再次响应应用程序并通知此事件。
  ET模式: 边沿触发,当 epoll_wait 检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用 epoll_wait 时,不会再次响应应用程序并通知此事件。

epoll详解:https://blog.csdn.net/qq_19923217/article/details/81943705

测试结论:epoll默认模式(LT模式)时,若检测到描述符可读后不读取出数据,那么下次调用epoll_wait还会触发可读事件
ET模式模式时,若检测到描述符可读后不读取出数据,下次调用epoll_wait不会在触发可读事件
**注:**两种模式的测试代码仅ev.events = EPOLLIN | EPOLLET;此行不同,LT模式删去EPOLLET即可

#define SERVER_PORT 8888
#define MAXDATASIZE 100  
#define SERVER_IP "192.168.1.15" 

int main() 
{
    
     
    int sockfd, numbytes; 
    char buf[MAXDATASIZE]; 
    struct sockaddr_in server_addr; 

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
	{
    
     
        perror("socket"); 
        exit(1); 
    }

    server_addr.sin_family = AF_INET; 
    server_addr.sin_port = htons(SERVER_PORT); 
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP); 
    bzero(&(server_addr.sin_zero),sizeof(server_addr.sin_zero)); 
    if (connect(sockfd, (struct sockaddr *)&server_addr,sizeof(struct sockaddr_in)) == -1)
	{
    
    
         perror("connect error"); 
         exit(1);
    } 
	
	struct epoll_event ev;
	struct epoll_event events[10];
	int epollfd = epoll_create(10);
	ev.events = EPOLLIN | EPOLLET;
	ev.data.fd = sockfd;
	epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev);
    
	while(1) 
	{
    
     
		printf("epoll wait...\n");
		int ret = epoll_wait(epollfd, events, 10, -1);
		printf("ret: %d\n", ret);
	}  
	close(sockfd); 
	return 0;
}

猜你喜欢

转载自blog.csdn.net/chengcheng1024/article/details/114144137