Unix-Linux编程实践教程——第七章

来源:互联网 发布:fast paxos java示例 编辑:程序博客网 时间:2024/05/16 01:45

章节概要

本章节介绍事件驱动编程以及curses库的使用和异步IO——aio

基本curses函数

  • initscr() 初始化curses库和tty
  • endwin() 关闭curses并重置tty
  • refresh() 使屏幕按照你的意图显示,刷新画面
  • move(r,c) 移动光标到屏幕(r,c)位置
  • addstr(s) 在当前位置画字符串s
  • addch(c) 在当前位置画字符c
  • clear() 清屏
  • standout() 启动standout模式(一般使屏幕反色)
  • standend() 关闭standout模式

hello1.c

/*********************************************************    > File Name: hello1.c    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 09时36分30秒 *********************************************************/#include<stdio.h>#include<curses.h>//简单实用curses库,显示helloworld//编译命令:gcc hello1.c -o hello1 -lcursesint main(){    initscr();    clear();    move(10,20);    addstr("Hello,world");    move(LINES-1,0);    refresh();    getch();    endwin();    return 0;}

hello2.c

/**********************************************************    > File Name: hello2.c    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 09时36分30秒 **********************************************************/#include<stdio.h>#include<curses.h>//整个屏幕由黑白两色helloworld依次交替显现int main(){    initscr();    clear();    for(int i=0;i<LINES;++i){        move(i,i+i);        if(i%2==1) standout();        addstr("Hello,world");        if(i%2==1) standend();    }    refresh();    getch();    endwin();    return 0;}

hello3.c

/************************************************************    > File Name: hello3.c    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 09时36分30秒 ************************************************************/#include<stdio.h>#include<curses.h>#include<unistd.h>//字符串在屏幕自上而下逐行显示,每秒增加一行,反色和正常显示交替出现int main(){    initscr();    clear();    for(int i=0;i<LINES;++i){        move(i,i+i);        if(i%2==1) standout();        addstr("Hello,world");        if(i%2==1) standend();        sleep(1);        refresh();    }    endwin();    return 0;}

hello4.c

/************************************************************    > File Name: hello4.c    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 09时36分30秒 ************************************************************/#include<stdio.h>#include<curses.h>#include<unistd.h>int main(){    initscr();    clear();    for(int i=0;i<LINES;++i){        move(i,i+i);        if(i%2==1) standout();        addstr("Hello,world");        if(i%2==1) standend();        refresh();        sleep(1);        //通过下面两步操作,清楚之前显示的字符串        move(i,i+i);        addstr("     ");    }    endwin();    return 0;}

hello5.c

/************************************************************    > File Name: hello5.c    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 09时36分30秒 ************************************************************/#include<stdio.h>#include<curses.h>#include<unistd.h>//左右边界设定#define LEFTEDGE 10#define RIGHTEDGE 30#define ROW 10int main(){    char message[] = "Hello";    char blank[] = "     ";    int dir = +5;    int pos = LEFTEDGE;    initscr();    clear();    while(1){        move(ROW,pos);        addstr(message);        move(LINES-1,COLS-1);        refresh();        sleep(1);        move(ROW,pos);        addstr(blank);        pos += dir;        //通过dir正负控制左右移动        if(pos>=RIGHTEDGE) dir = -7;        if(pos<=LEFTEDGE) dir = +7;    }    endwin();    return 0;}

sleep1.c

/*************************************************************    > File Name: sleep1.c    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 10时11分53秒 *************************************************************/#include<stdio.h>#include<signal.h>#include<unistd.h>//#define SHHHHint main(){    void wakeup(int);    printf("about to sleep for 4 second\n");    //设置SIGALRM的处理函数    signal(SIGALRM,wakeup);    //设置时钟    alarm(4);    pause(); //挂起进程,任何信号都可唤醒进程    printf("Morning so soon?\n");}void wakeup(int signum){#ifndef SHHHH    printf("Alarm received from kernel\n");#endif}

