文档章节

poll 示例

for_
 for_
发布于 2016/07/04 22:28
字数 418
阅读 64
收藏 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_

粉丝 92
博文 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
1K
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
2018/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
113
0
【select模块】select IO多路复用和select实现FTP

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

等你的破船
2018/07/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

uni app 零基础小白到项目实战

$emit 子组件传给父组件$ref 父组件操作子组件 公用模板 uni-app全局变量的几种实现方法 const websiteUrl = 'http'const now = Date.now || function() { return new Date().getTime......

达达前端小酒馆
27分钟前
7
0
Tomcat是如何实现异步Servlet的

前言 通过我之前的Tomcat系列文章,相信看我博客的同学对Tomcat应该有一个比较清晰的了解了,在前几篇博客我们讨论了Tomcat在SpringBoot框架中是如何启动的,讨论了Tomcat的内部组件是如何设...

木木匠
51分钟前
28
0
mysql中间件分享(Mysql-prxoy,Atlas,DBProxy,Amoeba,cobar,TDDL)

hello 各位小伙伴大家好,我是小栈君,这期我们分享关于mysql中间件的研究,也就是数据层的读写分离和负载均衡,希望能够在实际的应用中能够帮助到各位小伙伴。 下期我们将继续分享go语言的系...

IT干货栈
今天
10
0
OSChina 周一乱弹 —— 人生,还真是到处是意外

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @这次装个文艺青年吧 :#今日歌曲推荐# 分享lil peep的单曲《High School》 《High School》- lil peep 手机党少年们想听歌,请使劲儿戳(这里...

小小编辑
今天
892
13
Spring使用ThreadPoolTaskExecutor自定义线程池及实现异步调用

多线程一直是工作或面试过程中的高频知识点,今天给大家分享一下使用 ThreadPoolTaskExecutor 来自定义线程池和实现异步调用多线程。 一、ThreadPoolTaskExecutor 本文采用 Executors 的工厂...

CREATE_17
今天
12
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部