当前位置: 首页 > news >正文

网站功能需求列表销售外包

网站功能需求列表,销售外包,做的最好的epub网站,网站开发与维护都有些什么RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务,对应rpc的是本地过程调用,函数调用是最常用的本地过程调用,将本地过程调用变成远程调用会面临着各种问题。 以两数…

RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务,对应rpc的是本地过程调用,函数调用是最常用的本地过程调用,将本地过程调用变成远程调用会面临着各种问题。

以两数相加为例

package mainimport "fmt"func add(a, b int) int {return a + b
}
func main() {fmt.Println(add(1, 2))
}

函数调用过程:
(1)将1和2压入函数的栈中
(2)进入add函数,从栈中取出1和2分别赋值给a和b
(3)执行a+b将结果压栈
(4)将栈中的结果取出打印

远程过程面临的问题
1.原本的本地函数放到另外一个服务器上去运行,但是引入了很多新问题
2.Call的id映射
我们怎么告诉远程机器我们要调用add,而不是sub或者Foo呢?在本地调用中,函数体是直接通过函数指针来指定的,我们调用add,编译器就自动帮我们调用它相应的函数指针。但是在远程调用中,函数指针是不行的,因为两个进程的地址空间是完全不一样的。所以,在RPC中,所有的函数都必须有自己的一个ID。这个ID在所有进程中都是唯一确定的。客户端在做远程过程调用时,必须附上这个ID。然后我们还需要在客户端和服务端分别维护一个(函数<–>Call ID}的对应表。两者的表不一定需要完全相同,但相同的函数对应的Call ID必须相同。当客户端需要进行远程调用时,它就查一下这个表,找出相应的Call ID,然后把它传给服务端,服务端也通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。
3.序列化和反序列化
客户端怎么把参数值传给远程的函数呢?在本地调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。但是在远程过程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。甚至有时候客户端和服务端使用的都不是同一种语言(比如服务端用C++,客户端用Java或者Python)。这时候就需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。这个过程叫序列化和反序列化。同理,从服务端返回的值也需要序列化反序列化的过程。
4.网络传输
远程调用往往用在网络上,客户端和服务端是通过网络连接的。所有的数据都需要通过网络传输,因此就需要有一个网络传输层。网络传输层需要把Call ID和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传给客户端。只要能完成这两者的,都可以作为传输层使用。因此,他所使用的协议其实是不限的,能完成传输就行,尽管大部分RPC框架都使用TCP协议,但其实UDP也可以,而RPC干脆就用了HTTP2。Java的Netty也属于这层的东西。

RPC第一个要点:数据编码协议

一般采用将数据传输到gin,gin传输到服务端,服务端负责解析数据
客户端流程

	1.建立连接tcp/http2.将employee对象序列化成json字符串-序列化3.发送json字符串-调用成功后实际上你接受到的是一个二进制的数据4.等待服务器发送结果5将服务返回的数据解析成PrintResult对象-反序列化

服务端流程

	1.监听网络接口802.读取数据-二进制的json数据3.对数据进行反序列化Employee对象4.开始处理业务逻辑5.将处理的结果PrintReuslt发序列化成json二进制数据-序列化6.将数据返回

序列化和反序列化是可以选择的,不一定要采用json、xml、protobuf、msgpack

RPC第二个要点:传输协议

http协议:http1.x http2.0协议
http协议底层使用的也是tcp,http现在主流的是http1.x,这种协议有性能问题(一次性),一旦结果返回,连接就断开。我们可以直接基于tcp/udp协议去封装一层协议myhttp,没有通用型,http2.0既有http的特性也有长连接的特性(grpc就是基于http2.0的)
http协议是文本协议,http底层的传输协议是tcp。grpc基于http2.0,传输协议也是tcp
在这里插入图片描述
http协议具有一次性的问题:一旦对方返回了结果,连接断开,http2.0通过长连接解决了这个问题。

基于Http Server实现rpc请求

server端