计时器

  • ITIMER_REAL 计量真实真实,计时完发送SIGALRM消息
  • ITIMER_VIRTUAL 只有进程在用户态运行才计时,计时完发送SIGALRM消息
  • ITIMER_PROF 计时器在进程运行于用户态或由该进程调用而陷入和心态时计时。计时完发送SIGPROF消息

ticker_demo.c

/*************************************************************    > File Name: ticker_demo.c    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 10时23分30秒 ************************************************************/#include<stdio.h>#include<sys/time.h>#include<signal.h>#include<unistd.h>#include<stdlib.h>int main(){    void countdown(int);    int set_ticker(int);    //设置SIGALRM的处理函数    signal(SIGALRM,countdown);    //设置计时器    if(set_ticker(500)==-1){        perror("set_ticker");    }else{        while(1){            pause();        }    }    return 0;}void countdown(int signum){    static int num = 10;    printf("%d..",num--);    fflush(stdout);    if(num<0){        printf("DONE!\n");        exit(0);    }}int set_ticker(int n){    //itimerval结构体it_interval初始值it_value间隔值    struct itimerval new_timeset;    long n_sec,n_usecs;    n_sec = n/1000;    n_usecs = (n%1000)*1000L;    new_timeset.it_interval.tv_sec = n_sec;    new_timeset.it_interval.tv_usec = n_usecs;    new_timeset.it_value.tv_sec = n_sec;    new_timeset.it_value.tv_usec = n_usecs;    //使用ITIMER_REAL计时器    return setitimer(ITIMER_REAL,&new_timeset,NULL);}

/***********************************************************    > File Name: sigdemo3.c    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 12时12分49秒 ***********************************************************/#include<stdio.h>#include<signal.h>#include<string.h>#include<unistd.h>#define INPUTLEN 100//这个程序用来测试多个信号传来时系统是怎么处理的int main(int ac,char* av[]){    void inthandler(int);    void quithandler(int);    char input[INPUTLEN];    int nchars;    signal(SIGINT,inthandler);    signal(SIGQUIT,quithandler);    do{        printf("\nType a message\n");        nchars = read(0,input,(INPUTLEN-1));        if(nchars==-1){            perror("read returned an error");        }else{            input[nchars]='\0';            printf("You typed:%s",input);        }    }while(strncmp(input,"quit",4)!=0);}void inthandler(int signum){    printf("Received signal %d..waiting\n",signum);    sleep(2);    printf("Leaving inthandler\n");}void quithandler(int signum){    printf("Received signal %d..waiting\n",signum);    sleep(3);    printf("Leaving quithandler\n");}

sigactdemo.c

/************************************************************    > File Name: sigactdemo.c    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 12时35分47秒 *************************************************************/#include<stdio.h>#include<signal.h>#include<unistd.h>#define INPUTLEN 100//使用sigaction来处理多个信号的情况int main(){    struct sigaction newhandler;    sigset_t blocked;    void inthandler(int);    char x[INPUTLEN];    //设置sa_handler来处理信号来时的应对方式    newhandler.sa_handler = inthandler;    //设置sa_flags来通知内核处理信号的方式    newhandler.sa_flags = SA_RESETHAND|SA_RESTART;    //清空blocked的位    sigemptyset(&blocked);    //设置blocked的位    sigaddset(&blocked,SIGQUIT);    //设置sa_mask来决定处理一个消息时是否阻塞其他信号    newhandler.sa_mask = blocked;    if(sigaction(SIGQUIT,&newhandler,NULL)==-1)        perror("sigaction");    else{        while(1){            fgets(x,INPUTLEN,stdin);            printf("input:%s",x);        }    }    return 0;}void inthandler(int s){    printf("Called with signal %d\n",s);    sleep(2);    printf("done handling signal %d\n",s);}

