您的位置:新葡亰496net > 新葡亰官网 > 新葡亰496net:Service服务端和客商端程序,多维数

新葡亰496net:Service服务端和客商端程序,多维数

发布时间:2019-10-31 18:25编辑:新葡亰官网浏览(123)

    前端高性能计算之二:asm.js & webassembly

    2017/10/21 · HTML5 · webassembly

    原文出处: magicly   

    前一篇我们说了要解决高性能计算的两个方法,一个是并发用WebWorkers,另一个就是用更底层的静态语言。

    2012年,Mozilla的工程师Alon Zakai在研究LLVM编译器时突发奇想:能不能把C/C 编译成Javascript,并且尽量达到Native代码的速度呢?于是他开发了Emscripten编译器,用于将C/C 代码编译成Javascript的一个子集asm.js,性能差不多是原生代码的50%。大家可以看看这个PPT。

    之后Google开发了Portable Native Client,也是一种能让浏览器运行C/C 代码的技术。 后来估计大家都觉得各搞各的不行啊,居然Google, Microsoft, Mozilla, Apple等几家大公司一起合作开发了一个面向Web的通用二进制和文本格式的项目,那就是WebAssembly,官网上的介绍是:

    WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web.

    WebAssembly is currently being designed as an open standard by a W3C Community Group that includes representatives from all major browsers.

    所以,WebAssembly应该是一个前景很好的项目。我们可以看一下目前浏览器的支持情况: 新葡亰496net 1

    安装依赖

       数组一旦被定义了,它的维数和维界就不会变。因此,除了结构的初始化和销毁之外,数组只有存取元素和修改元素。数组一般分为行序和列许。一般系统都是用的行许。
    以2维数组a[m][n]为例
    列序:
    a[0][0]  a[1][0] ...... a[m-1][0]
    .............
    a[m-1][0] a[m-1][1] ...... a[m-1][n-1]

    1、功能说明:

    最近,遇到一个c语言的不定参数问题。其实,对于c语言的不定参数问题,只需要三个函数就可以搞定了。这三个函数的头文件是<stdarg.h>,其实下面的三个函数都是一个宏定义(macro)。
        这三个函数是:
        void va_start(va_list ap, last);
        type va_arg(va_list ap, type);
        void va_end(va_list ap);
        如果需要进行其他的一些操作,可以查看一下man手册进行查询。
        在这三个函数解释之前,先看一个变量va_list,这个变量的类型是什么呢?通过查看内核源代码,一直追踪下去,才发现它的类型是void *类型的。
        对于va_start(va_list ap, last)函数,这个函数是用来初始化指针变量ap(va_list类型)的,以后处理参数就是默认从ap处开始处理。last一般为char *传过来参数列表的第一个参数。
        对于va_arg(va_list ap, type)函数来说,就是将ap指针按照type类型向后移动,然后取出ap指针所指的那个参数。
        对于va_end(va_list ap)一般和va_start(va_list ap, last)配套使用,做一些善后处理的事情。
        这里有一个问题,当我们取参数的时候,如何判断我们要取的参数已经取完了?开始我是这么想的,通过va_arg的返回值进行判断,通过查阅资料,都是这么说的,看来我的猜想是对的。当我把程序写出来进行测试的时候,发现不是这样的:
    #include <stdio.h>
    #include <stdarg.h>
    int sum(const int , ...);
    int main(void)
    {
        printf("The result is:%d/n", sum(10, 9, 8));
        return 0;
    }
    int sum(const int first, ...)
    {
        va_list argp;
        int sum = 0;
        int tmp;
        va_start(argp, first);
        sum = first;
        printf("%d/n", first);
        while((tmp = va_arg(argp, int)) != 0) {
            printf("%d/n", tmp);
            sum = tmp;
        }
        va_end(argp);
        return sum;
    }
    这个程序的运行结果是:
    10
    新葡亰496net:Service服务端和客商端程序,多维数组的兑现。9
    8
    6676468
    134513824
    The result is:141190319
        这个结果说明,通过va_arg的返回值进行参数是否取完来判断是有问题的。
        会不会是通过argp的值来判断的呢?让我们来做个测试:
    #include <stdio.h>
    #include <stdarg.h>
    int sum(const int , ...);
    int main(void)
    {
        printf("The result is:%d/n", sum(10, 9, 8));
        return 0;
    }
    int sum(const int first, ...)
    {
        va_list argp;
        int sum = 0;
        int tmp;
        va_start(argp, first);
        sum = first;
        printf("%d/n", first);
        while(argp) {
            tmp = va_arg(argp, int);
            printf("%d/n", tmp);
            sum = tmp;
        }
        va_end(argp);
        return sum;
    }
        这个程序的执行结果出乎我的意料,出现了段错误。
        至于如何修改这个程序把不定参数取出来,我还是没有找到解决方法。后来,我想到了printf()函数,我查看了它的源代码,其中主要是调用了vsprintf()函数,至于为什么调用vsprintf()函数,我想可能是为了实现类似于fprintf()之类的函数调用的方便,这样也提高了函数的利用率。printf()函数的主要代码:
    328 va_start(args, fmt);
    329 n = vsprintf(sprint_buf, fmt, args);
    330 va_end(args);
        我继续查看了vsprintf()函数,结果发现,在这个函数当中,它好像是通过判断字符串当中“%”号的多少来决定后面参数的个数的。想到这里,我断定,在想调用不定参数这样的函数的时候,其实是需要指出参数的个数的,只是是通过间接的方式。比如我们最熟悉的printf()函数,其实我们在第一个参数当中,通过%号已经指出了参数的个数,不是吗?
        想到这里,我想到了之前看到man手册中给出的例子为什么是这样的:
    #include <stdio.h>
           #include <stdarg.h>
           void
           foo(char *fmt, ...)
           {
               va_list ap;
               int d;
               char c, *s;
               va_start(ap, fmt);
               while (*fmt)
                   switch (*fmt ) {
                   case 's': /* string */
                       s = va_arg(ap, char *);
                       printf("string %s/n", s);
                       break;
                   case 'd': /* int */
                       d = va_arg(ap, int);
                       printf("int %d/n", d);
                       break;
                   case 'c': /* char */
                       /* need a cast here since va_arg only
                          takes fully promoted types */
                       c = (char) va_arg(ap, int);
                       printf("char %c/n", c);
                       break;
                   }
               va_end(ap);
           }
        这里的话,不是就通过第一个参数指定之后才读取的吗?其实我觉得是间接的告诉了参数的个数。
        通过上面的分析,下面做了一个简单的不定参数的应用。
        问题描述:给定一些字符串,求出它们的最长开始字串。
        实验代码如下:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdarg.h>
    void fun(char *fmt, ...);
    int main()
    {
        fun("sss", "fanabcd", "fanfanfanfan", "fanyyyyyyyyyyyy");//sss 表示了不定参数的个数
        return 0;    
    }
    void fun(char *fmt, ...)
    {
        va_list argp;
        char * str, res[20] = {0};
        int i;
        va_start(argp, fmt);
        if(*fmt == 's') {
            str = va_arg(argp, char *);
            strcpy(res, str);
        }
        fmt ;
        while(*fmt) {
            if(*fmt == 's') {
                str = va_arg(argp, char *);
                i = 0;
                while(res[i] != '/0') {
                    if(res[i] != str[i]) {
                        res[i] = 0;
                        break;
                    }
                    i ;
                }
            }
        }
        va_end(argp);
        printf("The result is:%s/n", res);
    }
        程序的执行结果是:
    The result is:fan
        通过这样的折腾,就把c语言的不定参数简单地应用起来了

    安装Emscripten

    访问

    1. 下载对应平台版本的SDK

    2. 通过emsdk获取最新版工具

    JavaScript

    # Fetch the latest registry of available tools. ./emsdk update # Download and install the latest SDK tools. ./emsdk install latest # Make the "latest" SDK "active" for the current user. (writes ~/.emscripten file) ./emsdk activate latest # Activate PATH and other environment variables in the current terminal source ./emsdk_env.sh

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # Fetch the latest registry of available tools.
    ./emsdk update
     
    # Download and install the latest SDK tools.
    ./emsdk install latest
     
    # Make the "latest" SDK "active" for the current user. (writes ~/.emscripten file)
    ./emsdk activate latest
     
    # Activate PATH and other environment variables in the current terminal
    source ./emsdk_env.sh
    1. 将下列添加到环境变量PATH中

    JavaScript

    ~/emsdk-portable ~/emsdk-portable/clang/fastcomp/build_incoming_64/bin ~/emsdk-portable/emscripten/incoming

    1
    2
    3
    ~/emsdk-portable
    ~/emsdk-portable/clang/fastcomp/build_incoming_64/bin
    ~/emsdk-portable/emscripten/incoming
    1. 其他

    我在执行的时候碰到报错说LLVM版本不对,后来参考文档配置了LLVM_ROOT变量就好了,如果你没有遇到问题,可以忽略。

    JavaScript

    LLVM_ROOT = os.path.expanduser(os.getenv('LLVM', '/home/ubuntu/a-path/emscripten-fastcomp/build/bin'))

    1
    LLVM_ROOT = os.path.expanduser(os.getenv('LLVM', '/home/ubuntu/a-path/emscripten-fastcomp/build/bin'))
    1. 验证是否安装好

    执行emcc -v,如果安装好会出现如下信息:

    JavaScript

    emcc (Emscripten gcc/clang-like replacement linker emulating GNU ld) 1.37.21 clang version 4.0.0 ( 974b55fd84ca447c4297fc3b00cefb6394571d18) ( 9e4ee9a67c3b67239bd1438e31263e2e86653db5) (emscripten 1.37.21 : 1.37.21) Target: x86_64-apple-darwin15.5.0 Thread model: posix InstalledDir: /Users/magicly/emsdk-portable/clang/fastcomp/build_incoming_64/bin INFO:root:(Emscripten: Running sanity checks)

    1
    2
    3
    4
    5
    6
    emcc (Emscripten gcc/clang-like replacement linker emulating GNU ld) 1.37.21
    clang version 4.0.0 (https://github.com/kripken/emscripten-fastcomp-clang.git 974b55fd84ca447c4297fc3b00cefb6394571d18) (https://github.com/kripken/emscripten-fastcomp.git 9e4ee9a67c3b67239bd1438e31263e2e86653db5) (emscripten 1.37.21 : 1.37.21)
    Target: x86_64-apple-darwin15.5.0
    Thread model: posix
    InstalledDir: /Users/magicly/emsdk-portable/clang/fastcomp/build_incoming_64/bin
    INFO:root:(Emscripten: Running sanity checks)

    Node.js(0.8 or above; 0.10.17 or above to run websocket-using servers in node):

    行序列:
    a[0][0]  a[1][0] ...... a[m-1][0]
    .............
    a[0][n-1] a[1][ [n-1 ] ...... a[m-1][n-1]
    数据一般使用连续的地址存储。计算的方法为 (i, j) = &a (b) j;//b 一维元素的个数
    推广到多维数组中(j1, j2, j3,.....,jn) = (b2*b3*...*bn * j1 b3*b4*...*bn*j2 ..... bn *jn-1 jn)
    例如:已知数组a[5][4][10]。求a[2][3][4] 的地址;
    j1=2、j2 = 3、j3 = 4;b1=5、b2=4、b3=10;
    a[2][3][4]=b2*b3*j1 b3*j2 j3=4*10*2 10*3 4;

           要开发的Web Service功能非常简单,就是一个add函数,将两个参数相加,返回其和。

    Hello, WebAssembly!

    创建一个文件hello.c

    JavaScript

    #include <stdio.h> int main() { printf("Hello, WebAssembly!n"); return 0; }

    1
    2
    3
    4
    5
    #include <stdio.h>
    int main() {
      printf("Hello, WebAssembly!n");
      return 0;
    }

    编译C/C 代码:

    JavaScript

    emcc hello.c

    1
    emcc hello.c

    上述命令会生成一个a.out.js文件,我们可以直接用Node.js执行:

    JavaScript

    node a.out.js

    1
    node a.out.js

    输出

    JavaScript

    Hello, WebAssembly!

    1
    Hello, WebAssembly!

    为了让代码运行在网页里面,执行下面命令会生成hello.htmlhello.js两个文件,其中hello.jsa.out.js内容是完全一样的。

    emcc hello.c -o hello.html<code>

    1
    2
    emcc hello.c -o hello.html<code>
     

    JavaScript

    ➜ webasm-study md5 a.out.js MD5 (a.out.js) = d7397f44f817526a4d0f94bc85e46429 ➜ webasm-study md5 hello.js MD5 (hello.js) = d7397f44f817526a4d0f94bc85e46429

    1
    2
    3
    4
    ➜  webasm-study md5 a.out.js
    MD5 (a.out.js) = d7397f44f817526a4d0f94bc85e46429
    ➜  webasm-study md5 hello.js
    MD5 (hello.js) = d7397f44f817526a4d0f94bc85e46429

    然后在浏览器打开hello.html,可以看到页面 新葡亰496net 2

    前面生成的代码都是asm.js,毕竟Emscripten是人家作者Alon Zakai最早用来生成asm.js的,默认输出asm.js也就不足为奇了。当然,可以通过option生成wasm,会生成三个文件:hello-wasm.html, hello-wasm.js, hello-wasm.wasm

    JavaScript

    emcc hello.c -s WASM=1 -o hello-wasm.html

    1
    emcc hello.c -s WASM=1 -o hello-wasm.html

    然后浏览器打开hello-wasm.html,发现报错TypeError: Failed to fetch。原因是wasm文件是通过XHR异步加载的,用file:////访问会报错,所以我们需要启一个服务器。

    JavaScript

    npm install -g serve serve

    1
    2
    npm install -g serve
    serve

    然后访问http://localhost:5000/hello-wasm.html,就可以看到正常结果了。

    Python2.x (2.7.3 or above preferred)

    下面为代码实现。(以下代码是我在ubuntu中简单测试通过。如在别的系统中无法运行,请谅解。本代码只经过简单的测试,如果出现问题,请谅解。)
    [plain]
    新葡亰496net:Service服务端和客商端程序,多维数组的兑现。/* 
    *created by Reage at 2013 March 28 
    *description: 数组的实现,包含创建、赋值、访问、打印 

    *blog: 
    */ 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <stdarg.h> 
     
     
    #define MAXDIM 4 
     
    typedef struct Array 

        int dim; 
        int *ptr; 
        int *bounds; 
        int *base_add; 
    }Array; 
     
    int array_init(Array *a, int dim, ...); 
    int array_set_value(Array *a, int value, ...); 
    int array_print_line(Array *a); 
    int array_get_value(Array *a, ...); 
    void array_destory(Array *a); 
     
    int main(int argc, char *argv[]) 

        Array a; 
        int i = 0; 
        int j; 
        int total = 1; 
        array_init(&a, 2, 4, 6); 
         
        for(; i < 4; i ) 
        { 
            for(j = 0; j < 6; j ) 
            { 
                array_set_value(&a, total , i, j); 
            } 
        } 
     
        array_print_line(&a); 
        for(i = 0; i < 4; i ) 
        { 
            for(j = 0; j < 6; j ) 
            { 
                printf("%-7d",array_get_value(&a,  i, j)); 
            } 
            printf("n"); 
        } 
        array_destory(&a); 

     
    int array_init(Array * a, int dim, ...) 

        if(1 > dim || 8 < dim) 
            return -1; 
        a->dim = dim; 
     
        va_list ap; 
        int i; 
        long total = 1; 
     
        a->bounds = (int *)malloc(dim * sizeof(int)); 
         
        va_start(ap, dim); 
        for(i = 0; i < dim; i ) 
        { 
            a->bounds[i] = va_arg(ap, int); 
            total *= a->bounds[i]; 
        } 
        va_end(ap); 
     
        a->ptr = (int *) malloc(total * sizeof(int)); 
     
        a->base_add = (int *) malloc(dim * sizeof(int)); 
        a->base_add[dim -1] = 1; 
        i = dim -2; 
        for(; i >= 0; i--) 
        { 
            a->base_add[i] = a->base_add[i 1] * a->bounds[i 1]; 
        } 
     
        return 0; 

     
    #define FREE(x) if(NULL != (x)) free(x) 
     
    void array_destory(Array *a) 

        FREE(a->ptr); 
        FREE(a->bounds); 
        FREE(a->base_add); 

     
    int array_get_value(Array *a, ...) 

        va_list va; 
        va_start(va, a); 
         
        int result = array_get_locate(a, va); 
        if(-1 == result) return -1; 
        return a->ptr[result]; 

     
     
    int array_print_line(Array *a) 

        int total = 1; 
        int i = 0; 
        int line ; 
        for(; i < a->dim; i ) 
        { 
            total *= a->bounds[i]; 
        } 
         
        line = total/a->bounds[0]; 
        for(i = 0; i < total; i ) 
        { 
            if(0 == i % line && 0 != i) printf("n"); 
            printf("%-7d", a->ptr[i]); 
        } 
        printf("n"); 
        return 0; 

     
     
    int array_get_locate(Array *a, va_list va) 

        int result = 0; 
        int bound; 
        int i; 
        for(i = 0; i < a->dim; i ) 
        { 
            bound = va_arg(va, int); 
            if(0 > bound || bound > a->bounds[i]) 
            { 
                return -1; 
            } 
            result = bound * a->base_add[i]; 
        } 
        return result; 

     
    int array_set_value(Array *a, int value, ...) 

        if(NULL == a) return -1; 
        va_list va; 
        va_start(va, value); 
     
        int result = array_get_locate(a, va); 
        if( -1 == result) return -1; 
     
        a->ptr[result] = value; 
        return 0; 

     

    调用C/C 函数

    前面的Hello, WebAssembly!都是main函数直接打出来的,而我们使用WebAssembly的目的是为了高性能计算,做法多半是用C/C 实现某个函数进行耗时的计算,然后编译成wasm,暴露给js去调用。

    在文件add.c中写如下代码:

    JavaScript

    #include <stdio.h> int add(int a, int b) { return a b; } int main() { printf("a b: %d", add(1, 2)); return 0; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <stdio.h>
    int add(int a, int b) {
      return a b;
    }
     
    int main() {
      printf("a b: %d", add(1, 2));
      return 0;
    }

    有两种方法可以把add方法暴露出来给js调用。

    Java(1.6.0_31 or later). Java is optional. It is required to use theClosure Compiler(in order to minify your code).

    /*
    *created by Reage at 2013 March 28
    *description: 数组的实现,包含创建、赋值、访问、打印
    *
    *blog:
    */
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdarg.h>

    2、C版本的程序:

    通过命令行参数暴露API

    JavaScript

    emcc -s EXPORTED_FUNCTIONS="['_add']" add.c -o add.js

    1
    emcc -s EXPORTED_FUNCTIONS="['_add']" add.c -o add.js

    注意方法名add前必须加_。 然后我们可以在Node.js里面这样使用:

    JavaScript

    // file node-add.js const add_module = require('./add.js'); console.log(add_module.ccall('add', 'number', ['number', 'number'], [2, 3]));

    1
    2
    3
    // file node-add.js
    const add_module = require('./add.js');
    console.log(add_module.ccall('add', 'number', ['number', 'number'], [2, 3]));

    执行node node-add.js会输出5。 如果需要在web页面使用的话,执行:

    JavaScript

    emcc -s EXPORTED_FUNCTIONS="['_add']" add.c -o add.html

    1
    emcc -s EXPORTED_FUNCTIONS="['_add']" add.c -o add.html

    然后在生成的add.html中加入如下代码:

    JavaScript

    <button onclick="nativeAdd()">click</button> <script type='text/javascript'> function nativeAdd() { const result = Module.ccall('add', 'number', ['number', 'number'], [2, 3]); alert(result); } </script>

    1
    2
    3
    4
    5
    6
    7
      <button onclick="nativeAdd()">click</button>
      <script type='text/javascript'>
        function nativeAdd() {
          const result = Module.ccall('add', 'number', ['number', 'number'], [2, 3]);
          alert(result);
        }
      </script>

    然后点击button,就可以看到执行结果了。

    Module.ccall会直接调用C/C 代码的方法,更通用的场景是我们获取到一个包装过的函数,可以在js里面反复调用,这需要用Module.cwrap,具体细节可以参看文档。

    JavaScript

    const cAdd = add_module.cwrap('add', 'number', ['number', 'number']); console.log(cAdd(2, 3)); console.log(cAdd(2, 4));

    1
    2
    3
    const cAdd = add_module.cwrap('add', 'number', ['number', 'number']);
    console.log(cAdd(2, 3));
    console.log(cAdd(2, 4));

    Gitclient. Git is required if building tools from source.

    #define MAXDIM 4

    (1)头文件:SmsWBS.h,注释部分不可少,url部分的IP必须填写当前Linux电脑的IP

    定义函数的时候添加EMSCRIPTEN_KEEPALIVE

    添加文件add2.c

    JavaScript

    #include <stdio.h> #include <emscripten.h> int EMSCRIPTEN_KEEPALIVE add(int a, int b) { return a b; } int main() { printf("a b: %d", add(1, 2)); return 0; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <stdio.h>
    #include <emscripten.h>
     
    int EMSCRIPTEN_KEEPALIVE add(int a, int b) {
      return a b;
    }
     
    int main() {
      printf("a b: %d", add(1, 2));
      return 0;
    }

    执行命令:

    JavaScript

    emcc add2.c -o add2.html

    1
    emcc add2.c -o add2.html

    同样在add2.html中添加代码:

    JavaScript

    <button onclick="nativeAdd()">click</button> <script type='text/javascript'> function nativeAdd() { const result = Module.ccall('add', 'number', ['number', 'number'], [2, 3]); alert(result); } </script>

    1
    2
    3
    4
    5
    6
    7
      <button onclick="nativeAdd()">click</button>
      <script type='text/javascript'>
        function nativeAdd() {
          const result = Module.ccall('add', 'number', ['number', 'number'], [2, 3]);
          alert(result);
        }
      </script>

    但是,当你点击button的时候,报错:

    JavaScript

    Assertion failed: the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)

    1
    Assertion failed: the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)

    可以通过在main()中添加emscripten_exit_with_live_runtime()解决:

    JavaScript

    #include <stdio.h> #include <emscripten.h> int EMSCRIPTEN_KEEPALIVE add(int a, int b) { return a b; } int main() { printf("a b: %d", add(1, 2)); emscripten_exit_with_live_runtime(); return 0; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <stdio.h>
    #include <emscripten.h>
     
    int EMSCRIPTEN_KEEPALIVE add(int a, int b) {
      return a b;
    }
     
    int main() {
      printf("a b: %d", add(1, 2));
      emscripten_exit_with_live_runtime();
      return 0;
    }

    或者也可以直接在命令行中添加-s NO_EXIT_RUNTIME=1来解决,

    JavaScript

    emcc add2.c -o add2.js -s NO_EXIT_RUNTIME=1

    1
    emcc add2.c -o add2.js -s NO_EXIT_RUNTIME=1

    不过会报一个警告:

    JavaScript

    exit(0) implicitly called by end of main(), but noExitRuntime, so not exiting the runtime (you can use emscripten_force_exit, if you want to force a true shutdown)exit(0) implicitly called by end of main(), but noExitRuntime, so not exiting the runtime (you can use emscripten_force_exit, if you want to force a true shutdown)

    1
    exit(0) implicitly called by end of main(), but noExitRuntime, so not exiting the runtime (you can use emscripten_force_exit, if you want to force a true shutdown)exit(0) implicitly called by end of main(), but noExitRuntime, so not exiting the runtime (you can use emscripten_force_exit, if you want to force a true shutdown)

    所以建议采用第一种方法。

    上述生成的代码都是asm.js,只需要在编译参数中添加-s WASM=1中就可以生成wasm,然后使用方法都一样。

    Fastcomp(Emscripten’s fork of LLVM and Clang)

    参考链接地址:Manually Building Emscripten on Mac OS X

    To build the Fastcomp code from source:

    Create a directory to store the build. It doesn’t matter where, because Emscripten gets the information from thecompiler configuration file (~/.emscripten). We show how to update this file later in these instructions:

    mkdirmyfastcompcdmyfastcomp

    Clone the fastcomp LLVM repository (https://github.com/kripken/emscripten-fastcomp):

    gitclone

    Clone thekripken/emscripten-fastcomp-clangrepository intoemscripten-fastcomp/tools/clang:

    cdemscripten-fastcompgitclone tools/clang

    Warning

    Youmustclone it into a directory namedclangas shown, so thatClangis present intools/clang!

    Create abuilddirectory (inside theemscripten-fastcompdirectory) and then navigate into it:

    mkdirbuildcdbuild

    Configure the build usingeithercmakeor theconfigurescript:

    Usingcmake:

    cmake..-DCMAKE_BUILD_TYPE=Release-DLLVM_TARGETS_TO_BUILD="X86;JSBackend"-DLLVM_INCLUDE_EXAMPLES=OFF-DLLVM_INCLUDE_TESTS=OFF-DCLANG_INCLUDE_EXAMPLES=OFF-DCLANG_INCLUDE_TESTS=OFF

    Note

    On Windows add the-G"VisualStudio10Win64"directive to build using Visual Studio (Visual Studio 2011 and 2012 do NOT work).

    Usingconfigure(Linux/Mac only):

    ../configure--enable-optimized--disable-assertions--enable-targets=host,js

    Determine the number of available cores on your system (Emscripten can run many operations in parallel, so using more cores may have a significant impact on compilation time):

    On Mac OS X you can get the number of cores using:Apple menu | About this mac | More info | System report. TheHardware overviewon the resulting dialog includes aTotal number of coresentry.

    On Linux you can find the number of cores by entering the following command on the terminal:cat/proc/cpuinfo|grep"^cpucores"|uniq.

    On Windows the number of cores is listed on theTask Manager | Performance Tab. You can open theTask Managerby enteringCtrl Shift Escfrom the Desktop.

    Callmaketo build the sources, specifying the number of available cores:

    make-j4

    Note

    If the build completes successfully,clang,clang , and a number of other files will be created in the release directory (/build/Release/bin).

    The final step is to update the~/.emscriptenfile, specifying the location offastcompin theLLVM_ROOTvariable.

    Note

    If you’re building thewholeof Emscripten from source, following the platform-specific instructions inBuilding Emscripten from Source, you won’t yet have Emscripten installed. In this case, skip this step and return to those instructions.

    If you already have an Emscripten environment (for example if you’re building Fastcomp using the SDK), then setLLVM_ROOTto the location of theclangbinary under thebuilddirectory. This will be something like/build/Release/binor/build/bin:

    ```

    vim ~/.emscripten

    ```

    修改 LLVM_ROOT到指定的文件目录

    LLVM_ROOT = '/usr/local/myfastcomp/emscripten-fastcomp/build/bin' # directory

    typedef struct Array
    {
        int dim;
        int *ptr;
        int *bounds;
        int *base_add;
    }Array;

    //gsoap ns service name: SmsWBS
    //gsoap ns service style: rpc
    //gsoap ns service namespace: http://192.168.2.161:8000/SmsWBS.wsdl
    //gsoap ns service location: http://192.168.2.161:8000
    //gsoap ns service encoding: encoded
    //gsoap ns schema namespace: urn:SmsWBS

    用asm.js和WebAssembly执行耗时计算

    前面准备工作都做完了, 现在我们来试一下用C代码来优化前一篇中提过的问题。代码很简单:

    JavaScript

    // file sum.c #include <stdio.h> // #include <emscripten.h> long sum(long start, long end) { long total = 0; for (long i = start; i <= end; i = 3) { total = i; } for (long i = start; i <= end; i = 3) { total -= i; } return total; } int main() { printf("sum(0, 1000000000): %ld", sum(0, 1000000000)); // emscripten_exit_with_live_runtime(); return 0; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // file sum.c
    #include <stdio.h>
    // #include <emscripten.h>
     
    long sum(long start, long end) {
      long total = 0;
      for (long i = start; i <= end; i = 3) {
        total = i;
      }
      for (long i = start; i <= end; i = 3) {
        total -= i;
      }
      return total;
    }
     
    int main() {
      printf("sum(0, 1000000000): %ld", sum(0, 1000000000));
      // emscripten_exit_with_live_runtime();
      return 0;
    }

    注意用gcc编译的时候需要把跟emscriten相关的两行代码注释掉,否则编译不过。 我们先直接用gcc编译成native code看看代码运行多块呢?

    JavaScript

    ➜ webasm-study gcc sum.c ➜ webasm-study time ./a.out sum(0, 1000000000): 0./a.out 5.70s user 0.02s system 99% cpu 5.746 total ➜ webasm-study gcc -O1 sum.c ➜ webasm-study time ./a.out sum(0, 1000000000): 0./a.out 0.00s user 0.00s system 64% cpu 0.003 total ➜ webasm-study gcc -O2 sum.c ➜ webasm-study time ./a.out sum(0, 1000000000): 0./a.out 0.00s user 0.00s system 64% cpu 0.003 total

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ➜  webasm-study gcc sum.c
    ➜  webasm-study time ./a.out
    sum(0, 1000000000): 0./a.out  5.70s user 0.02s system 99% cpu 5.746 total
    ➜  webasm-study gcc -O1 sum.c
    ➜  webasm-study time ./a.out
    sum(0, 1000000000): 0./a.out  0.00s user 0.00s system 64% cpu 0.003 total
    ➜  webasm-study gcc -O2 sum.c
    ➜  webasm-study time ./a.out
    sum(0, 1000000000): 0./a.out  0.00s user 0.00s system 64% cpu 0.003 total

    可以看到有没有优化差别还是很大的,优化过的代码执行时间是3ms!。really?仔细想想,我for循环了10亿次啊,每次for执行大概是两次加法,两次赋值,一次比较,而我总共做了两次for循环,也就是说至少是100亿次操作,而我的mac pro是2.5 GHz Intel Core i7,所以1s应该也就执行25亿次CPU指令操作吧,怎么可能逆天到这种程度,肯定是哪里错了。想起之前看到的一篇rust测试性能的文章,说rust直接在编译的时候算出了答案, 然后把结果直接写到了编译出来的代码里, 不知道gcc是不是也做了类似的事情。在知乎上GCC中-O1 -O2 -O3 优化的原理是什么?这篇文章里, 还真有loop-invariant code motion(LICM)针对for的优化,所以我把代码增加了一些if判断,希望能“糊弄”得了gcc的优化。

    JavaScript

    #include <stdio.h> // #include <emscripten.h> // long EMSCRIPTEN_KEEPALIVE sum(long start, long end) { long sum(long start, long end) { long total = 0; for (long i = start; i <= end; i = 1) { if (i % 2 == 0 || i % 3 == 1) { total = i; } else if (i % 5 == 0 || i % 7 == 1) { total = i / 2; } } for (long i = start; i <= end; i = 1) { if (i % 2 == 0 || i % 3 == 1) { total -= i; } else if (i % 5 == 0 || i % 7 == 1) { total -= i / 2; } } return total; } int main() { printf("sum(0, 1000000000): %ld", sum(0, 100000000)); // emscripten_exit_with_live_runtime(); return 0; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #include <stdio.h>
    // #include <emscripten.h>
     
    // long EMSCRIPTEN_KEEPALIVE sum(long start, long end) {
    long sum(long start, long end) {
      long total = 0;
      for (long i = start; i <= end; i = 1) {
        if (i % 2 == 0 || i % 3 == 1) {
          total = i;
        } else if (i % 5 == 0 || i % 7 == 1) {
          total = i / 2;
        }
      }
      for (long i = start; i <= end; i = 1) {
        if (i % 2 == 0 || i % 3 == 1) {
          total -= i;
        } else if (i % 5 == 0 || i % 7 == 1) {
          total -= i / 2;
        }
      }
      return total;
    }
     
    int main() {
      printf("sum(0, 1000000000): %ld", sum(0, 100000000));
      // emscripten_exit_with_live_runtime();
      return 0;
    }

    执行结果大概要正常一些了。

    JavaScript

    ➜ webasm-study gcc -O2 sum.c ➜ webasm-study time ./a.out sum(0, 1000000000): 0./a.out 0.32s user 0.00s system 99% cpu 0.324 total

    1
    2
    3
    ➜  webasm-study gcc -O2 sum.c
    ➜  webasm-study time ./a.out
    sum(0, 1000000000): 0./a.out  0.32s user 0.00s system 99% cpu 0.324 total

    ok,我们来编译成asm.js了。

    JavaScript

    #include <stdio.h> #include <emscripten.h> long EMSCRIPTEN_KEEPALIVE sum(long start, long end) { // long sum(long start, long end) { long total = 0; for (long i = start; i <= end; i = 1) { if (i % 2 == 0 || i % 3 == 1) { total = i; } else if (i % 5 == 0 || i % 7 == 1) { total = i / 2; } } for (long i = start; i <= end; i = 1) { if (i % 2 == 0 || i % 3 == 1) { total -= i; } else if (i % 5 == 0 || i % 7 == 1) { total -= i / 2; } } return total; } int main() { printf("sum(0, 1000000000): %ld", sum(0, 100000000)); emscripten_exit_with_live_runtime(); return 0; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #include <stdio.h>
    #include <emscripten.h>
     
    long EMSCRIPTEN_KEEPALIVE sum(long start, long end) {
    // long sum(long start, long end) {
      long total = 0;
      for (long i = start; i <= end; i = 1) {
        if (i % 2 == 0 || i % 3 == 1) {
          total = i;
        } else if (i % 5 == 0 || i % 7 == 1) {
          total = i / 2;
        }
      }
      for (long i = start; i <= end; i = 1) {
        if (i % 2 == 0 || i % 3 == 1) {
          total -= i;
        } else if (i % 5 == 0 || i % 7 == 1) {
          total -= i / 2;
        }
      }
      return total;
    }
     
    int main() {
      printf("sum(0, 1000000000): %ld", sum(0, 100000000));
      emscripten_exit_with_live_runtime();
      return 0;
    }

    执行

    JavaScript

    emcc sum.c -o sum.html

    1
    emcc sum.c -o sum.html

    然后在sum.html中添加代码``

    JavaScript

    <button onclick="nativeSum()">NativeSum</button> <button onclick="jsSumCalc()">JSSum</button> <script type='text/javascript'> function nativeSum() { t1 = Date.now(); const result = Module.ccall('sum', 'number', ['number', 'number'], [0, 100000000]); t2 = Date.now(); console.log(`result: ${result}, cost time: ${t2 - t1}`); } </script> <script type='text/javascript'> function jsSum(start, end) { let total = 0; for (let i = start; i <= end; i = 1) { if (i % 2 == 0 || i % 3 == 1) { total = i; } else if (i % 5 == 0 || i % 7 == 1) { total = i / 2; } } for (let i = start; i <= end; i = 1) { if (i % 2 == 0 || i % 3 == 1) { total -= i; } else if (i % 5 == 0 || i % 7 == 1) { total -= i / 2; } } return total; } function jsSumCalc() { const N = 100000000;// 总次数1亿 t1 = Date.now(); result = jsSum(0, N); t2 = Date.now(); console.log(`result: ${result}, cost time: ${t2 - t1}`); } </script>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    <button onclick="nativeSum()">NativeSum</button>
      <button onclick="jsSumCalc()">JSSum</button>
      <script type='text/javascript'>
        function nativeSum() {
          t1 = Date.now();
          const result = Module.ccall('sum', 'number', ['number', 'number'], [0, 100000000]);
          t2 = Date.now();
          console.log(`result: ${result}, cost time: ${t2 - t1}`);
        }
      </script>
      <script type='text/javascript'>
        function jsSum(start, end) {
          let total = 0;
          for (let i = start; i <= end; i = 1) {
            if (i % 2 == 0 || i % 3 == 1) {
              total = i;
            } else if (i % 5 == 0 || i % 7 == 1) {
              total = i / 2;
            }
          }
          for (let i = start; i <= end; i = 1) {
            if (i % 2 == 0 || i % 3 == 1) {
              total -= i;
            } else if (i % 5 == 0 || i % 7 == 1) {
              total -= i / 2;
            }
          }
     
          return total;
        }
        function jsSumCalc() {
          const N = 100000000;// 总次数1亿
          t1 = Date.now();
          result = jsSum(0, N);
          t2 = Date.now();
          console.log(`result: ${result}, cost time: ${t2 - t1}`);
        }
      </script>

    另外,我们修改成编译成WebAssembly看看效果呢?

    JavaScript

    emcc sum.c -o sum.js -s WASM=1

    1
    emcc sum.c -o sum.js -s WASM=1
    Browser webassembly asm.js js
    Chrome61 1300ms 600ms 3300ms
    Firefox55 600ms 800ms 700ms
    Safari9.1 不支持 2800ms 因不支持ES6我懒得改写没测试

    感觉Firefox有点不合理啊, 默认的JS太强了吧。然后觉得webassembly也没有特别强啊,突然发现emcc编译的时候没有指定优化选项-O2。再来一次:``

    JavaScript

    emcc -O2 sum.c -o sum.js # for asm.js emcc -O2 sum.c -o sum.js -s WASM=1 # for webassembly

    1
    2
    emcc -O2 sum.c -o sum.js # for asm.js
    emcc -O2 sum.c -o sum.js -s WASM=1 # for webassembly
    Browser webassembly -O2 asm.js -O2 js
    Chrome61 1300ms 600ms 3300ms
    Firefox55 650ms 630ms 700ms

    居然没什么变化, 大失所望。号称asm.js可以达到native的50%速度么,这个倒是好像达到了。但是今年Compiling for the Web with WebAssembly (Google I/O ‘17)里说WebAssembly是1.2x slower than native code,感觉不对呢。asm.js还有一个好处是,它就是js,所以即使浏览器不支持,也能当成不同的js执行,只是没有加速效果。当然WebAssembly受到各大厂商一致推崇,作为一个新的标准,肯定前景会更好,期待会有更好的表现。

    TheEmscripten code, from GitHub

    clone emscripten项目到本地

    ```

    git clone

    cd emscripten

    npm install

    ```

    测试是否各依赖环境已经正确安装成功

    在emscripten目录下运行

    ```

    ./emcc tests/hello_world.cpp

    ```

    如果没有报错则会在同目录下找到一个新文件a.out.js

    现在可以通过nodejs来运行a.out.js这个文件了

    ```

    node a.out.js

    ```

    会在控制台打印出

    ```

    hello, world!

    ```

    通过browserify编译使之能在浏览器运行

    安装browserify

    ```

    sudo npm install browserify -g

    ```

    编译a.out.js文件

    ```

    browserify a.out.js > test.js

    ```

    现在可以在网页中引入test.js文件

    ```

    <script src='test.js'></script>

    ```

    打开控制台可以看到

    ```

    hello world

    ```

    可以在输出的时候直接指定声称为浏览器端运行的代码,

    ./emcc tests/hello_world.cpp -o test.html

    在js中调用c /c写的函数

    Module.ccap("function_name", return_type, arg_type, arg)

    int array_init(Array *a, int dim, ...);
    int array_set_value(Array *a, int value, ...);
    int array_print_line(Array *a);
    int array_get_value(Array *a, ...);
    void array_destory(Array *a);

    int ns__add(int num1, int num2, int *sum);
    这个头文件需要注意的是,前面的 // 部分是有意义的,可以在上面修改,如果完全去掉,将会导致生成的中间文件不同,由此会引起要修改Makefile文件                                           

    Rust

    本来还想写Rust编译成WebAssembly的,不过感觉本文已经太长了, 后期再写如果结合Rust做WebAssembly吧。

    着急的可以先看看这两篇

    • Compiling to the web with Rust and emscripten
    • Rust ⇋ JavaScript

    使用emscritpen输入代码优化

    ./emcc tests/hello-test.cpp -o function.js

    代码是通过指定优化的优化参数运行时,EMCC。级别包括:-O0(不优化),-O1,-O2,-Os,-OZ和-O3

    添加setting

    -s EXPORTED_FUNCTIONS="['_uncompress']"  //到处函数

    -s  NO_FILESYSTEM=1      //0 在代码中包含文件系统代码, 1在代码中不包含文件系统代码

    -s EXPORTED_RUNTIME_METHODS    //到处可以在模块中使用的函数

    [

    'FS_createFolder',

    'FS_createPath',

    'FS_createDataFile',

    'FS_createPreloadedFile',

    'FS_createLazyFile',

    'FS_createLink',

    'FS_createDevice',

    'FS_unlink',

    'Runtime',

    'ccall',

    'cwrap',

    'setValue',

    'getValue',

    'ALLOC_NORMAL',

    'ALLOC_STACK',

    'ALLOC_STATIC',

    'ALLOC_DYNAMIC',

    'ALLOC_NONE',

    'allocate',

    'getMemory',

    'Pointer_stringify',

    'AsciiToString',

    'stringToAscii',

    'UTF8ArrayToString',

    'UTF8ToString',

    'stringToUTF8Array',

    'stringToUTF8',

    'lengthBytesUTF8',

    'stackTrace',

    'addOnPreRun',

    'addOnInit',

    'addOnPreMain',

    'addOnExit',

    'addOnPostRun',

    'intArrayFromString',

    'intArrayToString',

    'writeStringToMemory',

    'writeArrayToMemory',

    'writeAsciiToMemory',

    'addRunDependency',

    'removeRunDependency',

    ];

    Building Projects

    编译多个c /c文件到一个js中

    # Sub-optimal - JavaScript optimizations are omitted

    ./emcc -O2 a.cpp -o a.bc

    ./emcc -O2 b.cpp -o b.bc

    ./emcc a.bc b.bc -o project.js

    # Sub-optimal - LLVM optimizations omitted

    ./emcc a.cpp -o a.bc

    ./emcc b.cpp -o b.bc

    ./emcc -O2 a.bc b.bc -o project.js

    # Broken! Different JavaScript and LLVM optimisations used.

    ./emcc -O1 a.cpp -o a.bc

    ./emcc -O2 b.cpp -o b.bc

    ./emcc -O3 a.bc b.bc -o project.js

    # Correct. The SAME LLVM and JavaScript options are provided at both levels.

    ./emcc -O2 a.cpp -o a.bc

    ./emcc -O2 b.cpp -o b.bc

    ./emcc -O2 a.bc b.bc -o project.js

    int main(int argc, char *argv[])
    {
        Array a;
        int i = 0;
        int j;
        int total = 1;
        array_init(&a, 2, 4, 6);
       
        for(; i < 4; i )
        {
            for(j = 0; j < 6; j )
            {
                array_set_value(&a, total , i, j);
            }
        }

    (2)Makefile文件:

    Refers

    • 1 赞 收藏 评论

    新葡亰496net 3

        array_print_line(&a);
        for(i = 0; i < 4; i )
        {
            for(j = 0; j < 6; j )
            {
                printf("%-7d",array_get_value(&a,  i, j));
            }
            printf("n");
        }
        array_destory(&a);
    }

    比较关键,如果头文件中的 // 部分有修改,要检查是否要修改Makefile文件

    int array_init(Array * a, int dim, ...)
    {
        if(1 > dim || 8 < dim)
            return -1;
        a->dim = dim;

    GSOAP_ROOT=/usr/local/gSOAP
    WSNAME0=soap
    WSNAME=SmsWBS
    CC=g -g -DWITH_NONAMESPACES
    INCLUDE=-I $(GSOAP_ROOT)/include
    SERVER_OBJS=$(WSNAME0)C.o $(WSNAME0)Server.o stdsoap2.o
    CLIENT_OBJS=$(GSOAP_ROOT)/env/envC.o $(WSNAME0)ClientLib.o stdsoap2.o
    ALL_OBJS=${WSNAME}server.o $(WSNAME0)C.o $(WSNAME0)Server.o ${WSNAME}test.o $(WSNAME0)ClientLib.o
    #GSOAP_SRC=/usr/local/gsoap-2.7/gsoap

        va_list ap;
        int i;
        long total = 1;

    all:server

        a->bounds = (int *)malloc(dim * sizeof(int));
       
        va_start(ap, dim);
        for(i = 0; i < dim; i )
        {
            a->bounds[i] = va_arg(ap, int);
            total *= a->bounds[i];
        }
        va_end(ap);

    ${WSNAME}.wsdl:${WSNAME}.h
            $(GSOAP_ROOT)/bin/soapcpp2 -c $(GSOAP_ROOT)/import ${WSNAME}.h

        a->ptr = (int *) malloc(total * sizeof(int));

    stdsoap2.o:$(GSOAP_ROOT)/src/stdsoap2.c
            $(CC) -c $? $(INCLUDE)

        a->base_add = (int *) malloc(dim * sizeof(int));
        a->base_add[dim -1] = 1;
        i = dim -2;
        for(; i >= 0; i--)
        {
            a->base_add[i] = a->base_add[i 1] * a->bounds[i 1];
        }

    $(ALL_OBJS):%.o:%.c
            $(CC) -c $? $(INCLUDE)

        return 0;
    }

    server:Makefile ${WSNAME}.wsdl ${WSNAME}server.o $(SERVER_OBJS)
            $(CC) ${WSNAME}server.o $(SERVER_OBJS) -o ${WSNAME}server

    #define FREE(x) if(NULL != (x)) free(x)

    client:Makefile ${WSNAME}.wsdl ${WSNAME}test.c $(ALL_OBJS) stdsoap2.o
            $(CC) ${WSNAME}test.o $(CLIENT_OBJS) -o ${WSNAME}test

    void array_destory(Array *a)
    {
        FREE(a->ptr);
        FREE(a->bounds);
        FREE(a->base_add);
    }

    clean:
            rm -f *.o *.xml *.a *.wsdl *.nsmap $(WSNAME0)H.h $(WSNAME0)C.c $(WSNAME0)Server.c $(WSNAME0)Client.c $(WSNAME0)Stub.* $(WSNAME)$(WSNAME)Proxy.* $(WSNAME)$(WSNAME)Object.* $(WSNAME0)ServerLib.c $(WSNAME0)ClientLib.c $(WSNAME)server ns.xsd $(WSNAME)test

    int array_get_value(Array *a, ...)
    {
        va_list va;
        va_start(va, a);
       
        int result = array_get_locate(a, va);
        if(-1 == result) return -1;
        return a->ptr[result];
    }

     

    int array_print_line(Array *a)
    {
        int total = 1;
        int i = 0;
        int line ;
        for(; i < a->dim; i )
        {
            total *= a->bounds[i];
        }
       
        line = total/a->bounds[0];
        for(i = 0; i < total; i )
        {
            if(0 == i % line && 0 != i) printf("n");
            printf("%-7d", a->ptr[i]);
        }
        printf("n");
        return 0;
    }

    (3)服务端程序SmsWBSserver.c:

    int array_get_locate(Array *a, va_list va)
    {
        int result = 0;
        int bound;
        int i;
        for(i = 0; i < a->dim; i )
        {
            bound = va_arg(va, int);
            if(0 > bound || bound > a->bounds[i])
            {
                return -1;
            }
            result = bound * a->base_add[i];
        }
        return result;
    }

    #include "soapH.h"
    #include "SmsWBS.nsmap"

    int array_set_value(Array *a, int value, ...)
    {
        if(NULL == a) return -1;
        va_list va;
        va_start(va, value);

    int main(int argc, char **argv)
    {
            int m, s;               /* master and slave sockets */
            struct soap SmsWBS_soap;

        int result = array_get_locate(a, va);
        if( -1 == result) return -1;

            soap_init(&SmsWBS_soap);

        a->ptr[result] = value;
        return 0;
    }

            soap_set_namespaces(&SmsWBS_soap, namespaces);

     

            if (argc < 2)
            {
                    printf("usage: %s <server_port> n", argv[0]);
                    exit(1);
            }
            else
            {
                    m = soap_bind(&SmsWBS_soap, NULL, atoi(argv[1]), 100);
                    if (m < 0)
                    {
                            soap_print_fault(&SmsWBS_soap, stderr);
                            exit(-1);
                    }

    ...

                    fprintf(stderr, "Socket connection successful: master socket = %dn", m);

                    for (;;)
                    {
                            s = soap_accept(&SmsWBS_soap);

                            if (s < 0)
                            {
                                    soap_print_fault(&SmsWBS_soap, stderr);
                                    exit(-1);
                            }

                            fprintf(stderr, "Socket connection successful: slave socket = %dn", s);
                            soap_serve(&SmsWBS_soap);
                            soap_end(&SmsWBS_soap);
                    }

           }

            return 0;
    }

    int ns__add(struct soap *add_soap, int num1, int num2, int *sum)
    {
            *sum = num1 num2;
            return 0;
    }

     

    (4)客户端程序SmsWBStest.c:

    #include <stdio.h>
    #include <stdlib.h>
    #include "soapStub.h"
    #include "SmsWBS.nsmap"

    int add(const char *server, int num1, int num2, int *sum);

    int add(const char *server, int num1, int num2, int *sum)
    {
            struct soap SmsWBS_soap;
            int result = 0;

            soap_init(&SmsWBS_soap);
            soap_set_namespaces(&SmsWBS_soap, namespaces);

            soap_call_ns__add(&SmsWBS_soap, server, "", num1, num2, sum);

            if(SmsWBS_soap.error)
            {
                    printf("soap error:%d, %s, %s ", SmsWBS_soap.error, *soap_faultcode(&SmsWBS_soap), *soap_faultstring(&SmsWBS_soap));
                    result = SmsWBS_soap.error;
             }

            soap_end(&SmsWBS_soap);
            soap_done(&SmsWBS_soap);

            return result;
    }

    int main(int argc, char **argv)
    {
            int result = -1;
            char* server="http://localhost:8000";

            int num1 = 0;
            int num2 = 0;
            int sum = 0;

            if( argc < 3 )
            {
                    printf("usage: %s num1 num2 n", argv[0]);
                    exit(0);

            }

            num1 = atoi(argv[1]);
            num2 = atoi(argv[2]);

            result = add(server, num1, num2, &sum);
            if (result != 0)
            {
                    printf("soap err, errcode = %d n", result);
            }
            else
            {
                    printf("%d %d = %d n", num1, num2, sum);
            }

            return 0;
    }

    (5)编译和运行:

    前面都已经准备好了,现在只需要:

    make                                     ---得到服务端程序SmsWBSserver

    make client                            ---得到客户端程序SmsWBStest

    SmsWBSserver 9000             ----运行服务端程序

    出来类似下面的显示就表示运行正常

    Socket connection successful: master socket = 3

    再运行客户端程序:

    SmsWBStest 67 78

    显示:

    67 78 = 145

    调用Web Service成功

    本文由新葡亰496net发布于新葡亰官网,转载请注明出处:新葡亰496net:Service服务端和客商端程序,多维数

    关键词: