C++GO语言微服务基础技术①

目录

01-项目简介

02-单体式架构

03-微服务优缺点

04-单体式和微服务区别

05-RPC简介

06-RPC使用步骤

07-注册RPC服务函数接口

08-绑定服务和调用方法函数接口

09-rpc服务端和客户端编码实现

10-json的rpc

11-rpc的封装

12-rpc封装小结


01-项目简介

复制代码
# 单体式和微服务



## 单体式架构服务 

—— 过往大家熟悉的服务器。

特性:

1.  复杂性随着开发越来越高, 遇到问题解决困难。
2.  技术债务逐渐上升。
3.  耦合度高,维护成本大!
    1. 出现bug, 不容易排查
    2. 解决旧bug, 会出新bug
4.  持续交付时间较长。
5.  技术选型成本高,风险大。
6.  扩展性较差
    1. 垂直扩展:通过增加单个系统程的负荷来实现扩展。
    2. 水平扩展:通过增加更多的系统成员来实现扩展。

02-单体式架构

复制代码
## 微服务

- 优点:
    1.  职责单一
    2.  轻量级通信
    3.  独立性
    4.  迭代开发。
- 缺点:
    1.  运维成本高
    2.  分部式复杂度
    3.  接口成本高
    4.  重复性劳动
    5.  业务分离困难。

03-微服务优缺点

04-单体式和微服务区别

复制代码
# RPC 协议

## 什么是RPC

Remote Procedure Call Protocol   —— 远程过程调用协议!

IPC: 进程间通信 

RPC:远程进通信 —— 应用层协议(http协议同层)。底层使用 TCP 实现。

> 回顾:
>
> OSI 7 层模型架构:物、数、网、传、会、表、应
>
> TCP/IP 4 层架构:链路层、网络层、传输层、应用层

- 理解RPC:
    - **==像调用本地函数一样,去调用远程函数。==**
        - 通过rpc协议,传递:函数名、函数参数。达到在本地,调用远端函数,得返回值到本地的目标。

- 为什么微服务使用 RPC:

    1.  每个服务都被封装成 进程。彼此”独立“。

    2.  进程和进程之间,可以使用不同的语言实现。

05-RPC简介

复制代码
### RPC 入门使用

远程 —— 网络!!

> 回顾:Go语言 一般性 网络socket通信 
>
> server端:
>
> ​		net.Listen()  —— listener      创建监听器
>
> ​		listener.Accpet()  —— conn   启动监听,建立连接
>
> ​		conn.read() 
>
> ​        conn.write()
>
> ​        defer conn.Close() / listener.Close()
>
> client端:
>
> ​		net.Dial()  —— conn
>
> ​		conn.Write() 
>
> ​		conn.Read()
>
> ​        defer conn.Close()

06-RPC使用步骤

复制代码
### RPC 使用的步骤

---- 服务端:

1.  注册 rpc 服务对象。给对象绑定方法( 1. 定义类, 2. 绑定类方法 )

    ```go
    rpc.RegisterName("服务名",回调对象)
    ```

    

2.  创建监听器 

    ```go
    listener, err := net.Listen()
    ```

    

3.  建立连接

    ```go
    conn, err := listener.Accept()
    ```

    

4.  将连接 绑定 rpc 服务。

    ```go
    rpc.ServeConn(conn)
    ```

07-注册RPC服务函数接口

复制代码
---- 客户端:

1. 用 rpc 连接服务器。

    ```go
    conn, err := rpc.Dial()
    ```

    

2. 调用远程函数。

    ```go
    conn.Call("服务名.方法名", 传入参数, 传出参数)
    ```

    

## RPC 相关函数

1. 注册 rpc 服务

    ```go
    func (server *Server) RegisterName(name string, rcvr interface{}) error
    	参1:服务名。字符串类型。
    	参2:对应 rpc 对象。 该对象绑定方法要满足如下条件:
    		1)方法必须是导出的 —— 包外可见。 首字母大写。
    		2)方法必须有两个参数, 都是导出类型、內建类型。
    		3)方法的第二个参数必须是 “指针” (传出参数)
    		4)方法只有一个 error 接口类型的 返回值。
    举例:
    
    type World stuct {
    }		
    func (this *World) HelloWorld (name string, resp *string) error { 
    }
    rpc.RegisterName("服务名", new(World))
    ```

08-绑定服务和调用方法函数接口

复制代码
2. 绑定 rpc 服务

    ```go
    func (server *Server) ServeConn(conn io.ReadWriteCloser)
    	conn: 成功建立好连接的 socket —— conn
    ```

3. 调用远程函数:

    ```go
    func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error
    	serviceMethod: “服务名.方法名”
    	args:传入参数。 方法需要的数据。
    	reply:传出参数。定义 var 变量,&变量名  完成传参。

09-rpc服务端和客户端编码实现

复制代码
## 编码实现

server端

```go
package main