curses函数

  • cbreak() and nocbreak(): 当 cbreak 模式被开启後, 除了 DELETE 或 CTRL等仍被视为特殊控制字元外一切输入的字元将立刻被一一读取.当处於 nocbreak 模式时, 从键盘输入的字元将被储存在 buffer 里直到输入 RETURN或 NEWLINE.
  • 在较旧版的 curses 须呼叫 crmode(),nocrmode() 来取代 cbreak(),nocbreak()
  • nl() and nonl(): 用来决定当输入资料时, 按下 RETURN 键是否被对应为 NEWLINE 字元 ( 如 /n ).而输出资料时, NEWLINE 字元是否被对应为 RETURN 和 LINDFEED系统预设是开启的.
  • echo() and noecho():此函式用来控制从键盘输入字元时是否将字元显示在终端机上.系统预设是开启的.

bounce1d.c

/****************************************************************    > File Name: bounce1d.c    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 14时16分04秒 ***************************************************************/#include<stdio.h>#include<curses.h>#include<signal.h>#include<unistd.h>#include<string.h>#include<sys/time.h>#define MESSAGE "hello"#define BLANK "     "int row;int col;int dir;int main(){    int delay;    int ndelay;    int c;    void move_msg(int);    int set_ticker(int);    initscr();    crmode();    noecho();    clear();    row = 10;    col = 0;    dir = 1;    delay = 200;    move(row,col);    addstr(MESSAGE);    signal(SIGALRM,move_msg);    set_ticker(delay);    while(1){        ndelay = 0;        c = getch();        if(c=='Q') break;        if(c==' ') dir=-dir;        if(c=='f'&&delay>2) ndelay=delay/2;        if(c=='s') ndelay=delay*2;        if(ndelay>0) set_ticker(delay=ndelay);    }    endwin();    return 0;}void move_msg(int signum){    signal(SIGALRM,move_msg);    move(row,col);    addstr(BLANK);    col += dir;    move(row,col);    addstr(MESSAGE);    refresh();    if(dir==-1&&col<=0){        dir = 1;    }else if(dir==1&&(col+strlen(MESSAGE))>=COLS){        dir = -1;    }}int set_ticker(int n){    struct itimerval new_timeset;    long n_sec,n_usecs;    n_sec = n/1000;    n_usecs = (n%1000)*1000L;    new_timeset.it_interval.tv_sec = n_sec;    new_timeset.it_interval.tv_usec = n_usecs;    new_timeset.it_value.tv_sec = n_sec;    new_timeset.it_value.tv_usec = n_usecs;    return setitimer(ITIMER_REAL,&new_timeset,NULL);}

bounce.h

/***********************************************************    > File Name: bounce.h    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 14时41分47秒 ***********************************************************/#define BLANK ' '#define DFL_SYMBOL 'O'#define TOP_ROW 5#define BOT_ROW 20#define LEFT_EDGE 10#define RIGHT_EDGE 70#define X_INIT 10#define Y_INIT 10#define TICKS_PER_SEC 50#define X_TTM 5#define Y_TTM 8struct ppball{    int y_pos,x_pos,        y_ttm,x_ttm,        y_ttg,x_ttg,        y_dir,x_dir;    char symbol;};

bounce2d.c

