189 8069 5689

go跨语言调用 go语言 跨平台

怎么样使用Go语言中函数的参数传递与调用

按值传递函数参数,是拷贝参数的实际值到函数的形式参数的方法调用。在这种情况下,参数在函数内变化对参数不会有影响。

创新互联公司是一家专业提供善右企业网站建设,专注与成都网站设计、做网站、H5页面制作、小程序制作等业务。10年已为善右众多企业、政府机构等服务。创新互联专业网站建设公司优惠进行中。

默认情况下,Go编程语言使用调用通过值的方法来传递参数。在一般情况下,这意味着,在函数内码不能改变用来调用所述函数的参数。考虑函数swap()的定义如下。

代码如下:

/* function definition to swap the values */

func swap(int x, int y) int {

var temp int

temp = x /* save the value of x */

x = y /* put y into x */

y = temp /* put temp into y */

return temp;

}

现在,让我们通过使实际值作为在以下示例调用函数swap():

代码如下:

package main

import "fmt"

func main() {

/* local variable definition */

var a int = 100

var b int = 200

fmt.Printf("Before swap, value of a : %d\n", a )

fmt.Printf("Before swap, value of b : %d\n", b )

/* calling a function to swap the values */

swap(a, b)

fmt.Printf("After swap, value of a : %d\n", a )

fmt.Printf("After swap, value of b : %d\n", b )

}

func swap(x, y int) int {

var temp int

temp = x /* save the value of x */

x = y /* put y into x */

y = temp /* put temp into y */

return temp;

}

让我们把上面的代码放在一个C文件,编译并执行它,它会产生以下结果:

Before swap, value of a :100

Before swap, value of b :200

After swap, value of a :100

After swap, value of b :200

这表明,参数值没有被改变,虽然它们已经在函数内部改变。

通过传递函数参数,即是拷贝参数的地址到形式参数的参考方法调用。在函数内部,地址是访问调用中使用的实际参数。这意味着,对参数的更改会影响传递的参数。

要通过引用传递的值,参数的指针被传递给函数就像任何其他的值。所以,相应的,需要声明函数的参数为指针类型如下面的函数swap(),它的交换两个整型变量的值指向它的参数。

代码如下:

/* function definition to swap the values */

func swap(x *int, y *int) {

var temp int

temp = *x /* save the value at address x */

*x = *y /* put y into x */

*y = temp /* put temp into y */

}

现在,让我们调用函数swap()通过引用作为在下面的示例中传递数值:

代码如下:

package main

import "fmt"

func main() {

/* local variable definition */

var a int = 100

var b int= 200

fmt.Printf("Before swap, value of a : %d\n", a )

fmt.Printf("Before swap, value of b : %d\n", b )

/* calling a function to swap the values.

* a indicates pointer to a ie. address of variable a and

* b indicates pointer to b ie. address of variable b.

*/

swap(a, b)

fmt.Printf("After swap, value of a : %d\n", a )

fmt.Printf("After swap, value of b : %d\n", b )

}

func swap(x *int, y *int) {

var temp int

temp = *x /* save the value at address x */

*x = *y /* put y into x */

*y = temp /* put temp into y */

}

让我们把上面的代码放在一个C文件,编译并执行它,它会产生以下结果:

Before swap, value of a :100

Before swap, value of b :200

After swap, value of a :200

After swap, value of b :100

这表明变化的功能以及不同于通过值调用的外部体现的改变不能反映函数之外。

微服务跨语言调用(摘选)

微服务架构已成为目前互联网架构的趋势,关于微服务的讨论,几乎占据了各种技术大会的绝大多数版面。国内使用最多的服务治理框架非阿里开源的 dubbo 莫属,千米网也选择了 dubbo 作为微服务治理框架。另一方面,和大多数互联网公司一样,千米的开发语言是多样的,大多数后端业务由 java 支撑,而每个业务线有各自开发语言的选择权,便出现了 nodejs,python,go 多语言调用的问题。

