【IO复用-poll】

IO复用-poll系统调用

1.poll API

poll和select类似,都是在超时时间内轮训集合内的就绪文件描述符。原型如下;

#include <poll.h>

int poll(struct pollfd *fds, n_fds_t nfds, int timeout);

//pollfd定义如下
struct pollfd
{
	int fd;				//文件描述符
	short events;		//注册的事件,一次可设置多个,是一系列事件的按位或
	short revents;		//实际发生的事件,由内核填充
};

参数说明:

  1. fds结构体可指定我们感兴趣的文件描述符上发生的可读、写、异常事件;
  2. nfds指定集合fds的大小;
  3. timeout单位为毫秒,设置为-1时,永远阻塞直到有事件就绪;设置为0立即返回;
  4. 返回值和select一致;

2.poll支持的事件类型

poll支持的事件类型如下表:

事件描述是否可作为输入是否可作为输出
POLLIN数据(包含普通和优先数据)可读
POLLRDNORM普通数据可读
POLLBAND优先级带数据可读(Linux不支持)
POLLPRI高优先级数据可读(如TCP带外数据)
POLLOUT数据(包含普通和优先数据)可写
POLLWRNORM普通数据可写
POLLWRBAND优先级带数据可写
POLLRDHUPTCP连接被对方关闭或对方关闭写操作(由GNU引入)
POLLERR错误
POLLHUP挂起(如管道写被关闭后,读端将收到POLLHUP)
POLLNVAL文件描述符没打开

3.poll实例-处理带外数据

#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <poll.h>

#define CLIENT_SIZE 5

int main(int argc, char const *argv[])
{
    if (argc != 3)
    {
        printf("usage: %s <IP> <Port>\n", argv[0]);
        return 1;
    }
    const char *ip = argv[1];
    int port = atoi(argv[2]);
    /*设置sockaddr*/
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &addr.sin_addr);
    addr.sin_port = htons(port);
	/*创建socket*/
    int sock = socket(PF_INET, SOCK_STREAM, 0);
    assert(sock >= 0);
	/*命名socket*/
    int result = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
    assert(result != -1);
	/*进入监听状态*/
    result = listen(sock, 5);
    assert(result != -1);

    struct sockaddr_in client_addr;
    socklen_t client_addrlen = sizeof(client_addr);
	/*等待接收客户端连接*/
    int connfd = accept(sock, (struct sockaddr*)&client_addr, &client_addrlen);
    if (connfd < 0)
    {
        printf("accept failed, errno: %d\n", errno);
        close(sock);
    }
    
    char buf[1024];
    struct pollfd pfd[CLIENT_SIZE];
    
    for (; ; )
    {
    	memset(buf, '\0', sizeof(buf));
	    memset(pfd, 0, sizeof(pfd));
		/*监听connfd的可读和高优先级可读事件*/
	    pfd[0].fd = connfd;
	    pfd[0].events = POLLIN | POLLPRI;
    	/*poll阻塞等待事件就绪*/
        result = poll(pfd, CLIENT_SIZE, -1);

        if (result < 1)
        {
            printf("poll failed!\n");
            break;
        }

        for (int i = 0; i < CLIENT_SIZE; i++)
        {
            if (pfd[i].fd == connfd )
            {
                if (pfd[i].revents & POLLPRI)		//高优先级读数据(带外)
                {
                    result = recv(connfd, buf, sizeof(buf)-1, MSG_OOB);
                    if (result <= 0)
                    {
                        break;
                    }
                    printf("get %d bytes of OOB data: %s", result, buf);
                } 
                else if (pfd[i].revents & POLLIN)	//普通读数据
                {
                    result = recv(connfd, buf, sizeof(buf)-1, 0);
                    if (result <= 0)
                    {
                        break;
                    }
                    printf("get %d bytes of normal data: %s", result, buf);
                } 
                
            }
            
        }
    }
    close(connfd);
    close(sock);
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值