पिछले लेख में, मैंने नेट/आरपीसी पैकेज का उपयोग करके एक सरल आरपीसी इंटरफ़ेस लागू किया और गोलंग की कुछ मूल बातें सीखने के लिए नेट/आरपीसी और जेएसओएन एन्कोडिंग के साथ आने वाले गोब एन्कोडिंग को आज़माया। आरपीसी. इस पोस्ट में, मैं नेट/आरपीसी को प्रोटोबफ के साथ जोड़ूंगा और कोड उत्पन्न करने में हमारी सहायता के लिए अपना प्रोटोबफ प्लगइन बनाऊंगा, तो चलिए शुरू करते हैं।
यह लेख पहली बार मीडियम एमपीपी योजना में प्रकाशित हुआ था। यदि आप मीडियम उपयोगकर्ता हैं, तो कृपया मुझे मीडियम पर फ़ॉलो करें। आपका बहुत-बहुत धन्यवाद।
हमने अपने काम के दौरान जीआरपीसी और प्रोटोबफ़ का उपयोग किया होगा, लेकिन वे बाध्य नहीं हैं। GRPC को JSON का उपयोग करके एन्कोड किया जा सकता है, और प्रोटोबफ़ को अन्य भाषाओं में लागू किया जा सकता है।
प्रोटोकॉल बफ़र्स (Protobuf) एक मुफ़्त और ओपन-सोर्स क्रॉस-प्लेटफ़ॉर्म डेटा प्रारूप है जिसका उपयोग संरचित डेटा को क्रमबद्ध करने के लिए किया जाता है। यह ऐसे प्रोग्राम विकसित करने में उपयोगी है जो नेटवर्क पर एक दूसरे के साथ संचार करते हैं या डेटा संग्रहीत करते हैं। विधि में एक इंटरफ़ेस विवरण भाषा शामिल होती है जो कुछ डेटा की संरचना का वर्णन करती है और एक प्रोग्राम जो संरचित डेटा का प्रतिनिधित्व करने वाले बाइट्स की एक स्ट्रीम उत्पन्न करने या पार्स करने के लिए उस विवरण से स्रोत कोड उत्पन्न करता है।
सबसे पहले हम एक प्रोटो फ़ाइल hello-service.proto लिखते हैं जो एक संदेश "स्ट्रिंग" को परिभाषित करता है
syntax = "proto3"; package api; option go_package="api"; message String { string value = 1; }
फिर संदेश स्ट्रिंग के लिए गो कोड उत्पन्न करने के लिए प्रोटोक उपयोगिता का उपयोग करें
protoc --go_out=. hello-service.proto
फिर हम प्रोटोबफ़ फ़ाइल द्वारा उत्पन्न स्ट्रिंग का उपयोग करने के लिए हैलो फ़ंक्शन के तर्कों को संशोधित करते हैं।
type HelloServiceInterface = interface { Hello(request api.String, reply *api.String) error }
इसका उपयोग करना पहले से अलग नहीं है, यहां तक कि, यह सीधे स्ट्रिंग का उपयोग करने जितना सुविधाजनक नहीं है। तो हमें प्रोटोबफ़ का उपयोग क्यों करना चाहिए? जैसा कि मैंने पहले कहा था, भाषा-स्वतंत्र आरपीसी सेवा इंटरफेस और संदेशों को परिभाषित करने के लिए प्रोटोबफ का उपयोग करना, और फिर विभिन्न भाषाओं में कोड उत्पन्न करने के लिए प्रोटोक टूल का उपयोग करना, जहां इसका वास्तविक मूल्य निहित है । उदाहरण के लिए, gRPC कोड जनरेट करने के लिए आधिकारिक प्लगइन protoc-gen-go का उपयोग करें।
protoc --go_out=plugins=grpc. hello-service.proto
प्रोटोबफ़ फ़ाइलों से कोड उत्पन्न करने के लिए, हमें प्रोटोक स्थापित करना होगा, लेकिन प्रोटोक को यह नहीं पता है कि हमारी लक्ष्य भाषा क्या है, इसलिए हमें कोड उत्पन्न करने में सहायता के लिए प्लगइन्स की आवश्यकता है। प्रोटोक का प्लगइन सिस्टम कैसे काम करता है? उदाहरण के तौर पर उपरोक्त जीआरपीसी को लें।
यहां एक --go_out पैरामीटर है। चूँकि जिस प्लगइन को हम कॉल कर रहे हैं वह protoc-gen-go है, पैरामीटर को go_out कहा जाता है; यदि नाम XXX था, तो पैरामीटर को XXX_out कहा जाएगा।
जब प्रोटोक चल रहा होता है, तो यह पहले प्रोटोबफ़ फ़ाइल को पार्स करेगा और प्रोटोकॉल बफ़र्स-एन्कोडेड वर्णनात्मक डेटा का एक सेट उत्पन्न करेगा। यह पहले यह निर्धारित करेगा कि गो प्लगइन प्रोटोक में शामिल है या नहीं, और फिर यह $PATH में प्रोटोक-जेन-गो को खोजने का प्रयास करेगा, और यदि यह इसे नहीं ढूंढ पाता है, तो यह एक त्रुटि की रिपोर्ट करेगा, और फिर यह प्रोटोक-जेन-गो चलाएगा। protoc-gen-go कमांड और विवरण डेटा को stdin के माध्यम से प्लगइन कमांड पर भेजता है। प्लगइन फ़ाइल सामग्री उत्पन्न करने के बाद, यह विशिष्ट फ़ाइल उत्पन्न करने के लिए प्रोटोक को बताने के लिए प्रोटोकॉल बफ़र्स एन्कोडेड डेटा को स्टडआउट में इनपुट करता है।
प्लगइन्स = जीआरपीसी एक प्लगइन है जो इसे लागू करने के लिए प्रोटोक-जेन-गो के साथ आता है। यदि आप इसका उपयोग नहीं करते हैं, तो यह केवल गो में एक संदेश उत्पन्न करेगा, लेकिन आप जीआरपीसी-संबंधित कोड उत्पन्न करने के लिए इस प्लगइन का उपयोग कर सकते हैं।
यदि हम प्रोटोबफ़ में हैलो इंटरफ़ेस टाइमिंग जोड़ते हैं, तो क्या हम सीधे कोड उत्पन्न करने के लिए एक प्रोटोक प्लगइन को अनुकूलित कर सकते हैं?
syntax = "proto3"; package api; option go_package="./api"; service HelloService { rpc Hello (String) returns (String) {} } message String { string value = 1; }
इस लेख के लिए, मेरा लक्ष्य एक प्लगइन बनाना था जिसका उपयोग आरपीसी सर्वर-साइड और क्लाइंट-साइड कोड उत्पन्न करने के लिए किया जाएगा जो कुछ इस तरह दिखेगा।
// HelloService_rpc.pb.go type HelloServiceInterface interface { Hello(String, *String) error } func RegisterHelloService( srv *rpc.Server, x HelloServiceInterface, ) error { if err := srv.RegisterName("HelloService", x); err != nil { return err } return nil } type HelloServiceClient struct { *rpc.Client } var _ HelloServiceInterface = (*HelloServiceClient)(nil) func DialHelloService(network, address string) ( *HelloServiceClient, error, ) { c, err := rpc.Dial(network, address) if err != nil { return nil, err } return &HelloServiceClient{Client: c}, nil } func (p *HelloServiceClient) Hello( in String, out *String, ) error { return p.Client.Call("HelloService.Hello", in, out) }
इससे हमारा व्यवसाय कोड इस प्रकार बदल जाएगा
// service func main() { listener, err := net.Listen("tcp", ":1234") if err != nil { log.Fatal("ListenTCP error:", err) } _ = api.RegisterHelloService(rpc.DefaultServer, new(HelloService)) for { conn, err := listener.Accept() if err != nil { log.Fatal("Accept error:", err) } go rpc.ServeConn(conn) } } type HelloService struct{} func (p *HelloService) Hello(request api.String, reply *api.String) error { log.Println("HelloService.proto Hello") *reply = api.String{Value: "Hello:" request.Value} return nil } // client.go func main() { client, err := api.DialHelloService("tcp", "localhost:1234") if err != nil { log.Fatal("net.Dial:", err) } reply := &api.String{} err = client.Hello(api.String{Value: "Hello"}, reply) if err != nil { log.Fatal(err) } log.Println(reply) }
जनरेट किए गए कोड के आधार पर, हमारा कार्यभार पहले से ही बहुत कम है और त्रुटि की संभावना पहले से ही बहुत कम है। का शुभारंभ।
उपरोक्त एपीआई कोड के आधार पर, हम एक टेम्पलेट फ़ाइल निकाल सकते हैं:
const tmplService = ` import ( "net/rpc") type {{.ServiceName}}Interface interface { func Register{{.ServiceName}}( if err := srv.RegisterName("{{.ServiceName}}", x); err != nil { return err } return nil} *rpc.Client} func Dial{{.ServiceName}}(network, address string) ( {{range $_, $m := .MethodList}} return p.Client.Call("{{$root.ServiceName}}.{{$m.MethodName}}", in, out)} `
पूरा टेम्प्लेट स्पष्ट है, और इसमें कुछ प्लेसहोल्डर हैं, जैसे मेथडनेम, सर्विसनेम, आदि, जिन्हें हम बाद में कवर करेंगे।
Google ने गो भाषा एपीआई 1 जारी किया, जो एक नया पैकेज google.golang.org/protobuf/compile R/protogen पेश करता है, जो प्लगइन्स विकास की कठिनाई को काफी कम कर देता है:
प्रत्येक सेवा के लिए सबसे महत्वपूर्ण बात सेवा का नाम है, और फिर प्रत्येक सेवा में तरीकों का एक सेट होता है। सेवा द्वारा परिभाषित विधि के लिए, सबसे महत्वपूर्ण बात विधि का नाम, साथ ही इनपुट पैरामीटर का नाम और आउटपुट पैरामीटर प्रकार है। आइए सबसे पहले सेवा की मेटा जानकारी का वर्णन करने के लिए एक सर्विसडेटा को परिभाषित करें:
// ServiceData type ServiceData struct { PackageName string ServiceName string MethodList []Method } // Method type Method struct { MethodName string InputTypeName string OutputTypeName string }
फिर मुख्य तर्क, और कोड जनरेशन तर्क, और अंत में कोड उत्पन्न करने के लिए tmpl को कॉल आता है।
func main() { protogen.Options{}.Run(func(gen *protogen.Plugin) error { for _, file := range gen.Files { if !file.Generate { continue } generateFile(gen, file) } return nil }) } // generateFile function definition func generateFile(gen *protogen.Plugin, file *protogen.File) { filename := file.GeneratedFilenamePrefix "_rpc.pb.go" g := gen.NewGeneratedFile(filename, file.GoImportPath) tmpl, err := template.New("service").Parse(tmplService) if err != nil { log.Fatalf("Error parsing template: %v", err) } packageName := string(file.GoPackageName) // Iterate over each service to generate code for _, service := range file.Services { serviceData := ServiceData{ ServiceName: service.GoName, PackageName: packageName, } for _, method := range service.Methods { inputType := method.Input.GoIdent.GoName outputType := method.Output.GoIdent.GoName serviceData.MethodList = append(serviceData.MethodList, Method{ MethodName: method.GoName, InputTypeName: inputType, OutputTypeName: outputType, }) } // Perform template rendering err = tmpl.Execute(g, serviceData) if err != nil { log.Fatalf("Error executing template: %v", err) } } }
अंत में, हम संकलित बाइनरी निष्पादन फ़ाइल protoc-gen-go-spprpc को $PATH में डालते हैं, और फिर जो कोड हम चाहते हैं उसे उत्पन्न करने के लिए protoc चलाते हैं।
protoc --go_out=.. --go-spprpc_out=.. HelloService.proto
क्योंकि protoc-gen-go-spprpc को चलाने के लिए protoc पर निर्भर रहना पड़ता है, इसलिए इसे डीबग करना थोड़ा मुश्किल है। हम इसका उपयोग कर सकते हैं
fmt.Fprintf(os.Stderr, "Fprintln: %v\n", err)
डीबग करने के लिए त्रुटि लॉग को प्रिंट करने के लिए।
इस लेख में बस इतना ही है। हमने पहले प्रोटोबफ का उपयोग करके एक आरपीसी कॉल लागू की और फिर कोड उत्पन्न करने में हमारी सहायता के लिए एक प्रोटोबफ प्लगइन बनाया। यह हमारे लिए प्रोटोबफ़ आरपीसी सीखने का द्वार खोलता है, और जीआरपीसी की संपूर्ण समझ के लिए हमारा मार्ग है। मुझे उम्मीद है कि हर कोई इस तकनीक में महारत हासिल कर सकता है।
अस्वीकरण: उपलब्ध कराए गए सभी संसाधन आंशिक रूप से इंटरनेट से हैं। यदि आपके कॉपीराइट या अन्य अधिकारों और हितों का कोई उल्लंघन होता है, तो कृपया विस्तृत कारण बताएं और कॉपीराइट या अधिकारों और हितों का प्रमाण प्रदान करें और फिर इसे ईमेल पर भेजें: [email protected] हम इसे आपके लिए यथाशीघ्र संभालेंगे।
Copyright© 2022 湘ICP备2022001581号-3