跨语言调用是一个很大的话题,也是一个很有挑战的技术活,目前业界经常被提及的解决方案有如下几种,不妨拿出来老生常谈一番:

当我们再聊跨语言调用时我们在聊什么?纵观上述几个较为通用,成熟的解决方案,可以得出结论:解决跨语言调用的思路无非是两种:

如果一个新型的团队面临技术选型,我认为上述的方案都可以纳入参考,可考虑到遗留系统的兼容性问题

旧系统的迁移成本

这也关键的选型因素。我们做出的第一个尝试,便是在 RPC 协议上下功夫。

通用协议的跨语言支持

springmvc的美好时代

springmvc

springmvc

在没有实现真正的跨语言调用之前,想要实现“跨语言”大多数方案是使用 http 协议做一层转换,最常见的手段莫过于借助 springmvc 提供的 controller/restController,间接调用 dubbo provider。这种方案的优势和劣势显而易见

通用协议的支持

事实上,大多数服务治理框架都支持多种协议,dubbo 框架除默认的 dubbo 协议之外,还有当当网扩展的 rest协议和千米网扩展的 json-rpc 协议可供选择。这两者都是通用的跨语言协议。

rest 协议为满足 JAX-RS 2.0 标准规范,在开发过程中引入了 @Path,@POST,@GET 等注解,习惯于编写传统 rpc 接口的人可能不太习惯 rest 风格的 rpc 接口。一方面这样会影响开发体验,另一方面,独树一帜的接口风格使得它与其他协议不太兼容,旧接口的共生和迁移都无法实现。如果没有遗留系统,rest 协议无疑是跨语言方案最简易的实现,绝大多数语言支持 rest 协议。

和 rest 协议类似,json-rpc 的实现也是文本序列化http 协议。dubbox 在 restful 接口上已经做出了尝试,但是 rest 架构和 dubbo 原有的 rpc 架构是有区别的,rest 架构需要对资源(Resources)进行定义, 需要用到 http 协议的基本操作 GET、POST、PUT、DELETE。在我们看来,restful 更合适互联网系统之间的调用,而 rpc 更适合一个系统内的调用。使用 json-rpc 协议使得旧接口得以兼顾,开发习惯仍旧保留,同时获得了跨语言的能力。

千米网在早期实践中采用了 json-rpc 作为 dubbo 的跨语言协议实现,并开源了基于 json-rpc 协议下的 python 客户端 dubbo-client-py 和 node 客户端 dubbo-node-client,使用 python 和 nodejs 的小伙伴可以借助于它们直接调用 dubbo-provider-java 提供的 rpc 服务。系统中大多数 java 服务之间的互相调用还是以 dubbo 协议为主,考虑到新旧协议的适配,在不影响原有服务的基础上,我们配置了双协议。

dubbo 协议主要支持 java 间的相互调用,适配老接口;json-rpc 协议主要支持异构语言的调用。

定制协议的跨语言支持

微服务框架所谓的协议(protocol)可以简单理解为:报文格式和序列化方案。服务治理框架一般都提供了众多的协议配置项供使用者选择,除去上述两种通用协议,还存在一些定制化的协议,如 dubbo 框架的默认协议:dubbo 协议以及 motan 框架提供的跨语言协议:motan2。

motan2协议的跨语言支持

   motan2

motan2

motan2 协议被设计用来满足跨语言的需求主要体现在两个细节中—MetaData 和 motan-go。在最初的 motan 协议中,协议报文仅由 Header+Body 组成,这样导致 path,param,group 等存储在 Body 中的数据需要反序列得到,这对异构语言来说是很不友好的,所以在 motan2 中修改了协议的组成;weibo 开源了 motan-go ,motan-php ,motan-openresty ,并借助于 motan-go 充当了 agent 这一翻译官的角色,使用 simple 序列化方案来序列化协议报文的 Body 部分(simple 序列化是一种较弱的序列化方案)。

   agent

agent

