惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
人人都是产品经理
人人都是产品经理
爱范儿
爱范儿
WordPress大学
WordPress大学
T
Tor Project blog
Jina AI
Jina AI
美团技术团队
酷 壳 – CoolShell
酷 壳 – CoolShell
V
V2EX
雷峰网
雷峰网
博客园 - 聂微东
B
Blog RSS Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 【当耐特】
Microsoft Azure Blog
Microsoft Azure Blog
S
SegmentFault 最新的问题
Recent Announcements
Recent Announcements
有赞技术团队
有赞技术团队
GbyAI
GbyAI
aimingoo的专栏
aimingoo的专栏
U
Unit 42
博客园 - Franky
Last Week in AI
Last Week in AI
阮一峰的网络日志
阮一峰的网络日志
Microsoft Security Blog
Microsoft Security Blog
F
Fortinet All Blogs
罗磊的独立博客
云风的 BLOG
云风的 BLOG
G
Google Developers Blog
大猫的无限游戏
大猫的无限游戏
Engineering at Meta
Engineering at Meta
C
Check Point Blog
Martin Fowler
Martin Fowler
The Cloudflare Blog
N
Netflix TechBlog - Medium
小众软件
小众软件
T
Tailwind CSS Blog
T
The Blog of Author Tim Ferriss
月光博客
月光博客
博客园 - 司徒正美
Stack Overflow Blog
Stack Overflow Blog
J
Java Code Geeks
Blog — PlanetScale
Blog — PlanetScale
P
Proofpoint News Feed
H
Help Net Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
The Exploit Database - CXSecurity.com
S
Securelist
I
Intezer
Spread Privacy
Spread Privacy

