引言 – 暂且心起, libuv linux 搭建

引言 – 暂时心起, libuv linux 搭建

引言 – 一切才刚刚初叶

  有一天突然想起来想写个动画. 找了一晃 ui 库太大. 后边想起在此之前弄过的
libuv. 但意识 libuv 相关资料也很少.

  有壹天突然想起来想写个动画. 找了弹指间 ui 库太大. 前边想起在此以前弄过的
libuv. 但意识 libuv 相关资料也很少.

  structc 是 C 结构基础库. 轻巧可复用.

所以就有了这几个内容. 

因而就有了这么些内容.

  structc –

  libuv –

  libuv –

  在此之前也讲述过三回 structc, 文字多代码风格少. 近年来加班不多,
计划详细分解哈其思维初衷.

libuv 在 linux 上面使用相比较简单,  1始发 从 linux hello 跑起来

libuv 在 linux 上面使用相比轻便, 一发端 从 linux hello 跑起来

0.0 全部布局

libuv linux 安装

libuv linux 安装

structc├── extern├── LICENSE├── Makefile├── README.md├── structc└── structc.sln

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

首先假定你和自家同壹用的是Ubuntu去做开荒. 在云平台上面测试过, Ubuntu
Server 版本比 CentOS 版本少个十几兆.

structc.sln : winds 项目处理文件visual studio

有意思味朋友能够详细相比数据, 也足以品尝跑跑 Ubuntu Server .

风乐趣朋友能够详细相比较数据, 也可以品尝跑跑 Ubuntu Server .

structc : 项目完全源码和资料文件目录

# 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 安装cdwget https://github.com/libuv/libuv/archive/v1.18.0.tar.gztar -zxvf v1.18.0.tar.gzcd libuv-1.18.0sh autogen.sh./configuremake -j4sudo make installsudo ldconfigcd ../rm -rf libuv-1.18.0 v1.18.0.tar.gz```

README.md : 项目介绍 马克down

执行上边命令操作, 大家的系统中就早已有了 libuv 开荒蒙受.

实践上边命令操作, 大家的系统中就已经有了 libuv 开拓情况.

Makefile : linux 编写翻译文件make

有有个别内需留意的是当大家要使用 libuv时候推荐用静态库.

有好几急需留意的是当大家要运用 libuv时候推荐用静态库.

LICENSE : MIT 开源协议

gcc -l:libuv.a
gcc -l:libuv.a

extern : 项目引进的外部库目录

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

到这里 linux 安装 libuv 已经告竣了.

extern├── jemalloc├── jemalloc-vc141-Release-static.lib├── libuv.lib├── pthread.h├── pthread_lib.lib├── sched.h├── semaphore.h├── strings.h├── uv└── uv.h

  不要紧写个 hello world demo

  无妨写个 hello world demo

上述正是大家看看 structc 项目完全结构.

#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!\n");
        exit(EXIT_FAILURE);
    }

    uv_tty_init(loop, &tty, 1, 0);
    uv_tty_set_mode(&tty, UV_TTY_MODE_NORMAL);

    // 开始发送消息
    buf[0].base = "\033[46;37m";
    buf[1].base = u8"(✿◡‿◡) 喵酱 ((●'-'●)) 比 ♥ 里~ \n";
    buf[2].base = "\033[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);
}
#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 != UV_TTY!\n");        exit(EXIT_FAILURE);    }    uv_tty_init(loop, &tty, 1, 0);    uv_tty_set_mode(&tty, UV_TTY_MODE_NORMAL);    // 开始发送消息    buf[0].base = "\033[46;37m";    buf[1].base = u8" 喵酱  比 ♥ 里~ \n";    buf[2].base = "\033[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);}

0.1 外部库

代码运维效果是, 输出一段话, 并且设置背景象.  对于  uv_tty_test
能够清楚为 main (本质是 structc 1种单元测试函数约束写法)

代码运营效果是, 输出一段话, 并且设置背景观. 对于 uv_tty_test
能够清楚为 main (本质是 structc 1种单元测试函数约束写法)

  当前很严苛的引进四个半外表库. 最大程度会静态库编译链接运营.
荣小编稳步细说.

到那容作者安利一个小东西, 感兴趣的能够尝试一下, 从零早先搭建贰个 c 的
struct 小框架. 伍脏渐渐全了.

到那容小编安利一个小东西, 感兴趣的能够尝尝一下, 从零早先搭建二个 c 的
struct 小框架. 伍脏慢慢全了.

  1. jemalloc –

  structc –

  structc –

  jemalloc 是 c 营造底层高质量 malloc 库.
也被称呼系统编制程序末期最后无需付费午餐.整个structc

一言以蔽之说一下libuv中运用的多少个函数,  第三个是 uv_try_write
尝试立时发送音讯数组. 不像 uv_write 写入到音信队列中.

简轻巧单说一下libuv中央银行使的几个函数, 第叁个是 uv_try_write
尝试立刻发送音信数组. 不像 uv_write 写入到新闻队列中.

malloc全权交给 je_malloc 抗压.在那之中 winds 编写翻译静态库部分,
项目作者也有细说 –

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).
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.

近期大家是用 tty 输出到荧屏方面, 能够用那几个 api . 固然仅仅是走 TCP,
不要过于信赖那么些 api.

How to build jemalloc for Windows=================================1. Install Cygwin with at least the following packages:   * autoconf   * autogen   * gawk   * grep   * sed2. Install Visual Studio 2015 or 2017 with Visual C++3. Add Cygwin\bin to the PATH environment variable4. Open "x64 Native Tools Command Prompt for VS 2017"   (note: x86/x64 doesn't matter at this point)5. Generate header files:   sh -c "CC=cl ./autogen.sh"6. Now the project can be opened and built in Visual Studio:   msvc\jemalloc_vc2017.sln

简单为了牢固照旧别用 uv_try_write.

简易为了稳固还是别用 uv_try_write.

( 注: vs 使用最新版本. 网站打不开那就FQ. 前面其也1致, 时刻保障最新
2018/10/10 ~ )

其次个要说的是 uv_run

其次个要说的是 uv_run

对此 linux 编写翻译安装参照上边脚本

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).
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).
# 开发环境安装sudo apt install gcc gdb autogen autoconf# jemalloc 安装cdwget https://github.com/jemalloc/jemalloc/releases/download/5.1.0/jemalloc-5.1.0.tar.bz2tar -jxvf jemalloc-5.1.0.tar.bz2cd jemalloc-5.1.0sh autogen.shmake -j4sudo make installsudo ldconfigcdrm -rf jemalloc-5.1.0 jemalloc-5.1.0.tar.bz2

其中 UV_RUN_DEFAULT 表示 uv_run
会一向不通运营, 只到失业要拍卖的时候, 才会有重临值.

其中 UV_RUN_DEFAULT 表示 uv_run
会一向不通运营, 只到未有事业要管理的时候, 才会有重临值.

当 jemalloc 创设好了. 设计 alloc 层引进到 structc 框架中, 用户代替系统
malloc…

