Go语言经过十余年的发展,已成为最流行的新兴语言。目前,Go语言已成为云计算领域的首选语言,且随着近几年区块链的流行,作为底层开发语言的Go再次火爆成为区块链技术培训领域第一编程语言,IBM的Fabic等重量级的区块链项目都是基于Go语言开发的。
殊不知,Go语言可开发的应用项目还有很多。除云计算、区块链等开源项目外,还包含Devops、人工智能、游戏、存储引擎、Web、系统/命令行工具、中间件、测试/持续交付、文件系统等各方面的开源项目。
一、获取字符串长度的几种方法
-使用 bytes.Count() 统计
-使用 strings.Count() 统计
-将字符串转换为 []rune 后调用 len 函数进行统计
-使用 utf8.RuneCountInString() 统计
例:
str:="HelloWord"
l1:=len([]rune(str))
l2:=bytes.Count([]byte(str),nil)-1)
l3:=strings.Count(str,"")-1
l4:=utf8.RuneCountInString(str)
fmt.Println(l1)
fmt.Println(l2)
fmt.Println(l3)
fmt.Println(l4)
打印结果:都是9
二、strings.Count函数和bytes.Count函数
这两个函数的用法是相同,只是一个作用在字符串上,一个作用在字节上
strings中的Count方法
func Count(s, sep string) int{}
判断字符sep在字符串s中出现的次数,没有找到则返回-1,如果为空字符串("")则返回字符串的长度+1
例:
str:="HelloWorld"
fmt.Println(strings.Count(str,"o")) //打印 o 出现的次数,打印结果为2
注:在Golang中,如果字符串中出现中文字符不能直接调用 len 函数来统计字符串字符长度,这是因为在 Go 中,字符串是以 UTF-8 为格式进行存储的,在字符串上调用 len 函数,取得的是字符串包含的 byte 的个数。
str:="HelloWorld"
str1 := "Hello,世界"
fmt.Println(len(str1)) //打印结果:13
fmt.Println(len(str)) //打印结果:9 (如果是纯英文字符的字符串,可以使用来判断字符串的长度)
如何跨语言调用golang的RPC方法
上面的三个例子,我们分别使用net/rpc、net/rpc/jsonrpc、protorpc实现了golang中的RPC服务端,并给出了对应的golang客户端RPC调用示例,因为JSON和protobuf是支持多语言的,所以使用jsonrpc和protorpc实现的RPC方法我们是可以在其他语言中进行调用的。下面给出一个php客户端程序,通过socket连接调用jsonrpc实现的服务端RPC方法。
$PHPROOT/jsonrpc.php
class JsonRPC {
private $conn;
function __construct($host, $port) {
$this->conn = fsockopen($host, $port, $errno, $errstr, 3);
if (!$this->conn) {
return false;
}
}
public function Call($method, $params) {
if (!$this->conn) {
return false;
}
$err = fwrite($this->conn, json_encode(array(
'method' => $method,
'params' => array($params),
'id' => 0,
))."\n");
if ($err === false) {
return false;
}
stream_set_timeout($this->conn, 0, 3000);
$line = fgets($this->conn);
if ($line === false) {
return NULL;
}
return json_decode($line,true);
}
}
$client = new JsonRPC("127.0.0.1", 8096);
$args = array('A'=>9, 'B'=>2);
$r = $client->Call("Arith.Multiply", $args);
printf("%d * %d = %d\n", $args['A'], $args['B'], $r['result']['Pro']);
$r = $client->Call("Arith.Divide", array('A'=>9, 'B'=>2));
printf("%d / %d, Quo is %d, Rem is %d\n", $args['A'], $args['B'], $r['result']['Quo'], $r['result']['Rem']);
其他RPC库
除了上面提到的三种在golang实现RPC的方式外,还有一些其他的rpc库提供了类似的功能,比较出名的有google开源的grpc,但是grpc的初次安装比较麻烦,这里就不做进一步介绍了,有兴趣的可以自己了解。
上面的例子我们演示了使用net/rpc实现RPC的过程,但是没办法在其他语言中调用上面例子实现的RPC方法。所以接下来的例子我们演示一下使用net/rpc/jsonrpc库实现RPC方法,此方式实现的RPC方法支持跨语言调用。
$GOPATH/src/test/rpc/jsonrpc_server.go
package main
import (
"errors"
"fmt"
"log"
"net"
"net/rpc"
"net/rpc/jsonrpc"
"os"
)
//算数运算结构体
type Arith struct {
}
//算数运算请求结构体
type ArithRequest struct {
A int
B int
}
//算数运算响应结构体
type ArithResponse struct {
Pro int //乘积
Quo int //商
Rem int //余数
}
//乘法运算方法
func (this *Arith) Multiply(req ArithRequest, res *ArithResponse) error {
res.Pro = req.A * req.B
return nil
}
//除法运算方法
func (this *Arith) Divide(req ArithRequest, res *ArithResponse) error {
if req.B == 0 {
return errors.New("divide by zero")
}
res.Quo = req.A / req.B
res.Rem = req.A % req.B
return nil
}
func main() {
rpc.Register(new(Arith)) //注册rpc服务
lis, err := net.Listen("tcp", "127.0.0.1:8096")
if err != nil {
log.Fatalln("fatal error: ", err)
}
fmt.Fprintf(os.Stdout, "%s", "start connection")
for {
conn, err := lis.Accept() //接收客户端连接请求
if err != nil {
continue
}
go func(conn net.Conn) { //并发处理客户端请求
fmt.Fprintf(os.Stdout, "%s", "new client in coming\n")
jsonrpc.ServeConn(conn)
}(conn)
}
}
上述服务端程序启动后,将会监听本地的8096端口,并处理客户端的tcp连接请求。我们可以用golang实现一个客户端程序连接上述服务端并进行RPC调用。
$GOPATH/src/test/rpc/jsonrpc_client.go
package main
import (
"fmt"
"log"
"net/rpc/jsonrpc"
)
//算数运算请求结构体
type ArithRequest struct {
A int
B int
}
//算数运算响应结构体
type ArithResponse struct {
Pro int //乘积
Quo int //商
Rem int //余数
}
func main() {
conn, err := jsonrpc.Dial("tcp", "127.0.0.1:8096")
if err != nil {
log.Fatalln("dailing error: ", err)
}
req := ArithRequest{9, 2}
var res ArithResponse
err = conn.Call("Arith.Multiply", req, &res) //乘法运算
if err != nil {
log.Fatalln("arith error: ", err)
}
fmt.Printf("%d * %d = %d\n", req.A, req.B, res.Pro)
err = conn.Call("Arith.Divide", req, &res)
if err != nil {
log.Fatalln("arith error: ", err)
}
fmt.Printf("%d / %d, quo is %d, rem is %d\n", req.A, req.B, res.Quo, res.Rem)
}
protorpc库
为了实现跨语言调用,在golang中实现RPC方法的时候我们应该选择一种跨语言的数据编解码方式,比如JSON,上述的jsonrpc可以满足此要求,但是也存在一些缺点,比如不支持http传输,数据编解码性能不高等。于是呢,一些第三方rpc库都选择采用protobuf进行数据编解码,并提供一些服务注册代码自动生成功能。下面的例子我们使用protobuf来定义RPC方法及其请求响应参数,并使用第三方的protorpc库来生成RPC服务注册代码。
首先,需要安装protobuf及protoc可执行命令,可以参考此篇文章:protobuf快速上手指南
然后,我们编写一个proto文件,定义要实现的RPC方法及其相关参数。
$GOPATH/src/test/rpc/pb/arith.proto
syntax = "proto3";
package pb;
//算术运算请求结构
message ArithRequest {
int32 a = 1;
int32 b = 2;
}
//算术运算响应结构
message ArithResponse {
int32 pro = 1; //乘积
int32 quo = 2; //商
int32 rem = 3; //余数
}
// rpc方法
service ArithService {
rpc multiply (ArithRequest) returns (ArithResponse); //乘法运算方法
rpc divide (ArithRequest) returns (ArithResponse); //除法运算方法
}
接下来我们需要根据上述定义的arith.proto文件生成RPC服务代码。
要先安装protorpc库:go get github.com/chai2010/protorpc
然后使用protoc工具生成代码:protoc --go_out=plugin=protorpc=. arith.proto
执行protoc命令后,在与arith.proto文件同级的目录下生成了一个arith.pb.go文件,里面包含了RPC方法定义和服务注册的代码。
基于生成的arith.pb.go代码我们来实现一个rpc服务端
$GOPATH/src/test/rpc/protorpc_server.go
package main
import (
"errors"
"test/rpc/pb"
)
//算术运算结构体
type Arith struct {
}
//乘法运算方法
func (this *Arith) Multiply(req *pb.ArithRequest, res *pb.ArithResponse) error {
res.Pro = req.GetA() * req.GetB()
return nil
}
//除法运算方法
func (this *Arith) Divide(req *pb.ArithRequest, res *pb.ArithResponse) error {
if req.GetB() == 0 {
return errors.New("divide by zero")
}
res.Quo = req.GetA() / req.GetB()
res.Rem = req.GetA() % req.GetB()
return nil
}
func main() {
pb.ListenAndServeArithService("tcp", "127.0.0.1:8097", new(Arith))
}
运行上述程序,将会监听本地的8097端口并接收客户端的tcp连接。
基于ariti.pb.go再来实现一个客户端程序。
$GOPATH/src/test/protorpc_client.go
package main
import (
"fmt"
"log"
"test/rpc/pb"
)
func main() {
conn, err := pb.DialArithService("tcp", "127.0.0.1:8097")
if err != nil {
log.Fatalln("dailing error: ", err)
}
defer conn.Close()
req := &pb.ArithRequest{9, 2}
res, err := conn.Multiply(req)
if err != nil {
log.Fatalln("arith error: ", err)
}
fmt.Printf("%d * %d = %d\n", req.GetA(), req.GetB(), res.GetPro())
res, err = conn.Divide(req)
if err != nil {
log.Fatalln("arith error ", err)
}
fmt.Printf("%d / %d, quo is %d, rem is %d\n", req.A, req.B, res.Quo, res.Rem)
}
ڡǕ��_'�
有疑问加站长微信联系(非本文作者)