Razeen`s Blog

Let's Encrypt 推出 Gen Y 根证书架构:揭示 Web PKI 的五大未来趋势 通过 Wi-Fi 自动备份你的 iPhone 到 Nas 管理培训感悟:从技术视角看管理之路 UPS 一拖多:保护你的 NAS 和 Linux 服务器 从影音中心到 AI 助手:我的50款 Homelab 服务清单 从SSL证书有效期将缩短到47天聊开去 部署一个自己的 Running Page 谈谈特斯拉 Model Y 用车一年的感受和费用分析 弃用 Disqus 评论,使用自建 Waline 使用 Prometheus 和 Grafana 搭建你的证书监控面板 服务器迁移记:一次磁盘换板引发的Linux分区与挂载的学习 改善信息来源, 利用 RSS 高效获取资讯 (RSShub + Reeder5 + WeWe RSS) 多种 Docker 镜像拉取解决方案与实践 App分享 | AppCleaner - Mac上的卸载神器 Azure OpenAI API 申请和使用 如何开通 OneKey 虚拟信用卡,并充值消费 如何拥有一个可长期在国内使用的国外手机号码 分享开通 ChatGPT Plus 过程 如何开通 Depay 虚拟信用卡,并充值消费 如何开通欧易Web3钱包, 交易入账 如何5分钟内1块钱注册 ChatGPT 如何注册美区的 Apple ID (2023年/无需科学上网) NAS折腾记(11): NASTool3.0体验和降级 NAS折腾记(10): Docker版本的NASTool配置 NAS折腾记(9): NASTool与微信交互,微信发送消息远程下载电影【多图】 NAS折腾记(8):群晖安装 NASTool 实现影音半自动化【多图】 内网穿透(2):Tailscale 组网实现内网穿透,操作简单,无成本 内网穿透(1):总结了11中内网穿透的方式,总有一种适合你 NAS折腾记(7):从零开始设置(黑)群晖系统 NAS折腾记(6):黑群晖系统安装好后怎么洗白? NAS折腾记(5):群晖硬盘休眠设置与分析 NAS折腾记(4): 20分钟手把手带你完美安装 DS918+ 黑群晖7.1.1 NAS折腾记(3):NAS 装机 NAS折腾记(2):B360-ITX 双M.2 双2.5G网口 6 SATA主版 开箱 NAS折腾记(1):328元的4盘位Nas机箱开箱 Openwrt + Clash 全局科学上网 Newifi3 刷入 OpenWrt 固件 v21.02 利用 Markdown 画一些流程图、时序图、甘特图等 Homelab(8): 搭建自用 Gitlab 与 Docker 仓库 Nginx Tcp 转发保留客户端真实 IP (PROXY Protocol) Homelab (7):IPSec VPN(基于证书认证)客户端设置 Homelab (6): 基于自签发证书的 IPSec VPN 搭建 Homelab (5): DDNS 动态域名解析 Homelab (4): Linux 服务器基础环境准备 Homelab (3): 整体网络与基础硬件介绍 Go学习笔记(十)老项目迁移 go module 大型灾难记录 Github Actions 初体验之自动化部署 Hexo 博客 记一次 Nginx DNS 缓存导致转发问题 Homelab (2): 电信悦me网关修改桥接模式,路由器拨号 Homelab (1):5分钟上手黑群晖 NAS 终极 Bash 脚本指南 Typora 自动上传图片到七牛云 Ubuntu 20.04 LTS 有线网卡驱动安装 折腾 Ubuntu 20.04 LTS 开发环境 Go学习笔记(九) 计时器的生命周期[译] 利用 git hook 规范你的代码与 commit message 规范 git commit message 与自动化版本控制 超详细 vim 配置 (with MacVim) Golang 中的 RESTful API 最佳实践 折腾服务器(开篇) 我的第一台个人服务器 Newifi3 实现低成本家庭级科学上网 Go学习笔记(八) | 使用 os/exec 执行命令 如何用 Go 调用 Windows API Mac OS 自动根据 WI-FI 名字改变网络位置 关于 Docker 清理 MIME Types 速查表 Go学习笔记(七) | 理解OAuth 2.0并实现一个客户端 我又又又把博客迁移了 Go学习笔记(六) | 使用swaggo自动生成Restful API文档 Go学习笔记(五) | 使用代码片段(snippets)提高编码效率 书单 - 2018 IPFS 初体验,利用 IPFS 托管你的静态网站 记一次 PostgreSQL LIKE 索引优化,联合字段 LIKE 查询优化。 Disqus 添加有趣的 Reactions 的功能 TLS 1.3 详解 (RFC 8446解读) gRPC在Go中的使用(三)gRPC实现TLS加密通信与流模式 gRPC在Go中的使用(一)Protocol Buffers语法与相关使用 CentOS 安装 tshark 抓包工具 Go学习笔记(四) | win上使用VSCode搭建Go开发环境 日常 Postgres 数据库点滴记录 简单了解 PKCS 规范 美食篇 | DIY戚风蛋糕(烤箱做蛋糕) Go学习笔记(三) | 怎么写Go基准测试(性能测试) TLS1.3正式更新,为Nginx添加TLS1.3的支持 一次诡异的数据库删除 GitHub Pages自定义域名开启HTTPS 证书透明度是什么?它是怎么工作的? Go学习笔记(二) | 我对 recover 的一点误解 搭建证书透明度(certificate-transparency)日志服务之从入门到放弃 修复远程登陆 Centos 时,出现 UTF-8 Warning HTTPS篇之SSL握手过程详解 Go学习笔记(一) | postgres与golang点点滴滴 AWS 命令行界面(aws-cli)从安装到快速上手 数字证书分类及怎么区分各类数字证书 常用 linux 命令小结(一)文件目录操作 云服务器搭建 hexo 博客,git hooks自动更新 SSH 免密登陆, SSH Config 配置 Golang CGO Mac 交叉编译 Windows 使用 goose 让数据库迁移更加轻松 开始使用Ghost
gRPC在Go中的使用(二)gRPC实现简单通讯
2018-07-19 · via Razeen`s Blog

在上一篇中,我们用protobuf定义了两个消息HelloWorldRequestHelloWorldResponse以及一个HelloWorldService服务。同时,我们还生成了相应的go代码.pb.go

那么客户端与服务端怎么去通过这些接口去完成通讯呢?下面我们一起实现一个简单的gRPC通讯。

在RPC通讯中,客户端使用存根(SayHelloWorld)发送请求到服务器并且等待响应返回,整个过程就像我们平常函数调用一样。

service HelloWorldService {
  rpc SayHelloWorld(HelloWorldRequest) returns (HelloWorldResponse){}
}

那么接下来,我们先创建一个服务端。

创建服务端

在生成的hello_world.pb.go中,已经为我们生成了服务端的接口:

// HelloWorldServiceServer is the server API for HelloWorldService service.
type HelloWorldServiceServer interface {
	SayHelloWorld(context.Context, *HelloWorldRequest) (*HelloWorldResponse, error)
}