而 UV_RUN_ONCE 表示实践 poll 3回.
类比你写代码只调用一遍 select 阻塞, 直到事件激活恐怕逾期触发.

而 UV_RUN_ONCE 代表试行 poll 1回.
类比你写代码只调用贰回 select 阻塞, 直到事件激活或许逾期触发.

alloc.h

相似的 UV_RUN_NOWAIT 也是只 poll
轮询一回, 可是未有要拍卖事务是不会阻塞.

相似的 UV_RUN_NOWAIT 也是只 poll
轮询二次, 不过没有要管理业务是不会阻塞.

#ifndef _H_ALLOC#define _H_ALLOC#include <stdlib.h>#include <string.h>// :) 高效内存分配, 莫名伤感 ~// _MSC_VER -> Winds CL// __GNUC__ -> Linux GCC//#ifdef _MSC_VER//// CPU 检测 x64 or x86// ISX64 defined 表示 x64 否则 x86//#   if defined || defined#       define ISX64#   endif//// _M_PPC 为 PowerPC 平台定义, 现在已不支持// so winds 可以认为都是小端平台//#   if defined#       define ISBENIAN#   endif#elif  __GNUC__#   if defined(__x86_64__)#       define ISX64#   endif//// 大小端检测 : ISBENIAN defined 表示大端//#   if defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN_BITFIELD)#       define ISBENIAN#   endif#else#   error BUILD  S#endif// OFF_ALLOC - 关闭全局 free / malloc 配置#ifndef OFF_ALLOC#   undef  free#   define free    free_#   undef  strdup#   define strdup  strdup_#   undef  malloc#   define malloc  malloc_#   undef  calloc#   define calloc  calloc_#   undef  realloc#   define realloc realloc_#endif//OFF_ALLOC//// free_ - free 包装函数// ptr      : 内存首地址// return   : void//extern void free_(void * ptr);//// malloc_ - malloc 包装, 封装一些特殊业务// size     : 分配的内存字节// return   : 返回可使用的内存地址.//extern void * malloc_(size_t size);//// strdup_ - strdup 包装函数// s        : '\0' 结尾 C 字符串// return   : 拷贝后新的 C 字符串//extern char * strdup_(const char * s);//// calloc_ - calloc 包装, 封装一些特殊业务// num      : 数量// size     : 大小// return   : 返回可用内存地址, 并且置0//extern void * calloc_(size_t num, size_t size);//// realloc_ - realoc 包装函数, 封装一些特殊业务// ptr      : 内存首地址, NULL 等同于 malloc// size     : 重新分配的内存大小// return   : 返回重新分配好的新地址内容//extern void * realloc_(void * ptr, size_t size);#endif//_H_STDEXIT

  到那里, 大约 linux libuv 的 hello world 应该也算起来了.

  到此处, 大约 linux libuv 的 hello world 应该也算起来了.

alloc.c

 

前言 – winds 跑起 libuv

#include <stdio.h>#define OFF_ALLOC#include "alloc.h"#define JEMALLOC_NO_DEMANGLE#include <jemalloc/jemalloc.h>//// free_ - free 包装函数// ptr      : 内存首地址// return   : void//inline void free_(void * ptr) {    je_free;}// 简单内存不足检测处理static inline void * mcheck(void * ptr, size_t size) {    if (NULL == ptr) {        fprintf(stderr, "out of memory trying to allocate %zu\n", size);        fflush;        abort();    }    return ptr;}//// malloc_ - malloc 包装, 封装一些特殊业务// size     : 分配的内存字节// return   : 返回可使用的内存地址.//inline void * malloc_(size_t size) {    void * ptr = je_malloc;    return mcheck(ptr, size);}//// strdup_ - strdup 包装函数// s        : '\0' 结尾 C 字符串// return   : 拷贝后新的 C 字符串//inline char * strdup_(const char * s) {    if  {        size_t n = strlen + 1;        char * ptr = malloc_;        return memcpy(ptr, s, n);    }    return NULL;}//// calloc_ - calloc 包装, 封装一些特殊业务// num      : 数量// size     : 大小// return   : 返回可用内存地址, 并且置0//inline void * calloc_(size_t num, size_t size) {    void * ptr = je_calloc(num, size);    return mcheck(ptr, size);}//// realloc_ - realoc 包装函数, 封装一些特殊业务// ptr      : 内存首地址, NULL 等同于 malloc// size     : 重新分配的内存大小// return   : 返回重新分配好的新地址内容//inline void * realloc_(void * ptr, size_t size) {    void * ntr = je_realloc(ptr, size);    return mcheck(ntr, size);}

前言 – winds 跑起 libuv

  上边起始带大家, 在 winds 编写翻译最新版本 libuv. 同样在 github 上 下载
libuv 最新的公布版本.

装进了一层. 从 alloc.h 中 OFF_ALLOC 宏能够看看, 具有辅助插拔才干 ~

   下边伊始带我们, 在 winds 编写翻译最新版本 libuv.  一样在 github 上 下载
libuv 最新的公布版本.

  libuv-1.18.0 –

2.libuv -  

    libuv-1.18.0

解压操作达成后, 会是上边那样的

  libuv 用 c 写的高质量单线程网络 io 库. 希望经过它来协理网络层.winds
编写翻译静态库

图片 1

参照 libuv 项目首页燥起来就行. 个中 gyp 安装了这一个版本, 此外与世浮沉 ~

解压操作实现后, 会是底下那样的

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

  gyp –

图片 1

先安装 Python 二.7 . 扯一点. 目前 python 好虎 (20一7年5月二二十五日),
不过依然不领会为何 二.7 和 3.x 版本不包容.

linux 编写翻译安装脚本

那儿候先参照一下官方网站的 libuv 首页 README.md 表明.  

就当下来讲依然多用 Python 二.七 认为. 随后安装 gyp google
推出的跨平台编写翻译意况.

# libuv 安装cdwget https://github.com/libuv/libuv/archive/v1.23.1.zipunzip v1.23.1.zipcd libuv-1.23.1sh autogen.sh./configuremake -j4sudo make installsudo ldconfigcd## 注意 uv 头文件, 全部导入到系统 include 目录下面#rm -rf libuv-1.23.1 v1.23.1.zip

先安装 Python 2.7 . 扯一点.  多年来 python 好虎 (20一七年12月2二5日), 
然而依旧不知道为何 2.7 和 三.x 版本不包容. 

  gyp –

注意要将编写翻译后 include 完整拷贝到安装目录 include下. 那样 uv
头文件全, 日后会用到.

就现阶段来说照旧多用 Python 二.七 以为.  随后安装 gyp google
推出的跨平台编写翻译情况.

是因为选用的是 VS20一七, 原始版本 gyp 不援助, 请参照作者提的这几个提交,
举行改造让其援救 VS201柒 版本

libuv 开箱即用, 不太急需哪些基础封装.

  gyp
– 

  gyp-vs2017 version