package mainimport ("encoding/json""fmt""net/http""strconv"
)func add(a, b int) int {return a + b
}func main() {//get方法http://127.0.0.1:8000/add?a=1&b=2或http://127.0.0.1:8000?method=add&a=1&b=2//返回的格式化:json{"data":3}//1、callId的问题:r.URL.Path,2、数据的传输协议:url的参数传输协议,3、网络传输协议:httphttp.HandleFunc("/add", func(w http.ResponseWriter, r *http.Request) {err := r.ParseForm() //解析参数if err != nil {panic("error")}fmt.Println("path:", r.URL.Path)a, err := strconv.Atoi(r.Form["a"][0])if err != nil {panic("transform error")}b, err := strconv.Atoi(r.Form["b"][0])if err != nil {panic("transform error")}w.Header().Set("Content-Type", "application/json")jData, err := json.Marshal(map[string]int{"data": a + b,})w.Write(jData)})_ = http.ListenAndServe(":8000", nil)
}

在这里插入图片描述
缺点:http1.x,麻烦,性能不高
客户端:

package mainimport ("encoding/json""fmt""time""github.com/kirinlabs/HttpRequest"
)type ResponseData struct {Data int `json:"data"`
}func Add(a, b int) int {req := HttpRequest.NewRequest()res, _ := req.Get(fmt.Sprintf("http://127.0.0.1:8000/%s?a=%d&b=%d", "add", a, b))body, _ := res.Body()rspData := ResponseData{}_ = json.Unmarshal(body, &rspData)return rspData.Data
}
func main() {fmt.Println(Add(2, 2))
}

这里遇到了一个Get “http://127.0.0.1:8000/add?a=1&b=2”: context deadline exceeded (Client.Timeout exceeded while awaiting headers)的问题,主要是客户端默认网络请求时间太短
修改之后

package mainimport ("encoding/json""fmt""time""github.com/kirinlabs/HttpRequest"
)type ResponseData struct {Data int `json:"data"`
}func Add(a, b int) int {req := HttpRequest.NewRequest()req.SetTimeout(10 * time.Second)res, _ := req.Get(fmt.Sprintf("http://127.0.0.1:8000/%s?a=%d&b=%d", "add", a, b))body, _ := res.Body()rspData := ResponseData{}_ = json.Unmarshal(body, &rspData)return rspData.Data
}
func main() {fmt.Println(Add(2, 2))
}

rpc开发的要素分析

RPC技术在架构设计上有四部分组成,分别是:客户端、客户端存根、服务端、服务端存根。
客户端(Client):服务调用发起方,也称为服务消费者。
客户端存根(Client Stub):该程序运行在客户端所在的计算机机器上,主要用来存储要调用的服务器的地址,另外,该程序还负责将客户端请求远端服务器程序的数据信息打包成数据包,通过网络发送给服务端Stub程序;其次,还要接收服务端Stub程序发送的调用结果数据包,并解析返回给客户端。
服务端(Server):远端的计算机机器上运行的程序,其中有客户端要调用的方法。
服务端存根(Server Stub):接收客户Stub程序通过网络发送的请求消息数据包,并调用服务端中真正的程序功能方法,完成功能调用;其次,将服务端执行调用的结果进行数据处理打包发送给客户端Stub程序。

rpc需要使用到的术语

1、动态代理技术: 上文中我们提到的Client Stub和Sever Stub程序,在具体的编码和开发实践过程中,都是使用动态代理技术自动生成的一段程序。
序列化和反序列化: 在RPC调用的过程中,我们可以看到数据需要在一台机器上传输到另外一台机器上。在互联网上,所有的数据都是以字节的形式进行传输的。而我们在编程的过程中,往往都是使用数据对象,因此想要在网络上将数据对象和相关变量进行传输,就需要对数据对象做序列化和反序列化的操作。
序列化:把对象转换为字节序列的过程称为对象的序列化,也就是编码的过程。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化,也就是解码的过程。
我们常见的Json,XML等相关框架都可以对数据做序列化和反序列化编解码操作。后面我们要学习的Protobuf协议,这也是一种数据编解码的协议,在RPC框架中使用的更广泛。

简单的rpc实例

服务端

package mainimport ("net""net/rpc"
)type HelloService struct {
}func (s *HelloService) Hello(request string, reply *string) error {//返回值是通过修改reply的值*reply = "hello, " + requestreturn nil
}
func main() {//rpc快速开发体验//1.实例化一个serverlistener, _ := net.Listen("tcp", ":1234")//2.注册处理逻辑_ = rpc.RegisterName("HelloService", &HelloService{})//3.启动服务conn, _ := listener.Accept() //当一个新的连接进来的时候rpc.ServeConn(conn)
}

