文档章节

poll 示例

for。
 for。
发布于 2016/07/04 22:28
字数 418
阅读 48
收藏 1

poll 使用的结构体如下

struct pollfd {
    int   fd;         /* file descriptor */
    short events;     /* requested events */
    short revents;    /* returned events */
};

需要使用该结构体数组对文件描述符进行注册,poll 通过该数组返回结果。事件就绪时需要遍历所有注册的文件描述符。

源码

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

#define SERV_PORT   9000
#define LISTENQ     10
#define OPEN_MAX    1024
#define MAXLINE     1024

int main(int argc, char **argv)
{
    int         listenfd, connfd, sockfd;
    int         nready, maxi, i, n;
    socklen_t   clilen;
    struct sockaddr_in  cliaddr, servaddr;
    struct pollfd       client[OPEN_MAX];
    char        buf[MAXLINE];

    /* 创建 socket */
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    /* 绑定地址到 socket */
    if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    /* 转为监听 socket */
    if (listen(listenfd, LISTENQ)) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    client[0].fd = listenfd;
    client[0].events = POLLRDNORM;
    for (i = 1; i < OPEN_MAX; ++i) {
        client[i].fd = -1;
    }

    maxi = 0;

    for ( ; ; ) {
        nready = poll(client, maxi + 1, 1000);
        if (nready < 0) {
            perror("poll");
            exit(EXIT_FAILURE);
        } else if (nready == 0) {
            fprintf(stderr, "timeout\n");
        }

        if (client[0].revents & POLLRDNORM) {
            /* 监听 socket 上读事件 */
            clilen = sizeof(cliaddr);
            connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
            if (connfd == -1) {
                perror("accept");
                continue;
            }
            fprintf(stderr, "accept %d\n", connfd);

            /* 从client 数组中找到一个空位 */
            for (i = 1; i < OPEN_MAX; i++) {
                if (client[i].fd < 0) {
                    client[i].fd = connfd;
                    break;
                }
            }

            if (i == OPEN_MAX) {
                fprintf(stderr, "too many clients");
                exit(EXIT_FAILURE);
            }

            client[i].events = POLLRDNORM;
            if (i > maxi) {
                maxi = i;
            }

            if (--nready <= 0) {
                continue;
            }
        }

        /* 剩余的文件描述符 */
        for (i = 1; i <= maxi; ++i) {
            if ((sockfd = client[i].fd) < 0)
                continue;
            if (client[i].revents & (POLLRDNORM | POLLERR)) {
                /* 读事件 */
                if ((n = read(sockfd, buf, MAXLINE)) < 0) {
                    if (errno == ECONNRESET) {
                        close(sockfd);
                        client[i].fd = -1;
                    } else {
                        fprintf(stderr, "read error");
                    }
                } else if (n == 0) {
                    /* 客户端关闭连接 */
                    close(sockfd);
                    client[i].fd = -1;
                } else {
                    /* 回写数据到客户端 */
                    write(sockfd, buf, n);
                }

                if (--nready <= 0) {
                    break;
                }
            }
        }
    }

    return 0;
}

参考资料

《UNP》

© 著作权归作者所有

共有 人打赏支持
for。

for。

粉丝 84
博文 47
码字总数 18257
作品 0
深圳
程序员
Linux下I/O多路复用select, poll, epoll 三种模型的Python使用

Linux下I/O多路复用select, poll, epoll 三种模型 select, poll, epoll本质上都是同步的I/O,因为它们都是在读写事件就绪后自己负责进行读写,这个读写的过程是阻塞的。 select, poll, epol...

首席贱人
2016/05/22
880
0
[Linux应用]通过sysfs在用户空间使用GPIO

ERREXIT("poll value"); / get value / ret = lseek(fd, 0, SEEK_SET); if(ret < 0) ERREXIT("lseek value"); ret = read(fd, buf, 2); buf[1] = '0'; printf("read ret = %d, value = %sn",......

zjy900507
05/11
0
0
Bittwiste - pcap 编辑工具

Bittwiste - pcap 编辑工具 It event poll2016-06-09185 阅读 工具编辑 Bittwiste的官方开源地址: bittwist.sourceforge.net 。软件提供了三个版本,分别针对FreeBSD、Linux、Windows系统。...

It event poll
2016/06/09
0
0
高性能Web服务器Nginx的配置与部署研究(8)核心模块之事件模块

本文来自:CSDN博客专栏《Nginx高性能Web服务器》 及Poechant技术博客,转载请注明出处。 一、事件模块的作用是什么? 用来设置Nginx处理链接请求。 二、相关指令 1. accept_mutex 含义:设置...

晨曦之光
2012/04/24
87
0
【select模块】select IO多路复用和select实现FTP

select是全平台通用的IO多路复用模块。最大连接数:1024。 poll和epoll没有最大连接数限制,但只能用在linux平台。 selectors是再封装模块,推荐使用。下篇会讨论。 select.(rlist, wlist, ...

等你的破船
07/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

初级开发-编程题

` public static void main(String[] args) { System.out.println(changeStrToUpperCase("user_name_abc")); System.out.println(changeStrToLowerCase(changeStrToUpperCase("user_name_abc......

小池仔
25分钟前
0
0
现场看路演了!

HiBlock
昨天
4
0
Rabbit MQ基本概念介绍

RabbitMQ介绍 • RabbitMQ是一个消息中间件,是一个很好用的消息队列框架。 • ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。Connection是RabbitMQ的s...

寰宇01
昨天
4
0
官方精简版Windows10:微软自己都看不过去了

微软宣布,该公司正在寻求解决方案,以减轻企业客户的Windows 10规模。该公司声称,企业客户下载整个Windows 10文件以更新设备既费钱又费时。 微软宣布,该公司正在寻求解决方案,以减轻企业...

linux-tao
昨天
4
0
TypeScript基础入门之JSX(二)

转发 TypeScript基础入门之JSX(二) 属性类型检查 键入检查属性的第一步是确定元素属性类型。 内在元素和基于价值的元素之间略有不同。 对于内部元素,它是JSX.IntrinsicElements上的属性类型...

durban
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部