3.pthread –

由于使用的是 VS2017, 原始版本 gyp 不辅助, 请参照笔者提的这几个提交,
举办修改让其扶助 VS20一柒 版本

ok winds 10 + VS201七 + libuv-一.1捌.0 + python2.七 + gyp + gyp vs2017version 编写翻译碰着搭建实现.

  那是终极那半个, 为 winds 引进 POSIX thread
模型.编写翻译起来很轻松(前提大家 VS 玩的熟).

  gyp-vs2017
version 
– 

千帆竞发走起, 先进入 gyp 目录试行

扯点闲篇. linux 和 winds 相反相成, 相持而统1. 1个是任何从头码,
三个方始就曾经登记未来.

ok winds 十 + VS20一七 + libuv-一.1捌.0 + python二.七 + gyp + gyp vs20一7version 编写翻译情形搭建完成.

python .\setup.py install

讲述不会细小, 但差不离那意思. (四个都不 eary, 玩很久才敢入门见大叔大姑) .
那里包装了一层

始于走起, 先进入 gyp 目录实行 

图片 3

thread.h

python .\setup.py install

做到后, 早先创设 uv.sln 工程. 先进入 libuv-1.1八.0 伊始目录, 施行上面发号施令

#ifndef _H_THREAD#define _H_THREAD#include "struct.h"#include <pthread.h>#include <semaphore.h>//// pthread_end - 等待启动线程结束// tid      : 线程id// return   : void//inline void pthread_end(pthread_t tid) {    pthread_join(tid, NULL);}//// pthread_run - 异步启动线程// id       : &tid 线程id地址// frun     : 运行的主体// arg      : 运行参数// return   : 返回线程构建结果, 0 is success//#define pthread_run(id, frun, arg)                                  \pthread_run_(&(id), , (void *)inline int pthread_run_(pthread_t * id, node_f frun, void * arg) {    return pthread_create(id, NULL, frun, arg);}//// pthread_async - 异步启动分离线程// frun     : 运行的主体// arg      : 运行参数// return   : 返回 0 is success// #define pthread_async(frun, arg)                                    \pthread_async_, (void *)inline int pthread_async_(node_f frun, void * arg) {    int ret;    pthread_t tid;    pthread_attr_t attr;    pthread_attr_init(&attr);    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);    ret = pthread_create(&tid, &attr, frun, arg);    pthread_attr_destroy(&attr);    return ret;}#endif//_H_THREAD

图片 3

 .\vcbuild.bat release vs2017 x64 static

运用今世编写翻译器包容性构建了 pthread 二种启动宏, 后续写 pthread create
相关代码会贯虱穿杨!

姣好后, 开端营造 uv.sln 工程. 先进入 libuv-壹.1八.0 开头目录,
实行下边命令 

随之能够瞥见 uv.sln 和Release\lib\libuv.lib 生成文件. 编写翻译进度中
x6四版本警告不少. 你一点一滴能够尝尝解决,

到此大家大1统治线程模型就定下来了. 还附带引出了三个很重大帮忙头文件.

 .\vcbuild.bat release vs2017 x64 static

重视是 linux 和 winds 对于 POSIX socket writev
批量读写达成的布局用了不同类型导致的.

struct.h

继而能够瞥见 uv.sln 和 Release\lib\libuv.lib 生成文件. 编写翻译进度中
x6四本子警告不少.  你完全能够尝试化解,

本身改了它有个别源码和测试代码, 解决了整套警告. 详细 libuv 在 VS2017下边运用无外乎 include + lib

#ifndef _H_STRUCT#define _H_STRUCT#include <math.h>#include "alloc.h"#include <ctype.h>#include <float.h>#include <stdio.h>#include <errno.h>#include <assert.h>#include <stdarg.h>#include <stdint.h>#include <stddef.h>#include <limits.h>#include <stdbool.h>#include <inttypes.h>//// enum Flag int - 函数返回值全局状态码// >= 0 标识 Success 状态, < 0 标识 Error 状态//enum {    SBase       =  +0, // 正确基础类型    EBase       =  -1, // 错误基础类型    EParam      =  -2, // 输入参数错误    EFd         =  -3, // 文件打开失败    EClose      =  -4, // 文件操作关闭    EAccess     =  -5, // 没有操作权限    EAlloc      =  -6, // 内存操作错误    EParse      =  -7, // 协议解析错误    ESmall      =  -8, // 过小基础错误    EBig        =  -9, // 过大基础错误    ETimeout    = -10, // 操作超时错误};//// DCODE - DEBUG 模式下的测试宏// DCODE({//     puts("debug start...");// });//#ifndef DCODE#   ifdef _DEBUG#       define DCODE  do code while(0)#   else#       define DCODE  #   endif //  ! _DEBUG#endif  //  ! DCODE//// icmp_f - 比较行为的类型//  : int add_cmp(const void * now, const void * node)//typedef int (* icmp_f)();//// vnew_f - 根据规则构建对象//  : void * rtree_new(void * node)//typedef void * (* vnew_f)();//// node_f - 销毁当前对象节点//  : void list_die(void * node); //typedef void (void * node);//// start_f - pthread create func//  : int * run(int * arg)//typedef void * (* start_f)(void * arg);//// each_f - each 循环操作, arg 外部参数, node 是内部结点//  : int dict_echo(struct dict * node, void * arg) { return 0; }//typedef int (void * node, void * arg);//// CERR - 打印错误信息// EXIT - 打印错误信息, 并 exit// IF   - 条件判断异常退出的辅助宏//#define CERR                                                   \fprintf(stderr, "[%s:%s:%d][%d:%s]" fmt "\n",                            \    __FILE__, __func__, __LINE__, errno, strerror, ##__VA_ARGS__)#define EXIT                                                   \do {                                                                     \    CERR(fmt, ##__VA_ARGS__);                                            \    exit(EXIT_FAILURE);                                                  \} while(0)#define IF                                                         \if  EXIT//// RETURN - 打印错误信息, 并 return 返回指定结果// val      : return的东西, 当需要 return void; 时候填 ',' 就过 or NIL// fmt      : 双引号包裹的格式化字符串// ...      : fmt中对应的参数// return   : val// #define RETURN(val, fmt, ...)                                           \do {                                                                    \    CERR(fmt, ##__VA_ARGS__);                                           \    return val;                                                         \} while(0)#define NIL#define RETNIL                                                \RETURN(NIL , fmt, ##__VA_ARGS__)#define RETNUL                                                \RETURN(NULL, fmt, ##__VA_ARGS__)#endif//_H_STRUCT

关键是 linux 和 winds 对于 POSIX socket writev
批量读写达成的布局用了不均等类型导致的. 

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

笔者尝试写 structc 项目时首先个源文件 : )

和睦改了它有个别源码和测试代码, 消除了整个警告. 详细 libuv 在 VS20一七上面使用无外乎 include + lib 

图片 5

0.2 IDE 弱议

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