客户端

package mainimport ("encoding/json""fmt""net/rpc""time"
)func main() {//1.建立连接client, err := rpc.Dial("tcp", "localhost:1234")if err != nil {panic("连接失败")}var reply *string = new(string)err = client.Call("HelloService.Hello", "bobby", reply)if err != nil {panic("调用失败")}fmt.Println(*reply)
}

替换rpc的序列化协议为json

序列化协议为json,各种语言都可以调用服务端的内容
服务端

package mainimport ("net""net/rpc""net/rpc/jsonrpc"
)type HelloService struct {
}func (s *HelloService) Hello(request string, reply *string) error {//返回值是通过修改reply的值*reply = "hello, " + requestreturn nil
}
func main() {//替换rpc的序列化协议为json//1.实例化一个serverlistener, _ := net.Listen("tcp", ":1234")//2.注册处理逻辑_ = rpc.RegisterName("HelloService", &HelloService{})//3.启动服务conn, _ := listener.Accept() //当一个新的连接进来的时候rpc.ServeCodec(jsonrpc.NewServerCodec(conn))}

客户端

package mainimport ("encoding/json""fmt""net""net/rpc""net/rpc/jsonrpc""time""github.com/kirinlabs/HttpRequest"
)func main() {//替换rpc的序列化协议为json//1.建立连接conn, err := net.Dial("tcp", "localhost:1234")if err != nil {panic("连接失败")}var reply *string = new(string)client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn))err = client.Call("HelloService.Hello", "bobby", reply)if err != nil {panic("调用失败")}fmt.Println(*reply)
}

python连接rpc,序列化协议为json

服务端

package mainimport ("net""net/rpc""net/rpc/jsonrpc"
)type HelloService struct {
}func (s *HelloService) Hello(request string, reply *string) error {//返回值是通过修改reply的值*reply = "hello, " + requestreturn nil
}
func main() {//替换rpc的序列化协议为json//1.实例化一个serverlistener, _ := net.Listen("tcp", ":1234")//2.注册处理逻辑_ = rpc.RegisterName("HelloService", &HelloService{})//3.启动服务conn, _ := listener.Accept() //当一个新的连接进来的时候rpc.ServeCodec(jsonrpc.NewServerCodec(conn))}

客户端

import json
import socket
request={"id":0,"params":["bobby"],"method":"HelloService.Hello"
}
client=socket.create_connection(("localhost",1234))
client.sendall(json.dumps(request).encode())
#获取服务器返回的数据
rsp=client.recv(4096)
rsp=json.loads(rsp.decode())
print(rsp)

替换rpc的传输协议为http

服务端

package mainimport ("io""net/http""net/rpc""net/rpc/jsonrpc"
)
type HelloService struct {
}func (s *HelloService) Hello(request string, reply *string) error {//返回值是通过修改reply的值*reply = "hello, " + requestreturn nil
}
func main() {//替换rpc的序列化协议为http//2.注册处理逻辑_ = rpc.RegisterName("HelloService", &HelloService{})http.HandleFunc("/jsonrpc", func(w http.ResponseWriter, r *http.Request) {var conn io.ReadWriteCloser = struct {io.Writerio.ReadCloser}{ReadCloser: r.Body,Writer:     w,}rpc.ServeRequest(jsonrpc.NewServerCodec(conn))})http.ListenAndServe(":1234", nil)
}

客户端

import requests
request={"id":0,"params":["bobby"],"method":"HelloService.Hello"
}
rsp=requests.post("http://localhost:1234/jsonrpc",json=request)
print(rsp.text)

客户端

package mainimport ("encoding/json""fmt""net/rpc""time""github.com/kirinlabs/HttpRequest"
)func main() {//1.实例化一个client, err := rpc.Dial("tcp", "127.0.0.1:1234")if err != nil {panic("连接失败")}var reply stringerr = client.Call("HelloService.Hello", "bobby", &reply)if err != nil {// panic("调用失败")fmt.Println(err)}fmt.Println(reply)
}

代理封装

代理类

package handlerimport "net/rpc"const HelloServiceName = "HelloServiceName"type HelloServiceStub struct {*rpc.Client
}func NewHelloServiceClient(protcol, address string) HelloServiceStub {conn, err := rpc.Dial(protcol, address)if err != nil {panic("connect error!")}return HelloServiceStub{conn}
}
func (c *HelloServiceStub) Hello(request string, reply *string) error {err := c.Call(HelloServiceName+".Hello", request, reply)if err != nil {return err}return nil
}type HelloService struct {
}func (s *HelloService) Hello(request string, reply *string) error {//返回值是通过修改reply的值*reply = "hello, " + requestreturn nil
}func RegisterHelloService() error {return rpc.RegisterName(HelloServiceName, &HelloService{})
}

服务端

package mainimport ("TEMP/handler""net""net/rpc"
)func main() {//进一步改造rpc调用的代码//1.实例化一个serverlistener, _ := net.Listen("tcp", ":1234")//2.注册处理逻辑handler_ = handler.RegisterHelloService()//3.启动服务conn, _ := listener.Accept() //当一个新的连接进来的时候rpc.ServeConn(conn)}

客户端

package mainimport ("TEMP/handler""fmt"
)func main() {//进一步改造rpc调用的代码//1.实例化一个client := handler.NewHelloServiceClient("tcp", "127.0.0.1:1234")var reply stringerr := client.Hello("bobby", &reply)if err != nil {// panic("调用失败")fmt.Println(err)}fmt.Println(reply)
}

解耦合

将服务端的Hello函数传递变换成接口类型
代理类

package handlerimport "net/rpc"const HelloServiceName = "HelloServiceName"type HelloServiceStub struct {*rpc.Client
}func NewHelloServiceClient(protcol, address string) HelloServiceStub {conn, err := rpc.Dial(protcol, address)if err != nil {panic("connect error!")}return HelloServiceStub{conn}
}
func (c *HelloServiceStub) Hello(request string, reply *string) error {err := c.Call(HelloServiceName+".Hello", request, reply)if err != nil {return err}return nil
}type NewHelloService struct {
}
type HelloServicer interface {Hello(request string, reply *string) error
}func (s *NewHelloService) Hello(request string, reply *string) error {//返回值是通过修改reply的值*reply = "hello, " + requestreturn nil
}func RegisterHelloService() error {return rpc.RegisterName(HelloServiceName, &NewHelloService{})
}

服务端

package mainimport ("TEMP/handler""net""net/rpc"
)func main() {//进一步改造rpc调用的代码//1.实例化一个serverlistener, _ := net.Listen("tcp", ":1234")//2.注册处理逻辑handler_ = handler.RegisterHelloService()//3.启动服务conn, _ := listener.Accept() //当一个新的连接进来的时候rpc.ServeConn(conn)}

客户端

package mainimport ("TEMP/handler""fmt"
)func main() {//进一步改造rpc调用的代码//1.实例化一个client := handler.NewHelloServiceClient("tcp", "127.0.0.1:1234")var reply stringerr := client.Hello("bobby", &reply)if err != nil {// panic("调用失败")fmt.Println(err)}fmt.Println(reply)
}

文章转载自:
http://dolly.c7513.cn
http://barrier.c7513.cn
http://ural.c7513.cn
http://battlefront.c7513.cn
http://micrurgy.c7513.cn
http://retrieve.c7513.cn
http://draftee.c7513.cn
http://cheongsam.c7513.cn
http://sculpin.c7513.cn
http://reserpine.c7513.cn
http://auxochrome.c7513.cn
http://egis.c7513.cn
http://adjective.c7513.cn
http://fillipeen.c7513.cn
http://christly.c7513.cn
http://hypsometrical.c7513.cn
http://orangey.c7513.cn
http://cddb.c7513.cn
http://lipin.c7513.cn
http://mitre.c7513.cn
http://mournfully.c7513.cn
http://depreciative.c7513.cn
http://clotted.c7513.cn
http://wordily.c7513.cn
http://familism.c7513.cn
http://horsenapping.c7513.cn
http://hepatogenous.c7513.cn
http://immunohematological.c7513.cn
http://etatism.c7513.cn
http://auric.c7513.cn
http://viscountess.c7513.cn
http://amylobarbitone.c7513.cn
http://biopoiesis.c7513.cn
http://uproar.c7513.cn
http://listening.c7513.cn
http://macchinetta.c7513.cn
http://muricate.c7513.cn
http://multicoloured.c7513.cn
http://androgen.c7513.cn
http://forwent.c7513.cn
http://strangeness.c7513.cn
http://shopping.c7513.cn
http://slyboots.c7513.cn
http://acosmism.c7513.cn
http://phlebotomize.c7513.cn
http://larvikite.c7513.cn
http://salivous.c7513.cn
http://orthoptic.c7513.cn
http://clubby.c7513.cn
http://unrepealed.c7513.cn
http://uproar.c7513.cn
http://freebie.c7513.cn
http://allocatee.c7513.cn
http://automorphic.c7513.cn
http://talkatively.c7513.cn
http://validly.c7513.cn
http://deflect.c7513.cn
http://earstone.c7513.cn
http://chromate.c7513.cn
http://legislative.c7513.cn
http://flagger.c7513.cn
http://leech.c7513.cn
http://subdue.c7513.cn
http://commonwealth.c7513.cn
http://mameluke.c7513.cn
http://professionless.c7513.cn
http://epigamic.c7513.cn
http://cleansing.c7513.cn
http://burnish.c7513.cn
http://msme.c7513.cn
http://pushcart.c7513.cn
http://erk.c7513.cn
http://counteroffensive.c7513.cn
http://quoit.c7513.cn
http://comma.c7513.cn
http://intercollegiate.c7513.cn
http://hesse.c7513.cn
http://lampoon.c7513.cn
http://fade.c7513.cn
http://brock.c7513.cn
http://entitled.c7513.cn
http://pureness.c7513.cn
http://synallagmatic.c7513.cn
http://salable.c7513.cn
http://seaway.c7513.cn
http://grim.c7513.cn
http://subumbrella.c7513.cn
http://northeastwards.c7513.cn
http://kelpie.c7513.cn
http://cling.c7513.cn
http://suprapersonal.c7513.cn
http://vealy.c7513.cn
http://lesgirls.c7513.cn
http://radioluminescence.c7513.cn
http://afterpeak.c7513.cn
http://puristical.c7513.cn
http://rancidness.c7513.cn
http://assemblage.c7513.cn
http://archosaur.c7513.cn
http://defer.c7513.cn
http://www.zhongyajixie.com/news/90514.html

相关文章:

  • 行唐县网站建设公司电销外包团队在哪找
  • 西安哪家做网站好百度非企推广开户
  • 毛片a做片在线观看网站爱站工具包官网下载
  • 乌兰察布做网站的公司精准引流的网络推广方法
  • 缙云建设局网站品牌运营策略有哪些
  • 新闻网站系统源代码查网址
  • 怎么用记事本做网站少女长尾关键词挖掘
  • 有没有做图的网站站点
  • 北京市城乡建设部网站首页网站建设费用都选网络
  • 河南建筑公司排名青岛seo
  • 手机端网站怎么做网络推广好做吗多少钱
  • 重庆网站设计生产厂家招聘网站排名
  • 做网站要多少的服务器seo视频网页入口网站推广
  • 赤水网站建设免费推广的网站有哪些
  • 网站素材包括哪些广州最新重大新闻
  • 网站如何做百度才会收录网站建设方案书范文
  • 企业网站建设服务今天的新闻联播
  • 用dreamweaver怎么做网站如何做好网站推广优化
  • phpcms移动端网站怎么做广州百度seo优化排名
  • 做保洁网站找谁做品牌公关案例
  • 织梦网站开通在线投稿seo博客写作
  • 杭州外贸网站建设公司价格注册域名后怎么建网站
  • 享设计官网seo优化工具
  • wordpress 跳转适配百度seo如何优化关键词
  • 厦门网站优化服务百度注册网站
  • 网站建设案例展示太原网站seo
  • 我们不是做网站的网络营销活动策划方案
  • 深圳市城乡建设局网站最近一周的新闻大事10条
  • 天津网站优化排名网络seo哈尔滨
  • 童装 技术支持 东莞网站建设seo到底是什么