高级I/O

高级I/O

 

一、主要函数:select,poll,epoll,readv,writev

二、

1 select,poll,epoll 的作用就是监视多个I/O. 如果不希望被某些信号打断可用pselect,ppoll.

2 select

每次用select 之前都要构造一下。当监视读一个写端关闭的进程时,select 总是能返回。

 

3 poll

POLLIN 读,POLLOUT

struct pollfd fds[2];

nfds = 2;

fds[0].fd = 0;

fds[0].events = POLLIN;

fds[1].fd = fd[0];

fds[1].events = POLLIN;

ret = poll(fds, 2, -1);//-1 表示永远等待

......

如果第三个参数用了timeout ,那么当超时的时候返回0.

每执行一次pollfds 都要被拷到内核处理,所以selectpoll 效率低。

4 epoll

第一步:epoll_create();

epfd=epoll_create(1), 创建一个event poll, 返回一个指向这个池的文件描述符,它里面的参数只要大于0 就行,如果为-1 的话就会死掉。

第二步:epoll_ctl();

epoll_ctl(epfd,EPOLL_CTL_ADD,fd[i][0],&event); EPOLL_CTL_ADD 添加关心的事件到池中

第三步:epoll_wait();

struct epoll_event event[2];

while(1)

{

    epoll_wait(epfd,event,2,-1);// 最后一个参数用-1 表示永远等待

    ....// 如果返回来的不只2 两个,通过while 循环下一次过来再取

}

5 readv,writev 分散读,聚集写

ssize_t readv(int fd, const struct iovec *iov, int iovcnt)

第二个参数iov 和第三个参数iovcnt 组成一个结构体数组iov[iovcnt];

int main(void)

{

    int fd, i;

    char *ptr[3] = {

    struct iovec iov[3];

    for (i = 0; i < 3; i++) {

        iov[i].iov_base = ptr[i];

        iov[i].iov_len = 6;

    }

    writev(1, iov, 3);

    exit(0);

}

6 SIGIO 信号  F_SETOWN, O_ASYNC

1)fcntl(fd,F_SETOWN,getpid())

2)fcntl(fd,F_SETFL,ret|O_ASYNC)  其中ret=fcntl(fd,F_GETFL)

3)sigaction(SIGIO,&act,NULL)

三、例程

1 、/*select.c*//*监视多个I/O*/
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void con_fds(fd_set *set, int fd)
{
    FD_ZERO(set);
    FD_SET(0, set);    
    FD_SET(fd, set);    
}

int main(void)
{
    int ret, nfds, cnt;
    char buf[88];
    fd_set readfds;
    int fd[2];
    pid_t pid;
    
    ret = pipe(fd);
    if (ret == -1) {
        perror("pipe");
        exit(1);
    }
    
    pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(1);
    }
    if (pid == 0) {
        close(fd[0]);
        srand(time(NULL));
        sleep(rand()%5 + 5);
        write(fd[1], "Hello!", 6);
        //while(1)
            sleep(1);
        close(fd[1]);
        exit(0);
    }

    close(fd[1]);

    nfds = fd[0]+1;

    while (1) {
        con_fds(&readfds, fd[0]);
        ret = select(nfds, &readfds, NULL,
            NULL, NULL);
        if (ret > 0) {
            printf("ret=%d/n", ret);
            if (FD_ISSET(0, &readfds)) {
                cnt = read(0, buf, 88);
                buf[cnt] = '/0';
                printf("%s/n", buf);
            }
            if (FD_ISSET(fd[0], &readfds)) {
                cnt = read(fd[0], buf, 88);
                buf[cnt] = '/0';
                printf("%s/n", buf);
            }
        }
        if (ret == -1) {
            perror("select");
            exit(1);
        }
    }
    
}
/*1、本程序有两个关心的fd:   0和fd[0],监视这两个I/O,哪个有数据就了都要读
  2、select:在每次调用select之前要构造,con_fds,构造所关心的fd。
  3、声明一个描述符集之后,必须用FD_ZERO清除其所有们,然后在其中设置我们关心的各个位。
  4、select的第一个参数是所关心的fd中"最大的描述符加1".一般我们不关心后三个参数,
所以都置为NULL
*/