再加上项目工程中程导弹入上边库

   winds 没得选, 最新最全的 visual studio best version 有才干统治一切.
那边根本说

 图片 5 

advapi32.libiphlpapi.libpsapi.libshell32.libuser32.libuserenv.libws2_32.lib

的是linux 上边大家的采纳. 最伊始小编是 vi + make + gcc + gdb 开辟和编写翻译的.

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

头文件什么的轻便导入下边就能够了

Makefile –

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
# 编译的目录结构# Release : make # Debug   : make D=-D_DEBUG# Clean   : make clean

头文件什么的简短程核导弹入上面就足以了 

到那大约 libuv winds 就水到渠成了.

make 是编写翻译宣布,make D=-D_DEBUG 是编写翻译 Debug, make clean 项目清理.
手工业操作.

WIN32_LEAN_AND_MEAN
_CRT_SECURE_NO_WARNINGS
_CRT_NONSTDC_NO_DEPRECATE
_WINSOCK_DEPRECATED_NO_WARNINGS

此地写了个示范 demo, 有意思味的能够尝尝演练一下

那般搞对小编都幸而, 什么都行.

到那基本上 libuv winds 就马到成功了.  

#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;    //    // \033[2J      : 清屏    // \033[H       : 光标移到    // \033[%dB     : 光标下移 %d 行    // \033[%dC     : 光标右移 %d 行    // \033[42;37m  : 底色 41 绿底, 字色 37 白字    //    // \033[0m      : 关闭所有属性    //    buf.len = sprintf(data, "\033[2J\033[H\033[%dB\033[%dC\033[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 = "\033[0m";        strcat(data, resets);        buf.len += (int)strlen;    }    // 写入消息    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\n");        uv_tty_reset_mode();        return;    }    fprintf(stderr, "Width %d, height %d\n", 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);}

但不要紧更加精进一步 [vi + make + gcc + gdb] -> [code + F5 + F10 +
F11] 是或不是更妙.

此处写了个示范 demo, 风乐趣的可以尝尝演习一下

其一显示屏新闻会动 哈哈, : )

微软当作桌面软件霸主, code(VSCode 简称)不用笔者多说, 不得不服. 那开搞

#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;
    //
    // \033[2J      : 清屏
    // \033[H       : 光标移到(0, 0)
    // \033[%dB     : 光标下移 %d 行
    // \033[%dC     : 光标右移 %d 行
    // \033[42;37m  : 底色 41 绿底, 字色 37 白字
    //
    // \033[0m      : 关闭所有属性
    //
    buf.len = sprintf(data, "\033[2J\033[H\033[%dB\033[%dC\033[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 = "\033[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\n");
        uv_tty_reset_mode();
        return;
    }

    fprintf(stderr, "Width %d, height %d\n", 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);
}

图片 7

  1. 安装软件

其1荧屏信息会动 哈哈, : )

(二傻子 入场 ~ )

  ubuntu best version

图片 7 

正文 – 稍加练习

  vscode

(二傻子 入场 ~ ) 

  通过上述对libuv遇到的搭建和省略先入为主的概念性描述,.
此时统统能够应用 libuv tty 轻易做个

 安装好 vscode 后, 在当中间安装插件 Microsoft C/C++ for Visual Studio
Code

 

跨平台的小动画了. 小编先写个, 推荐咱们参考例子抄写2回, 培育手感.
扯一点互连网本事有四个趋势

2.F1 -> Edit Configurations -> c_cpp_properties.json

正文 – 稍加练习

架构师和技能术专科学校家. 有点像从前游戏开垦中服务器架设和客户端引擎.
不过C技师依旧重申手感,

 设置如下内容和VS配置很相似

  通过以上对libuv意况的搭建和简单先入为主的概念性描述,.
此时统统可以使用 libuv tty 轻易做个

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

{    "configurations": [        {            "name": "Linux",            "includePath": [                "/usr/include/c++/7",                "/usr/include/x86_64-linux-gnu/c++/7",                "/usr/include/c++/7/backward",                "/usr/lib/gcc/x86_64-linux-gnu/7/include",                "/usr/local/include",                "/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed",                "/usr/include/x86_64-linux-gnu",                "/usr/include",                "${workspaceRoot}",                "${workspaceRoot}/structc/base",                "${workspaceRoot}/structc/struct",                "${workspaceRoot}/structc/system"            ],            "defines": [                "_DEBUG",                "__GNUC__"            ],            "intelliSenseMode": "clang-x64",            "browse": {                "path": [                    "/usr/include/c++/7",                    "/usr/include/x86_64-linux-gnu/c++/7",                    "/usr/include/c++/7/backward",                    "/usr/lib/gcc/x86_64-linux-gnu/7/include",                    "/usr/local/include",                    "/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed",                    "/usr/include/x86_64-linux-gnu",                    "/usr/include",                    "${workspaceRoot}"                ],                "limitSymbolsToIncludedHeaders": true,                "databaseFilename": ""            },            "compilerPath": "/usr/bin/clang",            "cStandard": "c11",            "cppStandard": "c++17"        }    ],    "version": 4}

跨平台的小动画了.  小编先写个, 推荐大家参考例子抄写3回, 作育手感.
扯一点互连网才干有两个趋势

#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"  背影 :- 汪国真\n",    u8"  \n",    u8"  背影\n",    u8"  总是很简单\n",    u8"  简单\n",    u8"  是一种风景\n",    u8"  \n",    u8"  背影\n",    u8"  总是很年轻\n",    u8"  年轻\n",    u8"  是一种清明\n",    u8"  \n",    u8"  背影\n",    u8"  总是很含蓄\n",    u8"  含蓄\n",    u8"  是一种魅力\n",    u8"  \n",    u8"  背影\n",    u8"  总是很孤零\n",    u8"  孤零\n",    u8"  更让人记得清\n"};// _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 != 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;    // 初始化定时器    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, "\033[2J\033[H\033[%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;    // 运行结束直接返回    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);}

3.F5 -> launch.json

架构师和手艺专家. 有点像之前游戏支付中服务器架设和客户端引擎.
可是C技师照旧重申手感,

职能是从上到下输出了汪国真先生诗词背影~ 🙂

依照规律改 program 项面生成 和 preLaunchTask 前置职分

弱化架构, 追求极致的统1.  (说白点, 代码更首要, 能说越来越好.)

  背影 –

{    // 使用 IntelliSense 了解相关属性。     // 悬停以查看现有属性的描述。    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387    "version": "0.2.0",    "configurations": [        {            "name": " Launch",            "type": "cppdbg",            "request": "launch",            "program": "${workspaceFolder}/Out/main.exe",            "args": [],            "stopAtEntry": false,            "cwd": "${workspaceFolder}",            "environment": [],            "externalConsole": true,            "preLaunchTask": "Debug",            "MIMode": "gdb",            "setupCommands": [                {                    "description": "Enable pretty-printing for gdb",                    "text": "-enable-pretty-printing",                    "ignoreFailures": true                }            ]        }    ]}
#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"  背影 :- 汪国真\n",
    u8"  \n",
    u8"  背影\n",
    u8"  总是很简单\n",
    u8"  简单\n",
    u8"  是一种风景\n",
    u8"  \n",
    u8"  背影\n",
    u8"  总是很年轻\n",
    u8"  年轻\n",
    u8"  是一种清明\n",
    u8"  \n",
    u8"  背影\n",
    u8"  总是很含蓄\n",
    u8"  含蓄\n",
    u8"  是一种魅力\n",
    u8"  \n",
    u8"  背影\n",
    u8"  总是很孤零\n",
    u8"  孤零\n",
    u8"  更让人记得清\n"
};

