• libuv 一 环境搭建, hello TTY


    引言 - 一时心起, libuv linux 搭建

      有一天突然想起来想写个动画. 找了一下 ui 库太大. 后面想起以前弄过的 libuv. 但发现 libuv 相关资料也很少.

    所以就有了这些内容. 

      libuv - https://github.com/libuv/libuv

    libuv 在 linux 上面使用比较简单,  一开始 从 linux hello 跑起来

    libuv linux 安装

    首先假定你和我一样用的是Ubuntu去做开发. 在云平台上面测试过, Ubuntu Server 版本比 CentOS 版本少个十几兆.

    有兴趣朋友可以详细比较数据, 也可以尝试跑跑 Ubuntu Server .

    # libuv 安装
    cd
    wget https://github.com/libuv/libuv/archive/v1.18.0.tar.gz
    tar -zxvf v1.18.0.tar.gz
    cd libuv-1.18.0
    
    sh autogen.sh
    ./configure
    
    make -j4
    
    sudo make install
    sudo ldconfig
    cd ../
    rm -rf libuv-1.18.0 v1.18.0.tar.gz
    ```

    执行上面命令操作, 我们的系统中就已经有了 libuv 开发环境.

    有一点需要注意的是当我们要使用 libuv时候推荐用静态库.

    gcc -l:libuv.a

    到这里 linux 安装 libuv 已经完工了. 

      不妨写个 hello world demo

    #include <uv.h>
    #include <assext.h>
    
    //
    // 测试 libuv tty 操作控制台
    // 输出一段有颜色的文字
    //
    void uv_tty_test(void) {
        uv_tty_t tty;
        uv_buf_t buf[3];
        unsigned i, len = sizeof buf / sizeof *buf;
        uv_loop_t * loop = uv_default_loop();
    
        // 目前只对 tty 控制台处理
        if (uv_guess_handle(1) != UV_TTY) {
            fprintf(stderr, "uv_guess_handle(1) != UV_TTY!
    ");
            exit(EXIT_FAILURE);
        }
    
        uv_tty_init(loop, &tty, 1, 0);
        uv_tty_set_mode(&tty, UV_TTY_MODE_NORMAL);
    
        // 开始发送消息
        buf[0].base = "33[46;37m";
        buf[1].base = u8"(✿◡‿◡) 喵酱 ((●'-'●)) 比 ♥ 里~ 
    ";
        buf[2].base = "33[0m";
        for (i = 0; i < len; ++i)
            buf[i].len = (int)strlen(buf[i].base);
        uv_try_write((uv_stream_t *)&tty, buf, len);
    
        // 重置终端行为
        uv_tty_reset_mode();
        uv_run(loop, UV_RUN_DEFAULT);
    }

    代码运行效果是, 输出一段话, 并且设置背景色.  对于  uv_tty_test 可以理解为 main (本质是 structc 一种单元测试函数约束写法)

    到这容我安利一个小东西, 感兴趣的可以尝试一下, 从零开始搭建一个 c 的 struct 小框架. 五脏逐渐全了.

      structc - https://github.com/wangzhione/structc

    简单说一下libuv中使用的几个函数,  第一个是 uv_try_write 尝试立即发送消息数组. 不像 uv_write 写入到消息队列中.

    int uv_try_write(uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs)
    Same as uv_write(), but won’t queue a
    write request if it can’t be completed immediately. Will return either: > 0: number of bytes written (can be less than the supplied buffer size). < 0: negative error code (UV_EAGAIN is returned if no data can be sent immediately).

    目前我们是用 tty 输出到屏幕上面, 可以用这个 api . 如果单纯是走 TCP, 不要过于依赖这个 api.

    说白了为了稳定性还是别用 uv_try_write.

    第二个要说的是 uv_run

    int uv_run(uv_loop_t* loop, uv_run_mode mode)
    
        This function runs the event loop. It will act differently depending on the specified mode:
            UV_RUN_DEFAULT: Runs the event loop until there are no more active and referenced handles or requests. 
                  Returns non-zero if uv_stop() was called and there are still active handles or requests.
                   Returns zero in all other cases. UV_RUN_ONCE: Poll for i/o once. Note that this function blocks if there are no pending callbacks.
                 Returns zero when done (no active handles or requests left),
                 or non-zero if more callbacks are expected
                 (meaning you should run the event loop again sometime in the future). UV_RUN_NOWAIT: Poll for i/o once but don’t block if there are no pending callbacks.
                  Returns zero if done (no active handles or requests left),
                  or non-zero if more callbacks are expected
                  (meaning you should run the event loop again sometime in the future).

    其中 UV_RUN_DEFAULT 表示 uv_run 会一直阻塞运行, 只到没有事情要处理的时候, 才会有返回值.

    UV_RUN_ONCE 表示执行 poll 一次. 类比你写代码只调用一次 select 阻塞, 直到事件激活或者超时触发.

    相似的 UV_RUN_NOWAIT 也是只 poll 轮询一次, 但是没有要处理事情是不会阻塞.

      到这里, 差不多 linux libuv 的 hello world 应该也算起来了.

    前言 - winds 跑起 libuv

       下面开始带大家, 在 winds 编译最新版本 libuv.  同样在 github 上 下载 libuv 最新的发布版本.

        libuv-1.18.0 - https://github.com/libuv/libuv/releases/tag/v1.18.0

    解压操作完成后, 会是下面这样的

    这时候先参照一下官网的 libuv 首页 README.md 说明.  

    先安装 Python 2.7 . 扯一点.  最近 python 好虎 (2017年12月23日),  但是还是不理解为啥 2.7 和 3.x 版本不兼容. 

    就目前而言还是多用 Python 2.7 感觉.  随后安装 gyp google 推出的跨平台编译环境.

      gyp - https://github.com/svn2github/gyp

    由于使用的是 VS2017, 原始版本 gyp 不支持, 请参照我提的这个提交, 进行修改让其支持 VS2017 版本

      gyp-vs2017 version  - https://github.com/svn2github/gyp/pull/1/commits/66e69a51f4393bc03cc3bfec53c7c35d974339b6

    ok winds 10 + VS2017 + libuv-1.18.0 + python2.7 + gyp + gyp vs2017 version 编译环境搭建完毕.

    开始走起, 先进入 gyp 目录执行 

    python .setup.py install

    完成后, 开始构建 uv.sln 工程. 先进入 libuv-1.18.0 初始目录, 执行下面命令 

     .vcbuild.bat release vs2017 x64 static

    随后可以看见 uv.sln 和 Releaseliblibuv.lib 生成文件. 编译过程中 x64版本警告不少.  你完全可以尝试解决,

    主要是 linux 和 winds 对于 POSIX socket writev 批量读写实现的结构用了不一样类型导致的. 

    自己改了它部分源码和测试代码, 消除了全部警告. 详细 libuv 在 VS2017 上面使用无外乎 include + lib 

    带上 libuv.h 下面的 include 头文件

      

    再加上项目工程中导入下面库 

    advapi32.lib
    iphlpapi.lib
    psapi.lib
    shell32.lib
    user32.lib
    userenv.lib
    ws2_32.lib

    头文件什么的简单导入下面就可以了 

    WIN32_LEAN_AND_MEAN
    _CRT_SECURE_NO_WARNINGS
    _CRT_NONSTDC_NO_DEPRECATE
    _WINSOCK_DEPRECATED_NO_WARNINGS

    到这基本上 libuv winds 就大功告成了.  

    这里写了个演示 demo, 有兴趣的可以尝试练习一下

    #include <uv.h>
    #include <assext.h>
    
    // 继承 uv_timer_t 结构
    struct gravity {
        uv_timer_t tick;
    
        uv_tty_t tty;
    
        int width;
        int height;
        int pos;
    
        char * msg;
    };
    
    // _update - 更新图片内容
    static void _update(struct gravity * grav) {
        char data[BUFSIZ];
        uv_buf_t buf;
        buf.base = data;
        //
        // 33[2J      : 清屏
        // 33[H       : 光标移到(0, 0)
        // 33[%dB     : 光标下移 %d 行
        // 33[%dC     : 光标右移 %d 行
        // 33[42;37m  : 底色 41 绿底, 字色 37 白字
        //
        // 33[0m      : 关闭所有属性
        //
        buf.len = sprintf(data, "33[2J33[H33[%dB33[%dC33[42;37m%s",
                                grav->pos,
                                (grav->width - (int)strlen(grav->msg)) / 2,
                                grav->msg);
        assert(buf.len < BUFSIZ);
        if (grav->pos == grav->height) {
            // 关闭屏幕额外属性
            const char * resets = "33[0m";
            strcat(data, resets);
            buf.len += (int)strlen(resets);
        }
    
        // 写入消息
        uv_try_write((uv_stream_t *)&grav->tty, &buf, 1);
    
        // 当超过当前屏幕, 退出定时器
        if (++grav->pos > grav->height) {
            // 重置tty
            uv_tty_reset_mode();
            uv_timer_stop(&grav->tick);
        }
    }
    
    //
    // uv_timer_test - 测试 timer 使用
    //
    void uv_timer_test(void) {
        uv_loop_t * loop = uv_default_loop();
        struct gravity grav = { { 0 } };
    
        uv_tty_init(loop, &grav.tty, 1, 0);
        uv_tty_set_mode(&grav.tty, UV_TTY_MODE_NORMAL);
    
        // 获取当前屏幕宽高信息
        if (uv_tty_get_winsize(&grav.tty, &grav.width, &grav.height)) {
            fprintf(stderr, "Could not get TTY information
    ");
            uv_tty_reset_mode();
            return;
        }
    
        fprintf(stderr, "Width %d, height %d
    ", grav.width, grav.height);
        
        // 启动 timer 刷新屏幕信息
        grav.msg = u8"我不甘心 ~";
        uv_timer_init(loop, &grav.tick);
        uv_timer_start(&grav.tick, (uv_timer_cb)_update, 200, 200);
        
        uv_run(loop, UV_RUN_DEFAULT);
    }

    这个屏幕信息会动 哈哈, : )

     

    (二傻子 入场 ~ ) 

    正文 - 稍加练习

      通过以上对libuv环境的搭建和简单先入为主的概念性描述,. 此时完全可以利用 libuv tty 简单做个

    跨平台的小动画了.  我先写个, 推荐大家参照例子抄写一遍, 培养手感. 扯一点互联网技术有两个方向

    架构师和技术专家. 有点像以前游戏开发中服务器架构和客户端引擎. 但是C程序员还是强调手感,

    弱化架构, 追求极致的统一.  (说白点, 代码更重要, 能说更好.)

    #include <uv.h>
    #include <chead.h>
    #include <assext.h>
    
    struct love {
        uv_timer_t tick;
    
        uv_tty_t tty;
    
        int width;
        int height;
        int pos;
    
        char ** msgs;
        int len;
    };
    
    static char * _figure[] = {
        u8"  背影 :- 汪国真
    ",
        u8"  
    ",
        u8"  背影
    ",
        u8"  总是很简单
    ",
        u8"  简单
    ",
        u8"  是一种风景
    ",
        u8"  
    ",
        u8"  背影
    ",
        u8"  总是很年轻
    ",
        u8"  年轻
    ",
        u8"  是一种清明
    ",
        u8"  
    ",
        u8"  背影
    ",
        u8"  总是很含蓄
    ",
        u8"  含蓄
    ",
        u8"  是一种魅力
    ",
        u8"  
    ",
        u8"  背影
    ",
        u8"  总是很孤零
    ",
        u8"  孤零
    ",
        u8"  更让人记得清
    "
    };
    
    // _love_stty : 内部发送消息
    static inline void _love_stty(struct love * love, const char * msg) {
        uv_buf_t buf;
        buf.base = (char *)msg;
        buf.len = (int)strlen(buf.base);
        uv_try_write((uv_stream_t *)&love->tty, &buf, 1);
    }
    
    // _love_init : 初始化当前 tty 结构
    static void _love_init(struct love * love) {
        uv_loop_t * loop = uv_default_loop();
        memset(love, 0, sizeof *love);
    
        // 初始化 tty 环境
        uv_tty_init(loop, &love->tty, 1, 0);
        uv_tty_set_mode(&love->tty, UV_TTY_MODE_NORMAL);
    
        // 只对 tty 输出处理
        if (uv_guess_handle(1) != UV_TTY)
            CERR_EXIT("uv_guess_handle(1) != UV_TTY!");
    
        // 获取当前屏幕宽高信息
        if (uv_tty_get_winsize(&love->tty, &love->width, &love->height)) {
            uv_tty_reset_mode();
            CERR_EXIT("Could not get TTY information");
        }
    
        // 设置具体内容
        love->msgs = _figure;
        love->len = LEN(_figure);
    
        // 初始化定时器
        uv_timer_init(loop, &love->tick);
    }
    
    // _love_screem : 屏幕绘制内容
    static void _love_screem(struct love * love) {
        char buf[BUFSIZ];
        int cnt = love->pos < love->len ? love->pos : love->len;
    
        // 重置索引位置
        int idx = love->height - love->pos;
        snprintf(buf, LEN(buf), "33[2J33[H33[%dB", idx);
        _love_stty(love, buf);
    
        // 全部显示
        for (idx = 0; idx < cnt; idx++)
            _love_stty(love, love->msgs[idx]);
    }
    
    // _update - 更新刷新事件
    static void _love_update(struct love * love) {
        ++love->pos;
    
        // 开始绘制内容
        _love_screem(love);
    
        // 运行结束直接返回
        if (love->pos >= love->height) {
            // 重置tty
            uv_tty_reset_mode();
            uv_timer_stop(&love->tick);
        }
    }
    
    //
    // uv_love_test - 情怀 ~
    //
    void uv_love_test(void) {
        struct love love;
        _love_init(&love);
    
        // 开始初始化, 定时器刷新事件
        uv_timer_start(&love.tick, (uv_timer_cb)_love_update, 200, 200);
    
        // 事件启动起来
        uv_run(uv_default_loop(), UV_RUN_DEFAULT);
    }

    效果是从上到下输出了汪国真先生诗词背影~ :) 

      背影 - https://pan.baidu.com/s/1kVd5aRX

          背景,  总是很简单, 更让人记得清 

    后记 - 好久没扯淡了

      有问题欢迎交流, 错误是难免的, 发现再改吧 ~  O_O

      只为你活一天 - http://music.163.com/m/song?id=29999535&userid=16529894

      

      

  • 相关阅读:
    3、tensorflow变量运算,数学运算
    2、tensorflow 变量的初始化
    1、tensorflow 框架理解
    tensorflow 打印全部变量的一种方法
    0、tensorflow学习开始
    tensorflow 小记——如何对张量做任意行求和,得到新tensor(一种方法:列表生成式)
    SASRec 实践
    jupyterlab 增加新内核的方法ipykernel
    vivo 全球商城:架构演进之路
    jenkins安装 git免密ssh配置
  • 原文地址:https://www.cnblogs.com/life2refuel/p/8033896.html
Copyright © 2020-2023  润新知