2

/*poll.c*/
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>


int main(void)
{
    int ret, nfds, cnt;
    char buf[88];
    int fd[2];
    pid_t pid;
    struct pollfd fds[2];
    
    ret = pipe(fd);
    if (ret == -1) {
        perror("pipe");
        exit(1);
    }
    
    pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(1);
    }
    if (pid == 0) {
        close(fd[0]);
        srand(time(NULL));
        sleep(rand()%5 + 5);
        write(fd[1], "Hello!", 6);
        while(1)
            sleep(1);
        close(fd[1]);
        exit(0);
    }

    close(fd[1]);

    nfds = 2;//2是所关心描述符的个数
    fds[0].fd = 0;
    fds[0].events = POLLIN;//关心输入,也就是关心"写"
    fds[1].fd = fd[0];
    fds[1].events = POLLIN;
    
    while (1) {
        ret = poll(fds, 2, -1);
        if (ret > 0) {
            printf("ret=%d/n", ret);
            if (fds[0].revents & POLLIN) {
                cnt = read(fds[0].fd,
                    buf, 88);
                buf[cnt] = '/0';
                printf("%s/n", buf);
            }
            if (fds[1].revents & POLLIN) {
                cnt = read(fds[1].fd,
                    buf, 88);
                buf[cnt] = '/0';
                printf("%s/n", buf);
            }
        }
        if (ret == -1) {
            perror("poll");
            exit(1);
        }
    }
    
}

/*1、poll比select略胜一点,不用在每次调用之前都构造一次
  2、    struct pollfd fds[2];
  3、if (fds[0].revents & POLLIN)
 */

3

/*epoll.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#include <string.h>
#include <poll.h>
#include <sys/epoll.h>

#define PIPENUM 5

int fd[PIPENUM][2];

int creat_pipe(void)//创建5个管道
{
    int i, ret;

    for (i = 0; i < PIPENUM; i++) {
        ret = pipe(fd[i]);
        if (ret == -1) {
            perror("pipe");
            return -1;
        }
    }
    return 0;
}

int con_readfds(void)//构造事件池
{
    int i, epfd;
    struct epoll_event event;
    epfd = epoll_create(1);
    if (epfd == -1) {
        perror("epoll_create");
        return epfd;
    }

    for (i = 0; i < PIPENUM; i++) {
        event.events = EPOLLIN;
        event.data.fd = fd[i][0];
        epoll_ctl(epfd, EPOLL_CTL_ADD, fd[i][0],
            &event);
    }
    return epfd;    
}


void father_close_fds(void)
{
    int i;
    for (i = 0; i < PIPENUM; i++) {
        close(fd[i][1]);
    }
}

void child_close_fds(int index)
{
    int i;

    for (i = 0; i < PIPENUM; i++) {
        close(fd[i][0]);
        if (i != index) {
            close(fd[i][1]);
        }
    }
}

void child_work(int i)
{
    char buf[100];
    child_close_fds(i);
    srand(getpid());
    bzero(buf, 100);
    sprintf(buf, "I am pid %d!", getpid());

    while (1) {
        sleep(rand() % (PIPENUM) + 6);
        write(fd[i][1], buf, strlen(buf));
    }
}

static void father_actual_work(struct epoll_event *event)
{
    int i, ret;
    char buf[100];    
    for (i = 0; i < 2; i++) {
        if (event[i].events & EPOLLIN) {
            ret = read(event[i].data.fd, buf, 100);
            buf[ret] = '/0';
            printf("%s/n", buf);
        }
    }
}

void father_work()
{
    int nfds, ret, epfd;
    struct epoll_event event[2];
    father_close_fds();    
    epfd = con_readfds();    

    while (1) {
        ret = epoll_wait(epfd, event, 2, -1);
        if (ret > 0) {
            father_actual_work(event);
        }
        if (ret == -1) {
            perror("select");
            return;
        }
    }

}

int main(void)
{
    int ret, i;
    pid_t pid;

    ret = creat_pipe();
    if (ret == -1)
        exit(1);

    for (i = 0; i < PIPENUM; i++) {
        pid = fork();
        if (pid == 0) {
            child_work(i);
            exit(0);
        }
    }

    father_work();
    exit(0);
}
/*1、epoll_create(1)创建event poll;
 2、epoll_ctl(epfd, EPOLL_CTL_ADD, fd[i][0],&event);*/