// _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), "\033[2J\033[H\033[%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);
}

背景, 总是相当粗略, 更令人记得清

4.F5 -> tasks.json

功效是从上到下输出了汪国真先生诗词背影~ 🙂 

图片 9

建立上面任务, 近来只利用了 Debug

  背影 –

后记 – 好久没扯淡了

{    // See https://go.microsoft.com/fwlink/?LinkId=733558    // for the documentation about the tasks.json format    "version": "2.0.0",    "tasks": [        {            "type"    : "shell",            "label"   : "Debug",            "command" : "make D=-D_DEBUG"        }    ]}

      背景,  总是很轻便, 更令人记得清 

  有标题招待交换, 错误是难免的, 发现再改吧 ~ O_O

此时大家就足以 F伍 搞起来 ~

图片 9

  只为你活一天

图片 11

 

  

汉子们是还是不是很亲切, 这么复杂定制化项目都能够可视化调节和测试. 还有何人 ~当然 IDE
有没有

后记 – 好久没扯淡了

  

都好说,难说的是你是不是耐的下心去感悟技术的系统,可无法学京东手艺,
对开源缺失敬畏

  有标题迎接交换, 错误是免不了的, 开掘再改吧 ~  O_O

之心, 才能不见得多厉害, 节操提前贷款没了 ~最后形成奥义之梗 : )

  只为你活1天
– 

前言 – 无妨说点布署

 

  进入 structc/structc 看到以下项目组织

 

wzhi@wzc:~/structc/structc$ tree -L 1.├── base├── conf├── main├── README.md├── struct├── structc.vcxproj├── structc.vcxproj.filters├── structc.vcxproj.user├── system└── test

  

base : 基础接口封装目录

  

conf : 配置文件目录

main : 主函数目录

struct : 数据结构接口目录

system : 系统库包装目录

test : 单元测试目录

一.0 main 主函数设计

wzhi@wzc:~/structc/structc/main$ tree.├── main.c├── main_init.c├── main_run.c└── main_test.c

首要关心下入口 mian 主函数设计 main.c

#include "head.h"//// main - 程序的总入口, 从扯开始// argc     : 输入参数个数// argv     : 参数集// return   : 返回程序退出的状态码//int main(int argc, char * argv[]) {    //    // 初始化 ... ...    // ... ...    EXTERN_RUN(main_init);    //    // make D=-D_DEBUG    // main_test 单元测试才会启动    //#ifdef _DEBUG    EXTERN_RUN(main_test);#endif    // ...     // ... 启动当前项目运行的主函数    //    EXTERN_RUN(main_run, argc, argv);    return EXIT_SUCCESS;}

其中 EXTERN_RUN 也很精妙

//// EXTERN_RUN - 简单的声明, 并立即使用的宏// ftest    : 需要执行的函数名称// ...      : 可变参数, 保留//#define EXTERN_RUN(ftest, ...)                                  \do {                                                            \    extern void ftest();                                        \    ftest (__VA_ARGS__);                                        \} while(0)

穿过评释直接选择的宏注解. structc 中 main 函数1共做了二件半事情.

main_init 开头化函数, main_run 业务运营函数, 还有半个 main_test
运维单元测试.

继之大家好美观看那几个单元测试套路.

一.1 test 单元测试套路设计

先看看 main_test.c

#include "head.h"//// TEST - 用于单元测试函数, 执行并输出运行时间// ftest    : 需要执行的测试函数名称// ...      : 可变参数, 保留//#define TEST(ftest, ...)                                         \do {                                                             \    extern void ftest();                                         \    clock_t $s = clock();                                        \    ftest (##__VA_ARGS__);                                       \    double $e = (double)clock();                                 \    printf(STR" run time:%lfs\n", /CLOCKS_PER_SEC);\} while(0)//// main_test - *_test is here run// return   : void//void main_test(void) {    //    // 开始你的表演, 单元测试    //    EXTERN_RUN(uv_tty_test);}

以上只授予了政工测试的才干. 在那之中 uv_tty_test
函数就是单元测试目录下里面一个的单元测试函数体.

而笔者辈每一种职业测试函数, 顺带会创制叁个同名的 .c 文件.
比方那里是uv_tty_test.c

#include <uv.h>#include <stdio.h>#include <stdlib.h>#include <string.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 != UV_TTY!\n");        exit(EXIT_FAILURE);    }    uv_tty_init(loop, &tty, 1, 0);    uv_tty_set_mode(&tty, UV_TTY_MODE_NORMAL);    // 开始发送消息    buf[0].base = "\033[46;37m";    buf[1].base = u8" 喵酱  比 ♥ 里~ \n";    buf[2].base = "\033[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);}

思路很直白. 这么些正是单元测试的真相… . 相比较明晰的来得

一.二 system 系统库设计

这么些中设计东东广大, 只挑一些经文的供人看看. 代码即注释 ~

socket.h