仔细揣摩下可以发现这么做和双协议的配置区别并不是大,只不过这里的 agent 是隐式存在的,与主服务共生。明显的区别在于 agent 方案中异构语言并不直接交互。

dubbo协议的跨语言支持

dubbo 协议设计之初只考虑到了常规的 rpc 调用场景,它并不是为跨语言而设计,但跨语言支持从来不是只有支持、不支持两种选择,而是要按难易程度来划分。是的,dubbo 协议的跨语言调用可能并不好做,但并非无法实现。千米网便实现了这一点,nodejs 构建的前端业务是异构语言的主战场,最终实现了 dubbo2.js,打通了 nodejs 和原生 dubbo 协议。作为本文第二部分的核心内容,重点介绍下我们使用 dubbo2.js 干了什么事。

Dubbo协议报文格式

   dubbo协议

dubbo协议

dubbo协议报文消息头详解:

magic:类似java字节码文件里的魔数,用来判断是不是 dubbo 协议的数据包。魔数是常量 0xdabb

flag:标志位, 一共8个地址位。低四位用来表示消息体数据用的序列化工具的类型(默认 hessian),高四位中,第一位为 1 表示是 request 请求,第二位为 1 表示双向传输(即有返回 response),第三位为 1 表示是心跳 ping 事件。

status:状态位, 设置请求响应状态,dubbo 定义了一些响应的类型。具体类型见com.alibaba.dubbo.remoting.exchange.Response

invoke id:消息 id, long 类型。每一个请求的唯一识别 id(由于采用异步通讯的方式,用来把请求 request 和返回的 response 对应上)

body length:消息体 body 长度, int 类型,即记录 Body Content 有多少个字节

body content:请求参数,响应参数的抽象序列化之后存储于此。

协议报文最终都会变成字节,使用 tcp 传输,任何语言只要支持网络模块,有类似 Socket 之类的封装,那么通信就不成问题。那,跨语言难在哪儿?以其他语言调用 java 来说,主要有两个难点:

ps:dubbo 协议通讯demo( )

一学就会,手把手教你用Go语言调用智能合约

智能合约调用是实现一个 DApp 的关键,一个完整的 DApp 包括前端、后端、智能合约及区块 链系统,智能合约的调用是连接区块链与前后端的关键。

我们先来了解一下智能合约调用的基础原理。智能合约运行在以太坊节点的 EVM 中。因此要 想调用合约必须要访问某个节点。

以后端程序为例,后端服务若想连接节点有两种可能,一种是双 方在同一主机,此时后端连接节点可以采用 本地 IPC(Inter-Process Communication,进 程间通信)机制,也可以采用 RPC(Remote Procedure Call,远程过程调用)机制;另 一种情况是双方不在同一台主机,此时只能采用 RPC 机制进行通信。

提到 RPC, 读者应该对 Geth 启动参数有点印象,Geth 启动时可以选择开启 RPC 服务,对应的 默认服务端口是 8545。。

接着,我们来了解一下智能合约运行的过程。

智能合约的运行过程是后端服务连接某节点,将 智能合约的调用(交易)发送给节点,节点在验证了交易的合法性后进行全网广播,被矿工打包到 区块中代表此交易得到确认,至此交易才算完成。

就像数据库一样,每个区块链平台都会提供主流 开发语言的 SDK(Software Development Kit,软件开发工具包),由于 Geth 本身就是用 Go 语言 编写的,因此若想使用 Go 语言连接节点、发交易,直接在工程内导入 go-ethereum(Geth 源码) 包就可以了,剩下的问题就是流程和 API 的事情了。

总结一下,智能合约被调用的两个关键点是节点和 SDK。

由于 IPC 要求后端与节点必须在同一主机,所以很多时候开发者都会采用 RPC 模式。除了 RPC,以太坊也为开发者提供了 json- rpc 接口,本文就不展开讨论了。

接下来介绍如何使用 Go 语言,借助 go-ethereum 源码库来实现智能合约的调用。这是有固定 步骤的,我们先来说一下总体步骤,以下面的合约为例。