/******************************************************    > File Name: bounce2d.c    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 14时16分04秒 *****************************************************/#include<stdio.h>#include<curses.h>#include<signal.h>#include<unistd.h>#include<string.h>#include<sys/time.h>#include "bounce.h"//将显示的主体封装在ppball结构体内struct ppball the_ball;void set_up();void wrap_up();void ball_move(int);int set_ticker(int);int bounce_os_lose(struct ppball*);int main(){    set_up();    int c;    while((c=getchar())!='Q'){        if(c=='f') the_ball.x_ttm--;        else if(c=='s') the_ball.x_ttm++;        else if(c=='F') the_ball.y_ttm--;        else if(c=='S') the_ball.y_ttm++;    }    wrap_up();    return 0;}void set_up(){    the_ball.y_pos = Y_INIT;    the_ball.x_pos = X_INIT;    the_ball.y_ttg = the_ball.y_ttm = Y_TTM;    the_ball.x_ttg = the_ball.x_ttm = X_TTM;    the_ball.y_dir = the_ball.x_dir = 1;    the_ball.symbol = DFL_SYMBOL;    initscr();    noecho();    crmode();    signal(SIGINT,SIG_IGN);    mvaddch(the_ball.y_pos,the_ball.x_pos,the_ball.symbol);    refresh();    signal(SIGALRM,ball_move);    set_ticker(1000/TICKS_PER_SEC);}void wrap_up(){    set_ticker(0);    endwin();}void ball_move(int signum){    int y_cur,x_cur,moved;    signal(SIGALRM,SIG_IGN);    y_cur = the_ball.y_pos;    x_cur = the_ball.x_pos;    moved = 0;    if(the_ball.y_ttm>0&&the_ball.y_ttg--==1){        the_ball.y_pos += the_ball.y_dir;        the_ball.y_ttg = the_ball.y_ttm;        moved = 1;    }    if(the_ball.x_ttm>0&&the_ball.x_ttg--==1){        the_ball.x_pos += the_ball.x_dir;        the_ball.x_ttg = the_ball.x_ttm;        moved = 1;    }    if(moved){        mvaddch(y_cur,x_cur,BLANK);        mvaddch(y_cur,x_cur,BLANK);        mvaddch(the_ball.y_pos,the_ball.x_pos,the_ball.symbol);        bounce_os_lose(&the_ball);        move(LINES-1,COLS-1);        refresh();    }    signal(SIGALRM,ball_move);}int bounce_os_lose(struct ppball* bp){    int return_val = 0;    if(bp->y_pos==TOP_ROW){        bp->y_dir = 1;        return_val = 1;    }else if(bp->y_pos==BOT_ROW){        bp->y_dir = -1;        return_val = 1;    }    if(bp->x_pos==LEFT_EDGE){        bp->x_dir = 1;        return_val = 1;    }else if(bp->x_pos==RIGHT_EDGE){        bp->x_dir = -1;        return_val = 1;    }    return return_val;}int set_ticker(int n){    struct itimerval new_timeset;    long n_sec,n_usecs;    n_sec = n/1000;    n_usecs = (n%1000)*1000L;    new_timeset.it_interval.tv_sec = n_sec;    new_timeset.it_interval.tv_usec = n_usecs;    new_timeset.it_value.tv_sec = n_sec;    new_timeset.it_value.tv_usec = n_usecs;    return setitimer(ITIMER_REAL,&new_timeset,NULL);}

bounce_async.c

/********************************************************    > File Name: bounce_async.c    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 15时56分49秒 ********************************************************/#include<stdio.h>#include<curses.h>#include<signal.h>#include<fcntl.h>#include<unistd.h>#include<sys/time.h>#include<string.h>#define MESSAGE "hello"#define BLANK "     "int row = 10;int col = 0;int dir = 1;int delay = 200;int done = 0;void on_input(int signum){    int c = getch();    if(c=='Q'||c==EOF) done=1;    else if(c==' ') dir = -dir;}void on_alarm(int signum){    //以防万一,重置SIGALRM    signal(SIGALRM,on_alarm);    mvaddstr(row,col,BLANK);    col += dir;    mvaddstr(row,col,MESSAGE);    refresh();    if(dir==-1&&col<=0) dir = 1;    else if(dir==1&&(col+strlen(MESSAGE))>=COLS) dir = -1;}//fcntl设置异步IOvoid enable_kbd_signals(){    int fd_flags;    //告诉内核发送输入信号给进程    fcntl(0,F_SETOWN,getpid());    fd_flags = fcntl(0,F_GETFL);    fcntl(0,F_SETFL,(fd_flags|O_ASYNC));}int set_ticker(int n){    struct itimerval new_timeset;    long n_sec,n_usecs;    n_sec = n/1000;    n_usecs = (n%1000)*1000L;    new_timeset.it_interval.tv_sec = n_sec;    new_timeset.it_interval.tv_usec = n_usecs;    new_timeset.it_value.tv_sec = n_sec;    new_timeset.it_value.tv_usec = n_usecs;    return setitimer(ITIMER_REAL,&new_timeset,NULL);}int main(){    void on_alarm(int);    void on_input(int);    void enable_kbd_signals();    initscr();    crmode();    noecho();    clear();    //设置SIGIO的处理函数,从键盘来的字符到达,内核会向进程发送SIGIO信号    signal(SIGIO,on_input);    enable_kbd_signals();    signal(SIGALRM,on_alarm);    set_ticker(delay);    move(row,col);    addstr(MESSAGE);    //循环调用pause,等待来自键盘和计时器的信号    while(!done){        pause();    }    endwin();}

