go语言自带的jsonrpc 不支持http/websocket,而是使用tcp协议,
aardio中增加了一个库 wsock.tcp.jsonClient 支持与go语言进行jsonrpc调用。
先使用go语言编写一个exe文件( 当然你可以把后缀名改为 dll,下面的代码一样可以运行 )
go语言代码如下,注意 go里面{换行写是语法错误 :
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 39 40 41 42 43 44 45 46 47 48 49
| package main
import ( "fmt" "log" "net" "net/rpc" "net/rpc/jsonrpc" )
type Args struct { X, Y int }
var listener net.Listener
type Calculator struct{}
func (t *Calculator) Add(args *Args, reply *int) error { *reply = args.X + args.Y return nil }
func (t *Calculator) Exit(args *int, reply *int) error { listener.Close() return nil }
func main() { cal := new(Calculator) server := rpc.NewServer() server.Register(cal)
listener, e := net.Listen("tcp", "localhost:0") if e != nil { fmt.Printf("error:%s\n", e) return } else { fmt.Printf("%s\n", listener.Addr().String()) }
for { if conn, err := listener.Accept(); err != nil { log.Fatal("error: " + err.Error()) } else { go server.ServeCodec(jsonrpc.NewServerCodec(conn)) } } }
|
假设上面用go语言生成的exe文件名为gotest.exe,并且是放在当前工程目录下,然后我们用下面的 aardio 代码调用这个 gotest.exe 里的go函数:
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 39 40 41 42 43 44 45 46 47 48
| import win.ui;
var winform = win.form(text="aardio调用go语言演示";right=759;bottom=469) winform.add( button={cls="button";text="调用Go语言的Calculator.Add函数";left=382;top=389;right=678;bottom=427;z=5}; edit={cls="edit";left=19;top=12;right=732;bottom=352;edge=1;hscroll=1;multiline=1;vscroll=1;z=1}; editX={cls="edit";text="2";left=109;top=392;right=185;bottom=424;edge=1;z=2}; editY={cls="edit";text="3";left=238;top=392;right=320;bottom=420;edge=1;z=3}; static={cls="static";text="+";left=198;top=395;right=230;bottom=420;align="center";transparent=1;z=4} )
import wsock.tcp.jsonClient; import process.popen;
var gofile = process.popen("/gotest.exe"); if(!gofile) return winform.msgbox("启动go程序失败");
var url = gofile.read(); if( !url || string.startWith(url,"error:") ) return winform.msgbox("启动go程序失败");
var go = wsock.tcp.jsonClient(url) winform.edit.print("已连接到go程序",url);
winform.button.oncommand = function(id,event){ var rep = go.Calculator.Add({ X = tonumber(winform.editX.text); Y = tonumber(winform.editY.text); } ) if( rep[["result"]] ){ winform.edit.print( "调用成功", rep.result ) } else { winform.edit.print( rep[["error"]] ) } }
winform.show() win.loopMessage();
go.Calculator.Exit(0);
|
附:调用Go语言编译器例子
1 2 3 4 5 6 7 8 9 10 11 12 13
| import console; import golang;
var go = golang();
go.runCode("/hello.go",` package main import "fmt" func main() { fmt.Println("hello world") }`)
console.pause();
|
最新版golang扩展库已支持自动下载配置Go编译器。
Go最新版已经支持调用生成DLL文件(需要调用gcc),在aardio中可以直接调用Go生成的DLL文件(使用cdecl调用约定),下面是调用Go编译器生成DLL的演示。
下面看演示:
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
| import console; import golang;
var go = golang();
string.save("/hello.go",` package main
import "C" import "fmt"
//export SayHello func SayHello(name string) { fmt.Printf("Go says: %s!\n", name) }
func main() { //DLL入口函数,没有也要写个空的 } `)
go.buildShared("/hello.go","/hello.dll");
var dll = raw.loadDll("/hello.dll",,"cdecl");
console.open(); var str = "必须在Go函数名前面加上 export 函数名的注释才能导出函数"; dll.SayHello(str,#str);
console.log( n ) console.pause();
|
Go写DLL要注意一个特别的地方,Go导出函数前必须写一行注释声明导出函数,例如上面的 //export SayHello
Go语言里的字符串GoString是一个结构体,用aardio来表示是这样的:
1 2 3 4 5 6 7 8
| class goString{ ctor( str ){ this.s = str; this.n = #str; }; string s; addr n; }
|
如果是在API函数里传值,一个GoString展开为2个API参数来表示就可以了(一个字符串,后面跟一个字符串长度)
因为aardio传结构体都是传指针,如果用结构体,在Go里面要声明为指针,示例:
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 39 40 41 42 43
| import console; import golang;
var go = golang();
string.save("/hello.go",` package main
import "C" import "fmt"
//export SayHello func SayHello(name *string) { fmt.Printf("Go says: %s!\n", *name) }
func main() { //DLL入口函数,没有也要写个空的 } `)
go.buildShared("/hello.go","/hello.dll");
var dll = raw.loadDll("/hello.dll",,"cdecl");
class goString{ ctor( str ){ this.s = str; this.n = #str; }; string s; addr n; }
console.open(); dll.SayHello( goString( "必须在Go函数名前面加上 export 函数名的注释才能导出函数") );
console.log( n ) console.pause();
|
需要先安装MinGW( GCC )
可以下载安装 MinGW-W64: https://sourceforge.net/projects/mingw-w64 这个只能安装在64位系统。
也可以下载安装 TDM-GCC: http://tdm-gcc.tdragon.net/download 这个提供支持32位、64位安装包。
golang扩展库会自动搜索MinGW,MinGW-W64,TDM-GCC的安装位置,不需要手动配置。
当然也可以调用golang扩展库提供的addPath函数自己添加gcc.exe所在的目录。
Go生成的文件很大,加上-ldflags "-s -w"
参数会小一些,go.buildShared()
已经自动加上这些参数。
编译上面的代码生成的DLL只有1MB多一点,而且可以支持WinXP,不需要依赖外部运行库,还是非常不错的。
而且测试了一下,编译的DLL还能内存加载。