4

/*select and pipe*/

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/time.h>

#include <sys/select.h>

#include <string.h>

#define PIPENUM 5

int fd[PIPENUM][2];

fd_set readfds;

int creat_pipe(void) // 产生5 个管道

{

    int i, ret;

    for (i = 0; i < PIPENUM; i++) {

        ret = pipe(fd[i]);

        if (ret == -1) {

            perror("pipe");

            return -1;

        }

    }

    return 0;

}

void con_readfds(void )// 构造

{

    int i;

    FD_ZERO(&readfds);

    for (i = 0; i < PIPENUM; i++) {

        FD_SET(fd[i][0], &readfds); // 关心的是fd[i][0]         

    }

    return;

}

int get_max_fds(void )// 取最大描述符加1

{

    int i, max = 0;

    for (i = 0; i < PIPENUM; i++) {

        if (max < fd[i][0])

            max = fd[i][0];

    }

    return max+1;

}

void father_close_fds(void)

// 父进程关闭5 个管道的写端

{

    int i;

    for (i = 0; i < PIPENUM; i++) {

        close(fd[i][1]);

    }

}

void child_close_fds(int index)

// 子进程关闭除自己以外的写端

{

    int i;

    for (i = 0; i < PIPENUM; i++) {

        close(fd[i][0]);

        if (i != index) {

            close(fd[i][1]);

        }

    }

}

void child_work(int i)

{

    char buf[100];

    child_close_fds(i);

    srand(getpid());

    bzero(buf, 100);

    sprintf(buf, "I am pid %d!", getpid());

    while (1) {

        sleep(rand() % (PIPENUM) + 6);

        write(fd[i][1], buf, strlen(buf));

    }

}

static void father_actual_work(void)

{

    int i, ret;

    char buf[100]; 

    for (i = 0; i < PIPENUM; i++) {

        if (FD_ISSET(fd[i][0], &readfds)) { // 不能写成fd[i][1]!

            ret = read(fd[i][0], buf, 100);

            buf[ret] = '/0';

            printf("%s/n", buf);

        }

    }

}

void father_work()

{

    int nfds, ret;

    father_close_fds();

    nfds = get_max_fds();

    while (1) {

        con_readfds();  // 每次用select 之前都要构造一下,设置你关心的描述符

        ret = select(nfds, &readfds, NULL,

            NULL, NULL);

        if (ret > 0) {

            father_actual_work();

        }

        if (ret == -1) {

            perror("select");

            return;

        }

    }

}

int main(void)

{

    int ret, i;

    pid_t pid;

    ret = creat_pipe();

    if (ret == -1)

        exit(1);

    for (i = 0; i < PIPENUM; i++) {

        pid = fork();

        if (pid == 0) {

            child_work(i);

            exit(0);

        }

    }

    father_work();

    exit(0);

}

/*select和pipe,监视5个管道,子进程写,父进程读*/

5

/*poll and pipe*/

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/time.h>

#include <sys/select.h>

#include <string.h>

#include <poll.h>

#define PIPENUM 5

int fd[PIPENUM][2];

struct pollfd fds[PIPENUM];

int creat_pipe(void)

{

    int i, ret;

    for (i = 0; i < PIPENUM; i++) {

        ret = pipe(fd[i]);

        if (ret == -1) {

            perror("pipe");

            return -1;

        }

    }

    return 0;

}

void con_readfds(void)

{

    int i;

    for (i = 0; i < PIPENUM; i++) {

        fds[i].fd = fd[i][0];

        fds[i].events = POLLIN;

    }

    return;

}

 

void father_close_fds(void)