import (
	"net/rpc"
	"fmt"
	"net"
)

// 定义类对象
type World struct {
}

// 绑定类方法
func (this *World) HelloWorld (name string, resp *string) error {
	*resp = name + " 你好!"
	return nil
}

func main()  {
	// 1. 注册RPC服务, 绑定对象方法
	err := rpc.RegisterName("hello", new(World))
	if err != nil {
		fmt.Println("注册 rpc 服务失败!", err)
		return
	}

	// 2. 设置监听
	listener, err := net.Listen("tcp", "127.0.0.1:8800")
	if err != nil {
		fmt.Println("net.Listen err:", err)
		return
	}
	defer listener.Close()

	fmt.Println("开始监听 ...")
	// 3. 建立链接
	conn, err := listener.Accept()
	if err != nil {
		fmt.Println("Accept() err:", err)
		return
	}
	defer conn.Close()
	fmt.Println("链接成功...")

	// 4. 绑定服务
	rpc.ServeConn(conn)
}

10-json的rpc

复制代码
client端

```go
package main

import (
	"net/rpc"
	"fmt"
)

func main()  {
	// 1. 用 rpc 链接服务器 --Dial()
	conn, err := rpc.Dial("tcp", "127.0.0.1:8800")
	if err != nil {
		fmt.Println("Dial err:", err)
		return
	}
	defer conn.Close()

	// 2. 调用远程函数
	var reply string 		// 接受返回值 --- 传出参数

	err = conn.Call("hello.HelloWorld", "李白", &reply)
	if err != nil {
		fmt.Println("Call:", err)
		return
	}

	fmt.Println(reply)
}
```

11-rpc的封装

复制代码
## json 版 rpc

- 使用 nc -l 127.0.0.1 880 充当服务器。
-  02-client.go 充当 客户端。 发起通信。 —— 乱码。 
    - 因为:RPC 使用了go语言特有的数据序列化 gob。 其他编程语言不能解析。
- 使用 通用的 序列化、反序列化。 —— json、protobuf

### 修改客户端

修改客户端,使用jsonrpc:

```go
conn, err := jsonrpc.Dial("tcp", "127.0.0.1:8800")
```

使用 nc -l 127.0.0.1 880 充当服务器。

看到结果:

​		{"method":"hello.HelloWorld","params":["李白"],"id":0}

### 修改服务器端

修改服务器端,使用 jsonrpc:

```go
jsonrpc.ServeConn(conn)
```

使用 nc 127.0.0.1 880 充当客户端。

看到结果:

​			echo -e '{"method":"hello.HelloWorld","params":["李白"],"id":0}' | nc 127.0.0.1 8800

**如果,绑定方法返回值的 error 不为空? 无论传出参数是否有值,服务端都不会返回数据。** 

12-rpc封装小结

复制代码
## rpc 封装

#### 服务端封装

1. ```go
    // 定义接口
    type xxx interface {
        方法名(传入参数,传出参数) error
    }
    例:
    type MyInterface interface {
        HelloWorld(string, *string) error
    }
    ```

2. ```go
    // 封装注册服务方法
    func RegisterService (i MyInterface) {
        rpc.RegisterName("hello", i)
    }
    ```



#### 客户端封装

1. ```go
    // 定义类
    type MyClient struct {
        c *rpc.Client
    }
    ```

2. ```go
    // 绑定类方法
    func (this *MyClient)HelloWorld(a string, b *string) error {
       return  this.c.Call("hello.HelloWorld", a, b)
    }
    ```

3. ```go
    // 初始客户端
    func InitClient(addr string) error {
        conn, _ := jsonrpc.Dial("tcp", adddr)
        return MyClient{c:conn}
    }
    ```

    

# protobuf
相关推荐
freshman_y25 分钟前
Qt实现车载多媒体项目,包含天气、音乐、视频、地图、五子棋功能模块,免费下载源文件!
开发语言·qt
拾忆-eleven38 分钟前
C++算法(19):整数类型极值,从INT_MIN原理到跨平台开发实战
数据结构·c++·算法
HelloZheQ1 小时前
Go:简洁高效,构建现代应用的利器
开发语言·后端·golang
悟能不能悟1 小时前
java实现一个操作日志模块功能,怎么设计
java·开发语言
Hxyle1 小时前
c++设计模式
开发语言·c++·设计模式
blammmp2 小时前
算法专题四:前缀和
java·开发语言·算法
www_pp_2 小时前
# 创建一个功能完备的计算器应用:使用PyQt5和Python
开发语言·python·qt
Aimyon_362 小时前
Java复习笔记-基础
java·开发语言·笔记
神仙别闹2 小时前
基于QT(C++)实现(图形界面)校园导览系统
数据库·c++·qt
明月看潮生2 小时前
青少年编程与数学 02-018 C++数据结构与算法 25课题、图像处理算法
c++·图像处理·算法·青少年编程·编程与数学