在服务端我们首先要做的就是实现这个接口。

package main

import (
	"context"
	"log"
	"net"

	pb "github.com/razeencheng/demo-go/grpc/demo2/helloworld"

	"github.com/golang/protobuf/ptypes"
	"github.com/golang/protobuf/ptypes/any"
	"google.golang.org/grpc"
)

type SayHelloServer struct{}

func (s *SayHelloServer) SayHelloWorld(ctx context.Context, in *pb.HelloWorldRequest) (res *pb.HelloWorldResponse, err error) {
	log.Printf("Client Greeting:%s", in.Greeting)
	log.Printf("Client Info:%v", in.Infos)

	var an *any.Any
	if in.Infos["hello"] == "world" {
		an, err = ptypes.MarshalAny(&pb.HelloWorld{Msg: "Good Request"})
	} else {
		an, err = ptypes.MarshalAny(&pb.Error{Msg: []string{"Bad Request", "Wrong Info Msg"}})
	}

	if err != nil {
		return
	}
	return &pb.HelloWorldResponse{
		Reply:   "Hello World !!",
		Details: []*any.Any{an},
	}, nil
}

简单如上面的几行,实现了这个接口我们只需要创建一个结构SayHelloServer,同时实现HelloWorldServiceServer的所有方法即可。

这里为了演示效果我打印了一些数据,同时利用any.Any在不同的情况下返回不同的类型数据。

当然,只是现实了接口还不够,我们还需要启动一个服务,这样客户端才能使用该服务。启动服务很简单,就像我们平常启用一个Server一样。

func main() {
	// 我们首先须监听一个tcp端口
	lis, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}
	
    // 新建一个grpc服务器
	grpcServer := grpc.NewServer()
    // 向grpc服务器注册SayHelloServer
	pb.RegisterHelloWorldServiceServer(grpcServer, &SayHelloServer{})
    // 启动服务
	grpcServer.Serve(lis)
}

从上面的代码,我们可以看到,简单的4步即可启动一个服务。

  1. 监听一个服务端口,供客户端调用;
  2. 创建一个grpc服务器,当然这里可以设置授权认证,这个在下一篇中我们将详细介绍;
  3. 注册服务,其实是调用生存的.pb.go中的RegisterHelloWorldServiceServer方法,将我们这里实现的SayHelloServer加入到该服务中。
  4. 启动服务,等待客户端连接。

我们 go run server.go,无任何报错,这样一个简单的grpc服务的服务端就准备就绪了。接下来我们看看客户端。

创建客户端

例如:

package main

import (
	"context"
	"log"

	"google.golang.org/grpc"

	pb "github.com/razeencheng/demo-go/grpc/demo2/helloworld"
)

func main() {
    // 创建一个 gRPC channel 和服务器交互
	conn, err := grpc.Dial("localhost:8080", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Dial failed:%v", err)
	}
	defer conn.Close()

    // 创建客户端
	client := pb.NewHelloWorldServiceClient(conn)
    
    // 直接调用
	resp1, err := client.SayHelloWorld(context.Background(), &pb.HelloWorldRequest{
		Greeting: "Hello Server 1 !!",
		Infos:    map[string]string{"hello": "world"},
	})

	log.Printf("Resp1:%+v", resp1)

	resp2, err := client.SayHelloWorld(context.Background(), &pb.HelloWorldRequest{
		Greeting: "Hello Server 2 !!",
	})

	log.Printf("Resp2:%+v", resp2)
}

客户端的实现比服务端更简洁,三步即可。

  1. 创建一个 gRPC channel 和服务器交互。这里也是可以设置授权认证的;
  2. 创建一个客户端去执行RPC。用到的也是.pb.go内的NewHelloWorldServiceClient方法;
  3. 像函数调用一样去调用RPC服务。

我直接RUN起来,如下,我们可以看到客户端发送到服务的消息以及服务端对不同消息的不同回复。

那么到这里,我们简单的实现了一个gRPC通讯。但很多时候,我们可能希望客户端与服务器能更安全的通信,或者客户端与服务器不再是一种固定的结构的传输,需要流式的去处理一些问题等等。针对这些问题,在下一篇博客中,我将结合实例详细说明。

文中完整代码在这里