步骤 01:编译合约,获取合约 ABI(Application Binary Interface,应用二进制接口)。 单击【ABI】按钮拷贝合约 ABI 信息,将其粘贴到文件 calldemo.abi 中(可使用 Go 语言IDE 创建该文件,文件名可自定义,后缀最好使用 abi)。

最好能将 calldemo.abi 单独保存在一个目录下,输入“ls”命令只能看到 calldemo.abi 文件,参 考效果如下:

步骤 02:获得合约地址。注意要将合约部署到 Geth 节点。因此 Environment 选择为 Web3 Provider。

在【Environment】选项框中选择“Web3 Provider”,然后单击【Deploy】按钮。

部署后,获得合约地址为:0xa09209c28AEf59a4653b905792a9a910E78E7407。

步骤 03:利用 abigen 工具(Geth 工具包内的可执行程序)编译智能合约为 Go 代码。abigen 工具的作用是将 abi 文件转换为 Go 代码,命令如下:

其中各参数的含义如下。 (1)abi:是指定传入的 abi 文件。 (2)type:是指定输出文件中的基本结构类型。 (3)pkg:指定输出文件 package 名称。 (4)out:指定输出文件名。 执行后,将在代码目录下看到 funcdemo.go 文件,读者可以打开该文件欣赏一下,注意不要修改它。

步骤 04:创建 main.go,填入如下代码。 注意代码中 HexToAddress 函数内要传入该合约部署后的地址,此地址在步骤 01 中获得。

步骤 04:设置 go mod,以便工程自动识别。

前面有所提及,若要使用 Go 语言调用智能合约,需要下载 go-ethereum 工程,可以使用下面 的指令:

该指令会自动将 go-ethereum 下载到“$GOPATH/src/github点抗 /ethereum/go-ethereum”,这样还算 不错。不过,Go 语言自 1.11 版本后,增加了 module 管理工程的模式。只要设置好了 go mod,下载 依赖工程的事情就不必关心了。

接下来设置 module 生效和 GOPROXY,命令如下:

在项目工程内,执行初始化,calldemo 可以自定义名称。

步骤 05:运行代码。执行代码,将看到下面的效果,以及最终输出的 2020。

上述输出信息中,可以看到 Go 语言会自动下载依赖文件,这就是 go mod 的神奇之处。看到 2020,相信读者也知道运行结果是正确的了。

golang调用java

golang调用java是什么,让我们一起了解一下?

golang是一种静态强类型、编译型语言。功能上有:内存安全,GC(垃圾回收),结构形态及 CSP-style 并发计算,golang调用java就是接收一个参数,然后输出一行结果。

由于Java世界里有非常丰富的开源应用模型和轮子,而这些正是Go世界里面最缺乏的东西,所以我首先考虑的就是如何在Go里面调用现有的Java代码。

我们用一个简单的Go调用Java的例子,来进行测试。(在winxp环境下能够正常运行)这段代码比较简单,就是在Go代码里面去call一个叫Hello的java对象。而这个Hello .java功能也非常简单,就是接收一个参数,然后输出一行结果。

// run_java package main   import ( "fmt" "os/exec" )   /** * 调用一个Hello.class,并接收一个参数 */ func callJava(){ cmd := exec.Command("java","Hello","tom") out,err := cmd.Output() if err != nil { println("error:",err.Error()) } fmt.Printf("call java class Hello: %q\n", string(out))   } func main() { fmt.Println("Test Call Java function!") callJava() }   /* Hello.java public class Hello{ public static void main(String[] args){ if(args.length==0) System.out.println("hello my world!"); else System.out.println("hello my world! "+args[0]); } }*/

注意:

为了能够运行我的例子,需要把Hello.class放在和 run_java的可执行文件同样的目录下。例如, run_java.exe在d:\goproject下,那么Hello.class也要在d:\goproject下。


当前名称:go跨语言调用 go语言 跨平台
本文网址:http://jkwzsj.com/article/ddjdsjc.html

其他资讯