golang下grpc的实践

Posted linux硬核玩家

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang下grpc的实践相关的知识,希望对你有一定的参考价值。

golang下grpc的实践

1.什么是grpc?

gRPC 是 google 开发的一款语言中立、平台中立、开源的远程过程调用(RPC)系统。既然是rpc系统,客户端就可以像调用本地对象一样直接调用远程机器上的服务端应用。通过这种方式,使得用户可以轻松的创建分布式的应用和服务。

gprc的优势在于对语言的要求不是很高(java、golang、python等),例如可以使用java编写服务端,然后用golang或者python编写服务端进行调用。其中最关键的媒介就是 protocol buffers。

Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

2.grpc在golang中的实践

本文将会介绍gprc在golang中的实践,如何去构建proto文件,以及书写相关的客户端与服务端的程序,以及测试下对相关类型的数据进行crud操作。通过本示例可以初步了解grpc的使用。

项目的目录结构如下所示:

 
   
   
 
  1. ├── Dockerfile

  2. ├── Gopkg.lock

  3. ├── Gopkg.toml

  4. ├── client

  5.    └── main.go

  6. ├── protobuf

  7.    ├── student.pb.go

  8.    └── student.proto

  9. ├── server

  10.    └── main.go

  11. └── vendor

  12. ├── github.com

  13. ├── golang.org

  14. └── google.golang.org

注意:

  • 1.protobuf是关键目录,其中的 student.proto定义了中间连接信息。包括相关结构体的定义,以及远程过程调用的参数以及返回值。 student.pb.go是protoc根据student.proto文件生成的golang可以调用的文件;

  • 2. clientserver目录中分别定义了客户端与服务端进行测试;

  • 3.vendor目录,Gopkg.lock和Gopkg.toml文件与go的包管理工具dep相关。

1..proto文件的编写

proto文件定义了一个 通信标准。student.proto信息如下所示:

 
   
   
 
  1. syntax = "proto3";

  2. package student;

  3. service Student {

  4. rpc GetStudents(StudentFilter) returns (stream StudentRequest) {}

  5. rpc CreateStudent(StudentRequest) returns (StudentResponse) {}

  6. rpc DeleteStudent(StudentRemove) returns (StudentResponse) {}

  7. }

  8. message StudentRequest {

  9. int32 id = 1;

  10. string name = 2;

  11. string email = 3;

  12. string phone= 4;

  13. message Subject {

  14. string name = 1;

  15. int32 score = 2;

  16. string level = 3;

  17. bool isUpToGrade = 4;

  18. }

  19. repeated Subject subjects = 5;

  20. }

  21. message StudentResponse {

  22. int32 id = 1;

  23. bool success = 2;

  24. }

  25. message StudentFilter {

  26. string keyword = 1;

  27. }

  28. message StudentRemove {

  29. string keyword = 1;

  30. }

注意:

  • 1. syntax="proto3";声明了protocol buffer的使用版本是proto3,之前还有proto2;

  • 2. package指定了包名称;

  • 3. service声明了客户端,服务端相关函数调用的参数结构和返回值。

  • 4. message定义了相关结构体,可以进行嵌套;

    关于proto的更多语法信息可以参考该博客.

接下来我们需要将该proto文件翻译成golang可以使用的go文件,这里使用 protoc命令:

 
   
   
 
  1. protoc -I protobuf protobuf/student.proto --go_out=plugins=grpc:./protobuf/