{

    int i;

    for (i = 0; i < PIPENUM; i++) {

        close(fd[i][1]);

    }

}

void child_close_fds(int index)

{

    int i;

    for (i = 0; i < PIPENUM; i++) {

        close(fd[i][0]);

        if (i != index) {

            close(fd[i][1]);

        }

    }

}

 

void child_work(int i)

{

    char buf[100];

    child_close_fds(i);

    srand(getpid());

    bzero(buf, 100);

    sprintf(buf, "I am pid %d!", getpid());

    while (1) {

        sleep(rand() % (PIPENUM) + 6);

        write(fd[i][1], buf, strlen(buf));

    }

}

static void father_actual_work(void)

{

    int i, ret;

    char buf[100]; 

    for (i = 0; i < PIPENUM; i++) {

        if (fds[i].revents & POLLIN) {

            ret = read(fds[i].fd, buf, 100);

            buf[ret] = '/0';

            printf("%s/n", buf);

        }

    }

}

void father_work()

{

    int nfds, ret;

    father_close_fds();

    con_readfds(); 

    while (1) {

        ret = poll(fds, PIPENUM, -1);

        if (ret > 0) {

            father_actual_work();

        }

        if (ret == -1) {

            perror("select");

            return;

        }

    }

}

int main(void)

{

    int ret, i;

    pid_t pid;

    ret = creat_pipe();

    if (ret == -1)

        exit(1);

    for (i = 0; i < PIPENUM; i++) {

        pid = fork();

        if (pid == 0) {

            child_work(i);

            exit(0);

        }

    }

    father_work();

    exit(0);

}

/*poll pipe ,监视5 个管道, 子进程写,父进程读*/

6

/*writev.c*/
#include <sys/uio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main(void)
{
    int fd, i;
    char *ptr[3] = {
        "china:",
        "korea:",
        "japan1"
    };

    struct iovec iov[3];
    for (i = 0; i < 3; i++) {
        iov[i].iov_base = ptr[i];
        iov[i].iov_len = 6;
    }
   
    writev(1, iov, 3);
    printf("/n");
    exit(0);
}

7

/*readv.c*/
#include <sys/uio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main(void)
{
    int fd, i;

    struct iovec iov[3];
    for (i = 0; i < 3; i++) {
        iov[i].iov_base = malloc(32);
        iov[i].iov_len = 32;
    }
    

    fd = open("/etc/passwd", O_RDONLY);
    if (fd == -1) {
        perror("open");
        exit(1);
    }

    readv(fd, iov, 3);
    for (i = 0; i < 3; i++) {
        printf("%s/n", (char *)iov[i].iov_base);
    }
    close(fd);
    exit(0);
}

8

/*sigio.c*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
int fd[2];

void async_read(int s)
{
    char buf[32];
    int ret = read(fd[0], buf, 32);
    write(1, buf, ret);
    printf("/n");
}

int main(void)
{
    struct sigaction act;
    int ret;

    act.sa_handler = async_read;
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_RESTART;

    sigaction(SIGIO,&act, NULL);
    
    ret = pipe(fd);
    if (ret == -1) {
        perror("pipe");
        exit(1);
    }

    fcntl(fd[0], F_SETOWN, getpid());
    ret = fcntl(fd[0], F_GETFL);
    fcntl(fd[0], F_SETFL, O_ASYNC);//???fcntl(fd[0], F_SETFL,ret | O_ASYNC)

    while (1) {
        sleep(3+rand()%3);
        write(fd[1], "Hello", 5);
    }
}
/*
  SIGIO信号:这个信号可以通知某种事件已发生
  为了接收SIGIO信号,需执行下列几步:
  1、sigaction(SIGIO,&act, NULL);为SIGIO信号建立信号处理程序
  2、fcntl(fd[0], F_SETOWN, getpid());以F_SETOWN调用fcntl来设置进程ID和进程组ID,它们将接收对于该描述符的信号。
  3、fcntl(fd[0], F_SETFL,ret | O_ASYNC);以 F_SETFL调用fcntl设置O_ASYNC文件状态标志,使在该描述符上可以进行异步I/O.
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值