#ifndef _H_SOCKET#define _H_SOCKET#include <time.h>#include <fcntl.h>#include "struct.h"#include <signal.h>#include <sys/types.h>#ifdef __GNUC__#include <netdb.h>#include <unistd.h>#include <sys/un.h>#include <sys/uio.h>#include <sys/time.h>#include <arpa/inet.h>#include <sys/socket.h>#include <netinet/tcp.h>#include <sys/resource.h>//// This is used instead of -1, since the. by WinSock// On now linux EAGAIN and EWOULDBLOCK may be the same value // connect 链接中, linux 是 EINPROGRESS,winds 是 WSAEWOULDBLOCK//typedef int socket_t;#define INVALID_SOCKET          #define SOCKET_ERROR            // socket_init - 初始化 socket 库初始化方法inline void socket_init(void) {    // 管道破裂, 忽略 SIGPIPE 信号    signal(SIGPIPE, SIG_IGN);}inline int socket_close(socket_t s) {    return close;}// socket_set_block     - 设置套接字是阻塞// socket_set_nonblock  - 设置套接字是非阻塞inline int socket_set_block(socket_t s) {    int mode = fcntl(s, F_GETFL, 0);    return fcntl(s, F_SETFL, mode & ~O_NONBLOCK);}inline int socket_set_nonblock(socket_t s) {    int mode = fcntl(s, F_GETFL, 0);    return fcntl(s, F_SETFL, mode | O_NONBLOCK);}// socket_recv      - 读取数据// socket_send      - 写入数据inline int socket_recv(socket_t s, void * buf, int sz) {    return (int)read(s, buf, sz);}inline int socket_send(socket_t s, const void * buf, int sz) {    return (int)write(s, buf, sz);}#endif#ifdef _MSC_VER#include <ws2tcpip.h>#undef  errno#define errno                   WSAGetLastError()#undef  strerror#define strerror                ((char * strerr)#undef  EINTR#define EINTR                   WSAEINTR#undef  EAGAIN#define EAGAIN                  WSAEWOULDBLOCK#undef  EINPROGRESS#define EINPROGRESS             WSAEWOULDBLOCK/* * WinSock 2 extension -- manifest constants for shutdown() */#define SHUT_RD                 SD_RECEIVE#define SHUT_WR                 SD_SEND#define SHUT_RDWR               SD_BOTH#define SO_REUSEPORT            SO_REUSEADDRtypedef SOCKET socket_t;typedef int socklen_t;//// gettimeofday - Linux sys/time.h 中得到微秒时间实现// tv       : 返回结果包含秒数和微秒数// tz       : 包含的时区, winds 上这个变量没有作用// return   : 默认返回 0//extern int gettimeofday(struct timeval * tv, void * tz);//// strerr - linux 上替代 strerror, winds 替代 FormatMessage // error    : linux 是 errno, winds 可以是 WSAGetLastError() ... // return   : system os 拔下来的提示常量字符串//extern const char * strerr(int err);// socket_init - 初始化 socket 库初始化方法inline void socket_init(void) {    WSADATA wsad;    WSAStartup(WINSOCK_VERSION, &wsad);}// socket_close     - 关闭上面创建后的句柄inline int socket_close(socket_t s) {    return closesocket;}// socket_set_block     - 设置套接字是阻塞// socket_set_nonblock  - 设置套接字是非阻塞inline int socket_set_block(socket_t s) {    u_long mode = 0;    return ioctlsocket(s, FIONBIO, &mode);}inline int socket_set_nonblock(socket_t s) {    u_long mode = 1;    return ioctlsocket(s, FIONBIO, &mode);}// socket_recv      - 读取数据// socket_send      - 写入数据inline int socket_recv(socket_t s, void * buf, int sz) {    return sz > 0 ? recv(s, buf, sz, 0) : 0;}inline int socket_send(socket_t s, const void * buf, int sz) {    return send(s, buf, sz, 0);}#endif//// 通用 sockaddr_in ipv4 地址//typedef struct sockaddr_in sockaddr_t[1];// socket_dgram     - 创建 UDP socket// socket_stream    - 创建 TCP socketinline socket_t socket_dgram(void) {    return socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);}inline socket_t socket_stream(void) {    return socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);}// socket_set_reuse - 开启端口和地址复用// socket_set_keepalive - 开启心跳包检测, 默认2h 5次inline int socket_set_enable(socket_t s, int optname) {    int ov = 1;    return setsockopt(s, SOL_SOCKET, optname, (void *)&ov, sizeof ov);}inline int socket_set_reuse(socket_t s) {    return socket_set_enable(s, SO_REUSEPORT);}inline int socket_set_keepalive(socket_t s) {    return socket_set_enable(s, SO_KEEPALIVE);}// socket_set_rcvtimeo - 设置接收数据毫秒超时时间// socket_set_sndtimeo - 设置发送数据毫秒超时时间inline int socket_set_time(socket_t s, int ms, int optname) {    struct timeval ov = { 0,0 };    if (ms > 0) {        ov.tv_sec = ms / 1000;        ov.tv_usec = (ms % 1000) * 1000;    }    return setsockopt(s, SOL_SOCKET, optname, (void *)&ov, sizeof ov);}inline int socket_set_rcvtimeo(socket_t s, int ms) {    return socket_set_time(s, ms, SO_RCVTIMEO);}inline int socket_set_sndtimeo(socket_t s, int ms) {    return socket_set_time(s, ms, SO_SNDTIMEO);}// socket_get_error - 得到当前socket error 值, 0 表示正确, 其它都是错误inline int socket_get_error(socket_t s) {    int err;    socklen_t len = sizeof;    int r = getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)&err, &len);    return r < 0 ? errno : err;}// socket_recvfrom  - recvfrom 接受函数// socket_sendto    - sendto 发送函数inline int socket_recvfrom(socket_t s, void * buf, int len, int flags, sockaddr_t in) {    socklen_t inlen = sizeof (sockaddr_t);    return recvfrom(s, buf, len, flags, (struct sockaddr *)in, &inlen);}inline int socket_sendto(socket_t s, const void * buf, int len, int flags, const sockaddr_t to) {    return sendto(s, buf, len, flags, (const struct sockaddr *)to, sizeof(sockaddr_t));}//// socket_recvn     - socket 接受 sz 个字节// socket_sendn     - socket 发送 sz 个字节//extern int socket_recvn(socket_t s, void * buf, int sz);extern int socket_sendn(socket_t s, const void * buf, int sz);// socket_bind          - bind    绑定函数// socket_listen        - listen  监听函数// socket_accept        - accept  等接函数// socket_connect       - connect 链接函数inline int socket_bind(socket_t s, const sockaddr_t addr) {    return bind(s, (const struct sockaddr *)addr, sizeof(sockaddr_t));}inline int socket_listen(socket_t s) {    return listen(s, SOMAXCONN);}inline socket_t socket_accept(socket_t s, sockaddr_t addr) {    socklen_t len = sizeof (sockaddr_t);    return accept(s, (struct sockaddr *)addr, &len);}inline int socket_connect(socket_t s, const sockaddr_t addr) {    return connect(s, (const struct sockaddr *)addr, sizeof(sockaddr_t));}//// socket_binds     - 端口绑定返回绑定好的 socket fd, 返回 INVALID_SOCKET or PF_INET PF_INET6// socket_listens   - 端口监听返回监听好的 socket fd.//extern socket_t socket_binds(const char * ip, uint16_t port, uint8_t protocol, int * family);extern socket_t socket_listens(const char * ip, uint16_t port, int backlog);//// socket_addr -socket_recv 通过 ip, port 构造 ipv4 结构//extern int socket_addr(const char * ip, uint16_t port, sockaddr_t addr);// socket_pton - 返回 ip 串inline char * socket_pton(sockaddr_t addr, char ip[INET_ADDRSTRLEN]) {    return (char *)inet_ntop(AF_INET, &addr->sin_addr, ip, INET_ADDRSTRLEN);}//// socket_host - 通过 ip:port 串得到 socket addr 结构// host     : ip:port 串// addr     : 返回最终生成的地址// return   : >= EBase 表示成功//extern int socket_host(const char * host, sockaddr_t addr);//// socket_tcp - 创建 TCP 详细套接字// host     : ip:port 串  // return   : 返回监听后套接字//extern socket_t socket_tcp(const char * host);//// socket_udp - 创建 UDP 详细套接字// host     : ip:port 串  // return   : 返回绑定后套接字//extern socket_t socket_udp(const char * host);//// socket_connects - 返回链接后的阻塞套接字// host     : ip:port 串  // return   : 返回链接后阻塞套接字//extern socket_t socket_connects(const char * host);//// socket_connectos - 返回链接后的非阻塞套接字// host     : ip:port 串  // ms       : 链接过程中毫秒数// return   : 返回链接后非阻塞套接字//extern socket_t socket_connectos(const char * host, int ms);#endif//_H_SOCKET