得到 student.pb.go文件,该文件的信息如下所示:

 
   
   
 
  1. // Code generated by protoc-gen-go. DO NOT EDIT.

  2. // source: student.proto

  3. package student

  4. import (

  5. context "context"

  6. fmt "fmt"

  7. proto "github.com/golang/protobuf/proto"

  8. grpc "google.golang.org/grpc"

  9. math "math"

  10. )

  11. // Reference imports to suppress errors if they are not otherwise used.

  12. var _ = proto.Marshal

  13. var _ = fmt.Errorf

  14. var _ = math.Inf

  15. // This is a compile-time assertion to ensure that this generated file

  16. // is compatible with the proto package it is being compiled against.

  17. // A compilation error at this line likely means your copy of the

  18. // proto package needs to be updated.

  19. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package

  20. type StudentRequest struct {

  21. Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`

  22. Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`

  23. Phone string `protobuf:"bytes,4,opt,name=phone,proto3" json:"phone,omitempty"`

  24. Subjects []*StudentRequest_Subject `protobuf:"bytes,5,rep,name=subjects,proto3" json:"subjects,omitempty"`

  25. XXX_NoUnkeyedLiteral struct{} `json:"-"`

  26. XXX_unrecognized []byte `json:"-"`

  27. XXX_sizecache int32 `json:"-"`

  28. }

  29. func (m *StudentRequest) Reset() { *m = StudentRequest{} }

  30. func (m *StudentRequest) String() string { return proto.CompactTextString(m) }

  31. func (*StudentRequest) ProtoMessage() {}

  32. func (*StudentRequest) Descriptor() ([]byte, []int) {

  33. return fileDescriptor_94a1c1b032ad0c00, []int{0}

  34. }

  35. func (m *StudentRequest) XXX_Unmarshal(b []byte) error {

  36. return xxx_messageInfo_StudentRequest.Unmarshal(m, b)

  37. }

  38. func (m *StudentRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {

  39. return xxx_messageInfo_StudentRequest.Marshal(b, m, deterministic)

  40. }

  41. func (m *StudentRequest) XXX_Merge(src proto.Message) {

  42. xxx_messageInfo_StudentRequest.Merge(m, src)

  43. }

  44. func (m *StudentRequest) XXX_Size() int {

  45. return xxx_messageInfo_StudentRequest.Size(m)

  46. }

  47. func (m *StudentRequest) XXX_DiscardUnknown() {

  48. xxx_messageInfo_StudentRequest.DiscardUnknown(m)

  49. }

  50. var xxx_messageInfo_StudentRequest proto.InternalMessageInfo

  51. func (m *StudentRequest) GetId() int32 {

  52. if m != nil {

  53. return m.Id

  54. }

  55. return 0

  56. }

  57. func (m *StudentRequest) GetName() string {

  58. if m != nil {

  59. return m.Name

  60. }

  61. return ""

  62. }

  63. if m != nil {

  64. }

  65. return ""

  66. }

  67. func (m *StudentRequest) GetPhone() string {

  68. if m != nil {

  69. return m.Phone

  70. }

  71. return ""

  72. }

  73. func (m *StudentRequest) GetSubjects() []*StudentRequest_Subject {

  74. if m != nil {

  75. return m.Subjects

  76. }

  77. return nil

  78. }

  79. type StudentRequest_Subject struct {

  80. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`

  81. Score int32 `protobuf:"varint,2,opt,name=score,proto3" json:"score,omitempty"`

  82. Level string `protobuf:"bytes,3,opt,name=level,proto3" json:"level,omitempty"`

  83. IsUpToGrade bool `protobuf:"varint,4,opt,name=isUpToGrade,proto3" json:"isUpToGrade,omitempty"`

  84. XXX_NoUnkeyedLiteral struct{} `json:"-"`

  85. XXX_unrecognized []byte `json:"-"`

  86. XXX_sizecache int32 `json:"-"`

  87. }

  88. func (m *StudentRequest_Subject) Reset() { *m = StudentRequest_Subject{} }

  89. func (m *StudentRequest_Subject) String() string { return proto.CompactTextString(m) }

  90. func (*StudentRequest_Subject) ProtoMessage() {}

  91. func (*StudentRequest_Subject) Descriptor() ([]byte, []int) {

  92. return fileDescriptor_94a1c1b032ad0c00, []int{0, 0}

  93. }

  94. func (m *StudentRequest_Subject) XXX_Unmarshal(b []byte) error {

  95. return xxx_messageInfo_StudentRequest_Subject.Unmarshal(m, b)

  96. }

  97. func (m *StudentRequest_Subject) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {

  98. return xxx_messageInfo_StudentRequest_Subject.Marshal(b, m, deterministic)

  99. }

  100. func (m *StudentRequest_Subject) XXX_Merge(src proto.Message) {

  101. xxx_messageInfo_StudentRequest_Subject.Merge(m, src)

  102. }

  103. func (m *StudentRequest_Subject) XXX_Size() int {

  104. return xxx_messageInfo_StudentRequest_Subject.Size(m)

  105. }

  106. func (m *StudentRequest_Subject) XXX_DiscardUnknown() {

  107. xxx_messageInfo_StudentRequest_Subject.DiscardUnknown(m)

  108. }

  109. var xxx_messageInfo_StudentRequest_Subject proto.InternalMessageInfo

  110. func (m *StudentRequest_Subject) GetName() string {

  111. if m != nil {

  112. return m.Name

  113. }

  114. return ""

  115. }

  116. func (m *StudentRequest_Subject) GetScore() int32 {

  117. if m != nil {

  118. return m.Score

  119. }

  120. return 0

  121. }

  122. func (m *StudentRequest_Subject) GetLevel() string {

  123. if m != nil {

  124. return m.Level

  125. }

  126. return ""

  127. }

  128. func (m *StudentRequest_Subject) GetIsUpToGrade() bool {

  129. if m != nil {

  130. return m.IsUpToGrade

  131. }

  132. return false

  133. }

  134. type StudentResponse struct {

  135. Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`

  136. Success bool `protobuf:"varint,2,opt,name=success,proto3" json:"success,omitempty"`

  137. XXX_NoUnkeyedLiteral struct{} `json:"-"`

  138. XXX_unrecognized []byte `json:"-"`

  139. XXX_sizecache int32 `json:"-"`

  140. }

  141. func (m *StudentResponse) Reset() { *m = StudentResponse{} }

  142. func (m *StudentResponse) String() string { return proto.CompactTextString(m) }

  143. func (*StudentResponse) ProtoMessage() {}

  144. func (*StudentResponse) Descriptor() ([]byte, []int) {

  145. return fileDescriptor_94a1c1b032ad0c00, []int{1}

  146. }

  147. func (m *StudentResponse) XXX_Unmarshal(b []byte) error {

  148. return xxx_messageInfo_StudentResponse.Unmarshal(m, b)

  149. }

  150. func (m *StudentResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {

  151. return xxx_messageInfo_StudentResponse.Marshal(b, m, deterministic)

  152. }

  153. func (m *StudentResponse) XXX_Merge(src proto.Message) {

  154. xxx_messageInfo_StudentResponse.Merge(m, src)

  155. }

  156. func (m *StudentResponse) XXX_Size() int {

  157. return xxx_messageInfo_StudentResponse.Size(m)

  158. }

  159. func (m *StudentResponse) XXX_DiscardUnknown() {

  160. xxx_messageInfo_StudentResponse.DiscardUnknown(m)

  161. }

  162. var xxx_messageInfo_StudentResponse proto.InternalMessageInfo

  163. func (m *StudentResponse) GetId() int32 {

  164. if m != nil {

  165. return m.Id

  166. }

  167. return 0

  168. }

  169. func (m *StudentResponse) GetSuccess() bool {

  170. if m != nil {

  171. return m.Success

  172. }

  173. return false

  174. }

  175. type StudentFilter struct {

  176. Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword,omitempty"`

  177. XXX_NoUnkeyedLiteral struct{} `json:"-"`

  178. XXX_unrecognized []byte `json:"-"`

  179. XXX_sizecache int32 `json:"-"`

  180. }

  181. func (m *StudentFilter) Reset() { *m = StudentFilter{} }

  182. func (m *StudentFilter) String() string { return proto.CompactTextString(m) }

  183. func (*StudentFilter) ProtoMessage() {}

  184. func (*StudentFilter) Descriptor() ([]byte, []int) {

  185. return fileDescriptor_94a1c1b032ad0c00, []int{2}

  186. }

  187. func (m *StudentFilter) XXX_Unmarshal(b []byte) error {

  188. return xxx_messageInfo_StudentFilter.Unmarshal(m, b)

  189. }

  190. func (m *StudentFilter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {

  191. return xxx_messageInfo_StudentFilter.Marshal(b, m, deterministic)

  192. }

  193. func (m *StudentFilter) XXX_Merge(src proto.Message) {

  194. xxx_messageInfo_StudentFilter.Merge(m, src)

  195. }

  196. func (m *StudentFilter) XXX_Size() int {

  197. return xxx_messageInfo_StudentFilter.Size(m)

  198. }

  199. func (m *StudentFilter) XXX_DiscardUnknown() {

  200. xxx_messageInfo_StudentFilter.DiscardUnknown(m)

  201. }

  202. var xxx_messageInfo_StudentFilter proto.InternalMessageInfo

  203. func (m *StudentFilter) GetKeyword() string {

  204. if m != nil {

  205. return m.Keyword

  206. }

  207. return ""

  208. }

  209. type StudentRemove struct {

  210. Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword,omitempty"`

  211. XXX_NoUnkeyedLiteral struct{} `json:"-"`

  212. XXX_unrecognized []byte `json:"-"`

  213. XXX_sizecache int32 `json:"-"`

  214. }

  215. func (m *StudentRemove) Reset() { *m = StudentRemove{} }

  216. func (m *StudentRemove) String() string { return proto.CompactTextString(m) }

  217. func (*StudentRemove) ProtoMessage() {}

  218. func (*StudentRemove) Descriptor() ([]byte, []int) {

  219. return fileDescriptor_94a1c1b032ad0c00, []int{3}

  220. }

  221. func (m *StudentRemove) XXX_Unmarshal(b []byte) error {

  222. return xxx_messageInfo_StudentRemove.Unmarshal(m, b)

  223. }

  224. func (m *StudentRemove) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {

  225. return xxx_messageInfo_StudentRemove.Marshal(b, m, deterministic)

  226. }

  227. func (m *StudentRemove) XXX_Merge(src proto.Message) {

  228. xxx_messageInfo_StudentRemove.Merge(m, src)

  229. }

  230. func (m *StudentRemove) XXX_Size() int {

  231. return xxx_messageInfo_StudentRemove.Size(m)

  232. }

  233. func (m *StudentRemove) XXX_DiscardUnknown() {

  234. xxx_messageInfo_StudentRemove.DiscardUnknown(m)

  235. }

  236. var xxx_messageInfo_StudentRemove proto.InternalMessageInfo

  237. func (m *StudentRemove) GetKeyword() string {

  238. if m != nil {

  239. return m.Keyword

  240. }

  241. return ""

  242. }

  243. func init() {

  244. proto.RegisterType((*StudentRequest)(nil), "student.StudentRequest")

  245. proto.RegisterType((*StudentRequest_Subject)(nil), "student.StudentRequest.Subject")

  246. proto.RegisterType((*StudentResponse)(nil), "student.StudentResponse")

  247. proto.RegisterType((*StudentFilter)(nil), "student.StudentFilter")

  248. proto.RegisterType((*StudentRemove)(nil), "student.StudentRemove")

  249. }

  250. func init() { proto.RegisterFile("student.proto", fileDescriptor_94a1c1b032ad0c00) }

  251. var fileDescriptor_94a1c1b032ad0c00 = []byte{

  252. // 325 bytes of a gzipped FileDescriptorProto

  253. 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0xc1, 0x4e, 0xc2, 0x40,

  254. 0x10, 0x86, 0x69, 0xa1, 0x16, 0x87, 0x14, 0x93, 0x8d, 0xc1, 0x0d, 0x17, 0x9b, 0x9e, 0xf0, 0x42,

  255. 0x0c, 0x1e, 0xb9, 0x09, 0x91, 0xfb, 0xa2, 0x0f, 0x50, 0xda, 0x49, 0xac, 0x94, 0x6e, 0xed, 0x6c,

  256. 0x31, 0xbe, 0x82, 0x4f, 0xe8, 0xe3, 0x98, 0x76, 0xb7, 0x15, 0x24, 0x78, 0xdb, 0xff, 0xef, 0xbf,

  257. 0x33, 0x5f, 0xff, 0x2c, 0x78, 0xa4, 0xca, 0x18, 0x33, 0x35, 0xcd, 0x0b, 0xa9, 0x24, 0x73, 0x8d,

  258. 0x0c, 0xbe, 0x6c, 0x18, 0xae, 0xf5, 0x59, 0xe0, 0x7b, 0x89, 0xa4, 0xd8, 0x10, 0xec, 0x24, 0xe6,

  259. 0x96, 0x6f, 0x4d, 0x1c, 0x61, 0x27, 0x31, 0x63, 0xd0, 0xcb, 0xc2, 0x1d, 0x72, 0xdb, 0xb7, 0x26,

  260. 0x97, 0xa2, 0x3e, 0xb3, 0x6b, 0x70, 0x70, 0x17, 0x26, 0x29, 0xef, 0xd6, 0xa6, 0x16, 0x95, 0x9b,

  261. 0xbf, 0xca, 0x0c, 0x79, 0x4f, 0xbb, 0xb5, 0x60, 0x73, 0xe8, 0x53, 0xb9, 0x79, 0xc3, 0x48, 0x11,

  262. 0x77, 0xfc, 0xee, 0x64, 0x30, 0xbb, 0x9d, 0x36, 0x34, 0xc7, 0xab, 0xa7, 0x6b, 0x9d, 0x13, 0xed,

  263. 0x85, 0xf1, 0x16, 0x5c, 0x63, 0xb6, 0x1c, 0xd6, 0x31, 0x07, 0x45, 0xb2, 0xd0, 0x70, 0x8e, 0xd0,

  264. 0xa2, 0x72, 0x53, 0xdc, 0x63, 0x4b, 0x57, 0x0b, 0xe6, 0xc3, 0x20, 0xa1, 0x97, 0xfc, 0x59, 0xae,

  265. 0x8a, 0x30, 0xd6, 0x8c, 0x7d, 0x71, 0x68, 0x05, 0x73, 0xb8, 0x6a, 0x81, 0x28, 0x97, 0x19, 0xe1,

  266. 0x49, 0x19, 0x1c, 0x5c, 0x2a, 0xa3, 0x08, 0x89, 0xea, 0x95, 0x7d, 0xd1, 0xc8, 0xe0, 0x0e, 0x3c,

  267. 0x73, 0xf9, 0x29, 0x49, 0x15, 0x16, 0x55, 0x74, 0x8b, 0x9f, 0x1f, 0xb2, 0x88, 0x0d, 0x72, 0x23,

  268. 0x0f, 0xa2, 0x02, 0x77, 0x72, 0x8f, 0xe7, 0xa3, 0xb3, 0x6f, 0x0b, 0x5c, 0x93, 0x65, 0x8f, 0x30,

  269. 0x58, 0xa1, 0x32, 0x8a, 0xd8, 0xe8, 0x6f, 0x8b, 0x7a, 0xef, 0xf8, 0xe6, 0x4c, 0xbb, 0x41, 0xe7,

  270. 0xde, 0x62, 0x4b, 0xf0, 0x16, 0x05, 0x86, 0x0a, 0x9b, 0xa1, 0xe7, 0xd2, 0x63, 0x7e, 0xfa, 0x41,

  271. 0x77, 0x12, 0x74, 0xd8, 0x02, 0xbc, 0x25, 0xa6, 0xf8, 0x3b, 0x65, 0x74, 0x1a, 0xae, 0x7e, 0xec,

  272. 0xbf, 0x21, 0x9b, 0x8b, 0xfa, 0x29, 0x3e, 0xfc, 0x04, 0x00, 0x00, 0xff, 0xff, 0x6b, 0xfd, 0x32,

  273. 0xdc, 0x9b, 0x02, 0x00, 0x00,

  274. }

  275. // Reference imports to suppress errors if they are not otherwise used.

  276. var _ context.Context

  277. var _ grpc.ClientConn

  278. // This is a compile-time assertion to ensure that this generated file

  279. // is compatible with the grpc package it is being compiled against.

  280. const _ = grpc.SupportPackageIsVersion4

  281. // StudentClient is the client API for Student service.

  282. //

  283. // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.

  284. type StudentClient interface {

  285. GetStudents(ctx context.Context, in *StudentFilter, opts ...grpc.CallOption) (Student_GetStudentsClient, error)

  286. CreateStudent(ctx context.Context, in *StudentRequest, opts ...grpc.CallOption) (*StudentResponse, error)

  287. DeleteStudent(ctx context.Context, in *StudentRemove, opts ...grpc.CallOption) (*StudentResponse, error)

  288. }

  289. type studentClient struct {

  290. cc *grpc.ClientConn

  291. }

  292. func NewStudentClient(cc *grpc.ClientConn) StudentClient {

  293. return &studentClient{cc}

  294. }

  295. func (c *studentClient) GetStudents(ctx context.Context, in *StudentFilter, opts ...grpc.CallOption) (Student_GetStudentsClient, error) {

  296. stream, err := c.cc.NewStream(ctx, &_Student_serviceDesc.Streams[0], "/student.Student/GetStudents", opts...)

  297. if err != nil {

  298. return nil, err

  299. }

  300. x := &studentGetStudentsClient{stream}

  301. if err := x.ClientStream.SendMsg(in); err != nil {

  302. return nil, err

  303. }

  304. if err := x.ClientStream.CloseSend(); err != nil {

  305. return nil, err

  306. }

  307. return x, nil

  308. }

  309. type Student_GetStudentsClient interface {

  310. Recv() (*StudentRequest, error)

  311. grpc.ClientStream

  312. }

  313. type studentGetStudentsClient struct {

  314. grpc.ClientStream

  315. }

  316. func (x *studentGetStudentsClient) Recv() (*StudentRequest, error) {

  317. m := new(StudentRequest)

  318. if err := x.ClientStream.RecvMsg(m); err != nil {

  319. return nil, err

  320. }

  321. return m, nil

  322. }

  323. func (c *studentClient) CreateStudent(ctx context.Context, in *StudentRequest, opts ...grpc.CallOption) (*StudentResponse, error) {

  324. out := new(StudentResponse)

  325. err := c.cc.Invoke(ctx, "/student.Student/CreateStudent", in, out, opts...)

  326. if err != nil {

  327. return nil, err

  328. }

  329. return out, nil

  330. }

  331. func (c *studentClient) DeleteStudent(ctx context.Context, in *StudentRemove, opts ...grpc.CallOption) (*StudentResponse, error) {

  332. out := new(StudentResponse)

  333. err := c.cc.Invoke(ctx, "/student.Student/DeleteStudent", in, out, opts...)

  334. if err != nil {

  335. return nil, err

  336. }

  337. return out, nil

  338. }

  339. // StudentServer is the server API for Student service.

  340. type StudentServer interface {

  341. GetStudents(*StudentFilter, Student_GetStudentsServer) error

  342. CreateStudent(context.Context, *StudentRequest) (*StudentResponse, error)

  343. DeleteStudent(context.Context, *StudentRemove) (*StudentResponse, error)

  344. }

  345. func RegisterStudentServer(s *grpc.Server, srv StudentServer) {

  346. s.RegisterService(&_Student_serviceDesc, srv)

  347. }

  348. func _Student_GetStudents_Handler(srv interface{}, stream grpc.ServerStream) error {

  349. m := new(StudentFilter)

  350. if err := stream.RecvMsg(m); err != nil {

  351. return err

  352. }

  353. return srv.(StudentServer).GetStudents(m, &studentGetStudentsServer{stream})

  354. }

  355. type Student_GetStudentsServer interface {

  356. Send(*StudentRequest) error

  357. grpc.ServerStream

  358. }

  359. type studentGetStudentsServer struct {

  360. grpc.ServerStream

  361. }

  362. func (x *studentGetStudentsServer) Send(m *StudentRequest) error {

  363. return x.ServerStream.SendMsg(m)

  364. }

  365. func _Student_CreateStudent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {

  366. in := new(StudentRequest)

  367. if err := dec(in); err != nil {

  368. return nil, err

  369. }

  370. if interceptor == nil {

  371. return srv.(StudentServer).CreateStudent(ctx, in)

  372. }

  373. info := &grpc.UnaryServerInfo{

  374. Server: srv,

  375. FullMethod: "/student.Student/CreateStudent",

  376. }

  377. handler := func(ctx context.Context, req interface{}) (interface{}, error) {

  378. return srv.(StudentServer).CreateStudent(ctx, req.(*StudentRequest))

  379. }

  380. return interceptor(ctx, in, info, handler)

  381. }

  382. func _Student_DeleteStudent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {

  383. in := new(StudentRemove)

  384. if err := dec(in); err != nil {

  385. return nil, err

  386. }

  387. if interceptor == nil {

  388. return srv.(StudentServer).DeleteStudent(ctx, in)

  389. }

  390. info := &grpc.UnaryServerInfo{

  391. Server: srv,

  392. FullMethod: "/student.Student/DeleteStudent",

  393. }

  394. handler := func(ctx context.Context, req interface{}) (interface{}, error) {

  395. return srv.(StudentServer).DeleteStudent(ctx, req.(*StudentRemove))

  396. }

  397. return interceptor(ctx, in, info, handler)

  398. }

  399. var _Student_serviceDesc = grpc.ServiceDesc{

  400. ServiceName: "student.Student",

  401. HandlerType: (*StudentServer)(nil),

  402. Methods: []grpc.MethodDesc{

  403. {

  404. MethodName: "CreateStudent",

  405. Handler: _Student_CreateStudent_Handler,

  406. },

  407. {

  408. MethodName: "DeleteStudent",

  409. Handler: _Student_DeleteStudent_Handler,

  410. },

  411. },

  412. Streams: []grpc.StreamDesc{

  413. {

  414. StreamName: "GetStudents",

  415. Handler: _Student_GetStudents_Handler,

  416. ServerStreams: true,

  417. },

  418. },

  419. Metadata: "student.proto",

  420. }

如果想要对proto的信息进行调整,一定要修改.proto文件信息,然后通过protoc工具重新生成,坚决不要直接修改go文件。

2.服务端编写

服务端就是提供上述service中描述的功能:

 
   
   
 
  1. service Student {

  2. rpc GetStudents(StudentFilter) returns (stream StudentRequest) {}

  3. rpc CreateStudent(StudentRequest) returns (StudentResponse) {}

  4. rpc DeleteStudent(StudentRemove) returns (StudentResponse) {}

  5. }

所以在 server/main.go文件中,我们编写了相关功能:

 
   
   
 
  1. package main

  2. import (

  3. "context"

  4. "errors"

  5. "google.golang.org/grpc"

  6. "log"

  7. "net"

  8. pb "orion/go_grpc_proto/protobuf"

  9. "strings"

  10. )

  11. const (

  12. port = "0.0.0.0:50052"

  13. )

  14. type server struct {

  15. studentList []*pb.StudentRequest

  16. }

  17. func (s *server) DeleteStudent(ctx context.Context, filter *pb.StudentRemove) (*pb.StudentResponse, error) {

  18. for idx, student := range s.studentList {

  19. if filter.Keyword != "" {

  20. if filter.Keyword == student.Name {

  21. s.studentList = append(s.studentList[:idx], s.studentList[idx + 1:]...)

  22. return &pb.StudentResponse{Id:student.Id, Success:true}, nil

  23. }

  24. }

  25. }

  26. return &pb.StudentResponse{Id: -1, Success:false}, errors.New("the student is not exist")

  27. }

  28. func (s *server) GetStudents(filter *pb.StudentFilter, stream pb.Student_GetStudentsServer) error {

  29. for _, student := range s.studentList {

  30. if filter.Keyword != "" {

  31. if !strings.Contains(student.Name, filter.Keyword) {

  32. continue

  33. }

  34. }

  35. if err := stream.Send(student); err != nil {

  36. return err

  37. }

  38. }

  39. return nil

  40. }

  41. func (s *server) CreateStudent(ctx context.Context, in *pb.StudentRequest) (*pb.StudentResponse, error) {

  42. s.studentList= append(s.studentList, in)

  43. return &pb.StudentResponse{Id:in.Id, Success:true}, nil

  44. }

  45. func main() {

  46. listen, err := net.Listen("tcp", port)

  47. if err != nil {

  48. log.Fatalf("failed to listen: %v", err)

  49. }

  50. //TODO: Creates a new gRPC server

  51. s := grpc.NewServer()

  52. pb.RegisterStudentServer(s, &server{})

  53. s.Serve(listen)

  54. }

注意:

  • 1.server端开放了相关端供客户端调用,并且把grpc服务和监听器进行了绑定;

3.客户端编写

客户端需要建立和服务端进行通信的grpc会话,然后以student.pb.go中定义的client接口远程调用服务端的接口:

 
   
   
 
  1. type StudentClient interface {

  2. GetStudents(ctx context.Context, in *StudentFilter, opts ...grpc.CallOption) (Student_GetStudentsClient, error)

  3. CreateStudent(ctx context.Context, in *StudentRequest, opts ...grpc.CallOption) (*StudentResponse, error)

  4. DeleteStudent(ctx context.Context, in *StudentRemove, opts ...grpc.CallOption) (*StudentResponse, error)

  5. }

详细的客户端代码如下所示:

 
   
   
 
  1. package main

  2. import (

  3. "context"

  4. "google.golang.org/grpc"

  5. "io"

  6. "log"

  7. pb "orion/go_grpc_proto/protobuf"

  8. )

  9. const (

  10. address = "127.0.0.1:50052"

  11. //address = "grpc-test.ainirobot.com:80"

  12. )

  13. func createStudent(client pb.StudentClient, customer *pb.StudentRequest) {

  14. resp, err := client.CreateStudent(context.Background(), customer)

  15. if err != nil {

  16. log.Fatalf("could not create student: %v", err)

  17. }

  18. if resp.Success {

  19. log.Printf("A new Student has been added with id: %d", resp.Id)

  20. } else {

  21. log.Fatalln("create student error.")

  22. }

  23. }

  24. func getStudents(client pb.StudentClient, filter *pb.StudentFilter) {

  25. stream, err := client.GetStudents(context.Background(), filter)

  26. if err != nil {

  27. log.Fatalf("Error on get students: %v", err)

  28. }

  29. for {

  30. student, err := stream.Recv()

  31. if err == io.EOF {

  32. break

  33. }

  34. if err != nil {

  35. log.Fatalf("%v.GetStudents(_) = _, %v", client, err)

  36. }

  37. log.Printf("Student: %v", student)

  38. }

  39. }

  40. func deleteStudent(client pb.StudentClient, ) {

  41. }

  42. func main() {

  43. conn, err := grpc.Dial(address, grpc.WithInsecure()) // grpc.WithInsecure() 在链接https服务端时不用检查服务端的证书

  44. if err != nil {

  45. log.Fatalf("did not connect: %v", err)

  46. }

  47. defer conn.Close()

  48. //TODO: create a new StudentClient

  49. client := pb.NewStudentClient(conn)

  50. customer := &pb.StudentRequest{

  51. Id: 1,

  52. Name: "zhang chen",

  53. Phone: "13898922311",

  54. Subjects: []*pb.StudentRequest_Subject{

  55. {

  56. Name: "shu xue",

  57. Score: 98,

  58. Level: "high",

  59. IsUpToGrade: true,

  60. },

  61. {

  62. Name: "yu wen",

  63. Score: 60,

  64. Level: "low",

  65. IsUpToGrade: true,

  66. },

  67. },

  68. }

  69. createStudent(client, customer)

  70. customer = &pb.StudentRequest{

  71. Id: 2,

  72. Name: "chen pi",

  73. Phone: "13354123875",

  74. Subjects: []*pb.StudentRequest_Subject{

  75. {

  76. Name: "shu xue",

  77. Score: 70,

  78. Level: "middle",

  79. IsUpToGrade: true,

  80. },

  81. {

  82. Name: "yu wen",

  83. Score: 90,

  84. Level: "high",

  85. IsUpToGrade: true,

  86. },

  87. },

  88. }

  89. createStudent(client, customer)

  90. // TODO:Filter with an empty Keyword

  91. filter := &pb.StudentFilter{Keyword: ""}

  92. getStudents(client, filter)

  93. }

4.功能验证

1.开启服务端等待客户端连接:

 
   
   
 
  1. go run server/main.go

2.开启客户端调用服务端的服务

 
   
   
 
  1. go run client/main.go

  2. 2019/03/11 14:29:08 A new Student has been added with id: 1

  3. 2019/03/11 14:29:08 A new Student has been added with id: 2

  4. 2019/03/11 14:29:08 Student: id:1 name:"zhang chen" email:"zhangchen@qq.com" phone:"13898922311" subjects:<name:"shu xue" score:98 level:"high" isUpToGrade:true > subjects:<name:"yu wen" score:60 level:"low" isUpToGrade:true >

  5. 2019/03/11 14:29:08 Student: id:2 name:"chen pi" email:"chenpi@qq.com" phone:"13354123875" subjects:<name:"shu xue" score:70 level:"middle" isUpToGrade:true > subjects:<name:"yu wen" score:90 level:"high" isUpToGrade:true >

  • 创建了两个student的信息,然后获取了所有的student信息。

小结

本篇文章介绍了grpc在golang中的实践,但是grpc本身是可以跨多个语言进行通信的,在后续的章节中引入python和golang的程序通过grpc进行通信。除此之外,还推荐大家学习另外一个golang下的rpc框架:rpcx.


以上是关于golang下grpc的实践的主要内容,如果未能解决你的问题,请参考以下文章

gRPC之GoLang入门HelloWord(排版整理)

gRPC最佳入门教程,Golang/Python/PHP多语言讲解

快速构建一个Golang下通用的GRPC服务,拒绝996

如何安装golang的grpc插件

window下golang使用gRPC入门案例

Golang gRPC 示例