bounce_aio.c

关于AIO的使用与理解
- 慢慢聊Linux AIO
- linux下aio异步读写详解与实例

/**************************************************    > File Name: bounce_aio.c    > Author: Duke-wei    > Mail: 13540639584@163.com     > Created Time: 2017年10月11日 星期三 16时24分17秒 **************************************************//* * 同步阻塞I/O:用户进程进行I/O操作,一直阻塞到I/O操作完成为止。  * 同步非阻塞I/O:用户程序可以通过设置文件描述符的属性O_NONBLOCK,I/O操作可以立即返回,但是并不保证I/O操作成功。  * 异步事件阻塞I/O:用户进程可以对I/O事件进行阻塞,但是I/O操作并不阻塞。通过select/poll/epoll等函数调用来达到此目的。 * 异步时间非阻塞I/O:也叫做异步I/O(AIO),用户程序可以通过向发送I/O请求命令,不用带I/O事件真正发生,可以继续左另外的事情,等I/O操作完成,内核会通过函数回调或者信号机制通知进程。提高系统吞吐量。 */#include<stdio.h>#include<curses.h>#include<signal.h>#include<sys/time.h>#include<aio.h>#include<string.h>#include<unistd.h>#include<stdlib.h>#define MESSAGE "hello"#define BLANK "     "int row = 10;int col = 0;int dir = 1;int delay = 200;int done = 0;struct aiocb kbcbuf;void on_input(int signum){    int c;    char *cp = (char*)kbcbuf.aio_buf;    if(aio_error(&kbcbuf)!=0) perror("reading failed");    else {        if(aio_return(&kbcbuf)==1){            c = *cp;            if(c=='Q'||c==EOF) done=1;            else if(c==' ') dir = -dir;        }    }    aio_read(&kbcbuf);}void on_alarm(int signum){    signal(SIGALRM,on_alarm);    mvaddstr(row,col,BLANK);    col += dir;    mvaddstr(row,col,MESSAGE);    refresh();    if(dir==-1&&col<=0) dir=1;    else if(dir==1&&(col+strlen(MESSAGE))>=COLS) dir=-1;}void setup_aio_buffer(){    static char input[1];    kbcbuf.aio_fildes = 0;    kbcbuf.aio_buf = input;    kbcbuf.aio_nbytes = 1;    kbcbuf.aio_offset = 0;    kbcbuf.aio_sigevent.sigev_notify = SIGEV_SIGNAL;    kbcbuf.aio_sigevent.sigev_signo = SIGIO;}int set_ticker(int n){    struct itimerval new_timeset;    long n_sec,n_usecs;    n_sec = n/1000;    n_usecs = (n%1000)*1000L;    new_timeset.it_interval.tv_sec = n_sec;    new_timeset.it_interval.tv_usec = n_usecs;    new_timeset.it_value.tv_sec = n_sec;    new_timeset.it_value.tv_usec = n_usecs;    return setitimer(ITIMER_REAL,&new_timeset,NULL);}int main(){    initscr();    crmode();    noecho();    clear();    signal(SIGIO,on_input);    setup_aio_buffer();    aio_read(&kbcbuf);    signal(SIGALRM,on_alarm);    set_ticker(delay);    mvaddstr(row,col,MESSAGE);    while(!done) pause();    endwin();}
原创粉丝点击