socket.c

#include "socket.h"#ifdef _MSC_VER//// gettimeofday - Linux sys/time.h 中得到微秒时间实现// tv       : 返回结果包含秒数和微秒数// tz       : 包含的时区, winds 上这个变量没有作用// return   : 默认返回 0//int gettimeofday(struct timeval * tv, void * tz) {    struct tm m;    SYSTEMTIME se;    GetLocalTime(&se);    m.tm_year = se.wYear - 1900;    m.tm_mon = se.wMonth - 1;    m.tm_mday = se.wDay;    m.tm_hour = se.wHour;    m.tm_min = se.wMinute;    m.tm_sec = se.wSecond;    m.tm_isdst = -1; // 不考虑夏令时    tv->tv_sec = (long)mktime(&m);    tv->tv_usec = se.wMilliseconds * 1000;    return 0;}#endif//// socket_recvn     - socket 接受 sz 个字节// socket_sendn     - socket 发送 sz 个字节//int socket_recvn(socket_t s, void * buf, int sz) {    int r, n = sz;    while (n > 0) {        r = recv(s, buf, n, 0);        if (r == 0) break;        if (r == SOCKET_ERROR) {            if (errno == EINTR)                continue;            return SOCKET_ERROR;        }        n -= r;        buf = (char *)buf + r;    }    return sz - n;}int socket_sendn(socket_t s, const void * buf, int sz) {    int r, n = sz;    while (n > 0) {        r = send(s, buf, n, 0);        if (r == 0) break;        if (r == SOCKET_ERROR) {            if (errno == EINTR)                continue;            return SOCKET_ERROR;        }        n -= r;        buf = (char *)buf + r;    }    return sz - n;}//// socket_addr - 通过 ip, port 构造 ipv4 结构//int socket_addr(const char * ip, uint16_t port, sockaddr_t addr) {    addr->sin_family = AF_INET;    addr->sin_port = htons;    addr->sin_addr.s_addr = inet_addr;    if (addr->sin_addr.s_addr == INADDR_NONE) {        struct hostent * host = gethostbyname;        if (!host || !host->h_addr)            return EParam;        // 尝试一种, 默认 ipv4        memcpy(&addr->sin_addr, host->h_addr, host->h_length);    }    memset(addr->sin_zero, 0, sizeof addr->sin_zero);    return SBase;}//// socket_binds     - 端口绑定返回绑定好的 socket fd, 返回 INVALID_SOCKET or PF_INET PF_INET6// socket_listens   - 端口监听返回监听好的 socket fd.//socket_t socket_binds(const char * ip, uint16_t port, uint8_t protocol, int * family) {    socket_t fd;    char ports[sizeof "65535"];    struct addrinfo * addr = NULL, hint = { 0 };    if (NULL == ip || *ip == '\0')        ip = "0.0.0.0"; // default INADDR_ANY    sprintf(ports, "%hu", port);    hint.ai_family = AF_UNSPEC;    if (protocol == IPPROTO_TCP)        hint.ai_socktype = SOCK_STREAM;    else {        assert(protocol == IPPROTO_UDP);        hint.ai_socktype = SOCK_DGRAM;    }    hint.ai_protocol = protocol;    if (getaddrinfo(ip, ports, &hint, &addr))        return INVALID_SOCKET;    fd = socket(addr->ai_family, addr->ai_socktype, 0);    if (fd == INVALID_SOCKET)        goto err_free;    if (socket_set_reuse        goto err_close;    if (bind(fd, addr->ai_addr, (int)addr->ai_addrlen))        goto err_close;    // Success return ip family    if         *family = addr->ai_family;    freeaddrinfo;    return fd;err_close:    socket_close;err_free:    freeaddrinfo;    return INVALID_SOCKET;}socket_t socket_listens(const char * ip, uint16_t port, int backlog) {    socket_t fd = socket_binds(ip, port, IPPROTO_TCP, NULL);    if (INVALID_SOCKET != fd && listen(fd, backlog)) {        socket_close;        return INVALID_SOCKET;    }    return fd;}// host_parse - 解析 host 内容static int host_parse(const char * host, char ip[BUFSIZ], uint16_t * pprt) {    int port = 0;    char * st = ip;    if (!host || !*host || *host == ':')        strcpy(ip, "0.0.0.0");    else {        char c;        // 简单检查字符串是否合法        size_t n = strlen;        if (n >= BUFSIZ)            RETURN(EParam, "host err %s", host);        // 寻找分号        while ((c = *host++) != ':' && c)            *ip++ = c;        *ip = '\0';        if (c == ':') {            if (n > ip - st + sizeof "65535")                RETURN(EParam, "host port err %s", host);            port = atoi;            // 有些常识数字, 不一定是魔法 ... :)            if (port <= 1024 || port > 65535)                RETURN(EParam, "host port err %s, %d", host, port);        }    }    *pprt = port;    return SBase;}//// socket_host - 通过 ip:port 串得到 socket addr 结构// host     : ip:port 串// addr     : 返回最终生成的地址// return   : >= EBase 表示成功//int socket_host(const char * host, sockaddr_t addr) {    uint16_t port; char ip[BUFSIZ];    if (host_parse(host, ip, &port) < SBase)        return EParam;    // 开始构造 addr    if (NULL == addr) {        sockaddr_t nddr;        return socket_addr(ip, port, nddr);    }    return socket_addr(ip, port, addr);}//// socket_tcp - 创建 TCP 详细套接字// host     : ip:port 串  // return   : 返回监听后套接字//socket_t socket_tcp(const char * host) {    uint16_t port; char ip[BUFSIZ];    if (host_parse(host, ip, &port) < SBase)        return EParam;    return socket_listens(ip, port, SOMAXCONN);}//// socket_udp - 创建 UDP 详细套接字// host     : ip:port 串  // return   : 返回绑定后套接字//socket_t socket_udp(const char * host) {    uint16_t port; char ip[BUFSIZ];    if (host_parse(host, ip, &port) < SBase)        return EParam;    return socket_binds(ip, port, IPPROTO_UDP, NULL);}//// socket_connects - 返回链接后的阻塞套接字// host     : ip:port 串  // return   : 返回链接后阻塞套接字//socket_t socket_connects(const char * host) {    sockaddr_t addr;    socket_t s = socket_stream();    if (INVALID_SOCKET == s) {        RETURN(s, "socket_stream is error");    }    // 解析配置成功后尝试链接    if (socket_host(host, addr) >= SBase)        if (socket_connect >= SBase)            return s;    socket_close;    RETURN(INVALID_SOCKET, "socket_connects %s", host);}//// socket_connecto      - connect 超时链接, 返回非阻塞 socket//static int socket_connecto(socket_t s, const sockaddr_t addr, int ms) {    int n, r;    struct timeval to;    fd_set rset, wset, eset;    // 还是阻塞的connect    if (ms < 0) return socket_connect;    // 非阻塞登录, 先设置非阻塞模式    r = socket_set_nonblock;    if (r < SBase) return r;    // 尝试连接, connect 返回 -1 并且 errno == EINPROGRESS 表示正在建立链接    r = socket_connect;    // connect 链接中, linux 是 EINPROGRESS,winds 是 WSAEWOULDBLOCK    if (r >= SBase || errno != EINPROGRESS) {        socket_set_block;        return r;    }    // 超时 timeout, 直接返回结果 EBase = -1 错误    if (ms == 0) {        socket_set_block;        return EBase;    }    FD_ZERO(&rset); FD_SET(s, &rset);    FD_ZERO(&wset); FD_SET(s, &wset);    FD_ZERO(&eset); FD_SET(s, &eset);    to.tv_sec = ms / 1000;    to.tv_usec = (ms % 1000) * 1000;    n = select((int)s + 1, &rset, &wset, &eset, &to);    // 超时直接滚    if (n <= 0) {        socket_set_block;        return EBase;    }    // 当连接成功时候,描述符会变成可写    if (n == 1 && FD_ISSET(s, &wset)){        socket_set_block;        return SBase;    }    // 当连接建立遇到错误时候, 描述符变为即可读又可写    if (FD_ISSET(s, &eset) || n == 2) {        socklen_t len = sizeof n;        // 只要最后没有 error 那就 链接成功        if (!getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&n, &len) && !n)            r = SBase;    }    socket_set_block;    return r;}//// socket_connectos - 返回链接后的非阻塞套接字// host     : ip:port 串  // ms       : 链接过程中毫秒数// return   : 返回链接后非阻塞套接字//socket_t socket_connectos(const char * host, int ms) {    sockaddr_t addr;    socket_t s = socket_stream();    if (INVALID_SOCKET == s) {        RETURN(s, "socket_stream is error");    }    // 解析配置成功后尝试链接    if (socket_host(host, addr) >= SBase)        if (socket_connecto(s, addr, ms) >= SBase)            return s;    socket_close;    RETURN(INVALID_SOCKET, "socket_connectos %s", host);}

即便 winds, 设计思路也是仿照 linux socket 套路. 营造 socket 接口,
希望位置代码能注解什么是少林

拳法,千锤百练. 前边 base structsystem 代码量不少, 难壹1说.
喜欢的能够继续抄袭一遍. (笔者也是

抄袭别人而走入了编制程序的社会风气, 掌握那分形的人生呢)

正文 – 风吹草动

  通过引言前言认知了 structc 是什么项目, 项目创设,
代码风格等. 那里筹划说一下布置 structc

体系初衷. 很久前写 C 代码, 开掘数据结构分明后, 基本全部系统就定下了.
所以想用 C营造八个通用

粗略的数据结构库. 所以有了那个项目.

  扯一点, 明白 structc 项目后可以为怎么才干加点. 比如学完 struct 目录,
数据结构能够轻巧结课.

抄完system操作系统能够结课.base 清楚后, 框架中间件设计也算入门了.
精晓全体布局后, 实战中的

脚手架设计也只是如此.但缺点也有, 见效慢.C 太老了, 想通过 C 看清编制程序源头,
不下时间是不现实的,

幸运的是最后获得 -> 哈哈-> 怎么脱发又严重了 ….

比如 atom.h

#ifndef _H_ATOM#define _H_ATOM#include "atomic.h"//// atom_t 自旋锁类型// [static] atom_t o = 0;//   atom_lock;//  - One Man RPG// atom_unlock;//typedef volatile long atom_t;// atom_acquire - 维护优化后读写代码不在其前#define atom_acquire()      atomic_fence(ATOMIC_ACQUIRE)// atom_release - 维护优化后读写代码不在其后#define atom_release()      atomic_fence(ATOMIC_RELEASE)// atom_seq_cst - 维护优化后读写代码前后不动#define atom_seq_cst()      atomic_fence(ATOMIC_SEQ_CST)#ifdef __GNUC__#define atom_trylock     (!__sync_lock_test_and_set, 1))#define atom_lock        while(__sync_lock_test_and_set, 1))#define atom_unlock      __sync_lock_release// 内存屏障, 维持代码顺序#define atom_sync()         __sync_synchronize()// v += a ; return v;#define atom_add      __sync_add_and_fetch, // type tmp = v ; v = a; return tmp;#define atom_set      __sync_lock_test_and_set, // v &= a; return v;#define atom_and      __sync_and_and_fetch, // return ++v;#define atom_inc         __sync_add_and_fetch, 1)// return --v;#define atom_dec         __sync_sub_and_fetch, 1)// bool b = v == c; b ? v=a : ; return b;#define atom_cas   __sync_bool_compare_and_swap, #endif#ifdef _MSC_VER#include <intrin.h>#include <intrin0.h>/* Interlocked intrinsic mapping for _nf/_acq/_rel */#if defined || defined#define _ACQUIRE ATOMIC_CONCAT#else /* defined || defined */#define _ACQUIRE x#endif /* defined || defined */#define atom_trylock     (!_ACQUIRE(_interlockedbittestandset), 0))#define atom_lock        while(_ACQUIRE(_interlockedbittestandset), 0))inline void store_release(atom_t * x) {    /* store _Value atomically with release memory order */#if defined || defined    __dmb(0xB /* _ARM_BARRIER_ISH or _ARM64_BARRIER_ISH*/);    __iso_volatile_store32((volatile int *)x, 0);#else    _ReadWriteBarrier();    *x = 0;#endif}#define atom_unlock      store_release// 保证代码优化后不乱序执行#define atom_sync()         MemoryBarrier()// v 和 a 都是 long 这样数据#define atom_add      InterlockedAdd((volatile LONG *)&, #define atom_set      InterlockedExchange((volatile LONG *)&, #define atom_and      InterlockedAnd((volatile LONG *)&, #define atom_inc         InterlockedIncrement((volatile LONG *)&#define atom_dec         InterlockedDecrement((volatile LONG *)&//// 对于 InterlockedCompareExchange 等价于下面// long tmp = v ; v == a ? v = c : ; return tmp;//// 咱们的 atom_cas 等价于下面// long tmp = v ; v == c ? v = a : ; return tmp;//#define atom_cas    == InterlockedCompareExchange((volatile LONG *)&, , )#endif#endif//_H_ATOM

代码在改中变的有意味, 有态度. 当然更招待同行给予补偿, 共同升高提高 ~

毕竟错误是难免的 : )  

后记 – 江湖再会

金子陵-

图片 12

相关文章