远程过程调用
简单实现
服务端
from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer
def add(a,b):
return a + b
server = SimpleJSONRPCServer(('127.0.0.1',8000))
server.register_function(add)
print("Listen on port 8000")
server.serve_forever()
客户端
import jsonrpclib
server = jsonrpclib.ServerProxy('http://127.0.0.1:8000')
print(server.add(1,2))
考虑问题
1)超时机制
2)限流,处于长期高可用状态
3)解耦
4)负载均衡,微服务-分布式应用的具体体现
5)序列化和饭序列化是否高效
zerorpc
简单调用
服务端
import zerorpc
class Caculator:
def add(self,a,b):
return a + b
s = zerorpc.Server(Caculator())
s.bind('tcp://0.0.0.0:8000')
s.run()
客户端
import zerorpc
c = zerorpc.Client()
c.connect('tcp://127.0.0.1:8000')
print(c.add(1,2))
流式调用
服务端
import zerorpc
class StreamingRPC(object):
@zerorpc.stream
def streaming_range(self, fr, to, step):
return range(fr, to, step)
s = zerorpc.Server(StreamingRPC())
s.bind("tcp://0.0.0.0:4242")
s.run()
客户端
import zerorpc
c = zerorpc.Client()
c.connect("tcp://127.0.0.1:4242")
for item in c.streaming_range(10, 20, 2):
print(item)
go语言实现
简单实现
服务端
package main
import (
"net"
"net/rpc"
)
type HelloService struct {}
func (s *HelloService) Hello(arg string,reply *string)error{
*reply = "hello" + arg
return nil
}
func main() {
listener,_ := net.Listen("tcp",":8000")
_ = rpc.RegisterName("HelloService",&HelloService{})
conn,_ := listener.Accept()
rpc.ServeConn(conn)
}
客户端
package main
import "net/rpc"
func main(){
client,err := rpc.Dial("tcp","localhost:8000")
if err!=nil{
panic("连接失败")
}
var reply string
err = client.Call("HelloService.Hello","111",&reply)
if err!=nil{
println(err)
}
println(reply)
}
tcp协议调用
go服务端
package main
import (
"net"
"net/rpc"
"net/rpc/jsonrpc"
)
type HelloService struct {}
func (s *HelloService) Hello(arg string,reply *string)error{
*reply = "hello" + arg
return nil
}
func main() {
listener,_ := net.Listen("tcp",":8000")
_ = rpc.RegisterName("HelloService",&HelloService{})
for{
conn,_ := listener.Accept()
rpc.ServeCodec(jsonrpc.NewServerCodec(conn))//替换成jsonrpc
}
}
go客服端
package main
import (
"net"
"net/rpc"
"net/rpc/jsonrpc"
)
func main(){
conn,err := net.Dial("tcp","localhost:8000")
if err!=nil{
panic("连接失败")
}
var reply string
client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn))
err = client.Call("HelloService.Hello",",world",&reply)
if err!=nil{
println(err)
}
println(reply)
}
python客户端
import socket,json
request = {
"id":0,
"params":["aaaaa"],
"method":"HelloService.Hello"
}
client = socket.create_connection(("127.0.0.1",8000))
client.sendall(json.dumps(request).encode())
rsp = client.recv(1024)
rsp = json.loads(rsp.decode())
print(rsp)
# {'id': 0, 'result': 'helloaaaaa', 'error': None}
http协议调用
go服务端
package main
import (
"io"
"net/http"
"net/rpc"
"net/rpc/jsonrpc"
)
type HelloService struct {}
func (s *HelloService) Hello(arg string,reply *string)error{
*reply = "hello" + arg
return nil
}
func main() {
_ = rpc.RegisterName("HelloService",&HelloService{})
http.HandleFunc("/jsonrpc",func(w http.ResponseWriter,r *http.Request){
var conn io.ReadWriteCloser = struct {
io.Writer
io.ReadCloser
}{
ReadCloser:r.Body,
Writer:w,
}
rpc.ServeRequest(jsonrpc.NewServerCodec(conn))
})
http.ListenAndServe(":8000",nil)
}
python客户端
import requests,json
request = {
"id":0,
"params":["aaaaa"],
"method":"HelloService.Hello"
}
rsp = requests.post("http://127.0.0.1:8000/jsonrpc",json=request)
print(rsp.text)
# {'id': 0, 'result': 'helloaaaaa', 'error': None}
改良版
handler
package handler
//定义服务名
const Service = "handler/HelloService"
//定义服务对象及方法
type HelloService struct {}
func (s *HelloService) Hello(arg string,reply *string)error{
*reply = "hello" + arg
return nil
}
服务端代理
package server_proxy
import (
"awesomeProject1/msg/rpc/handler"
"net/rpc"
)
type HelloService interface {
Hello(arg string,reply *string)error
}
//接受接口
func RegisterHelloService(srv HelloService) error{
return rpc.RegisterName(handler.Service,srv)
}
服务端
package main
import (
"awesomeProject1/msg/rpc/handler"
"awesomeProject1/msg/rpc/server/server_proxy"
"net"
"net/rpc"
)
func main() {
listener,_ := net.Listen("tcp",":8000")
server_proxy.RegisterHelloService(&handler.HelloService{})
for{
conn,_ := listener.Accept()
rpc.ServeConn(conn)
}
}
客户端代理
package client_proxy
import (
"awesomeProject1/msg/rpc/handler"
"fmt"
"net/rpc"
)
type HelloServiceStub struct {
*rpc.Client
}
func NewHelloServiceClient(protcal,address string) HelloServiceStub{
conn,err := rpc.Dial(protcal,address)
if err != nil{
panic("connect error")
}
return HelloServiceStub{conn}
}
func (c *HelloServiceStub) Hello(request string,reply *string) error{
err := c.Call(handler.Service+".Hello",request,reply)
if err != nil{
panic("调用失败")
}
fmt.Println(reply)
return err
}
客户端
package main
import (
"awesomeProject1/msg/rpc/client/client_proxy"
"fmt"
)
func main(){
var reply string
client := client_proxy.NewHelloServiceClient("tcp", "localhost:8000")
client.Hello("aaa",&reply)
fmt.Println(reply)
}
grpc
python
安装
pip install grpcio
pip install grpcio-tools
创建.proto文件
syntax = "proto3";
message DomoPushRequest {// 定义请求数据
string digest = 1;
string content= 2;
string psd = 3;
}
message DomoPushRst{// 定义返回格式
string rst_string = 1; //统一返回json字符串作处理
}
service DomoPushHandler {
rpc create_domopush (DomoPushRequest) returns (DomoPushRst) {}
}
执行命令,将会生成两个py文件
python3 -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. *.proto
定义server
from concurrent import futures
import grpc
from rpc.test_pb2 import DomoPushRequest,DomoPushRst
from rpc.test_pb2_grpc import DomoPushHandlerServicer,add_DomoPushHandlerServicer_to_server
class Hello(DomoPushHandlerServicer):
def create_domopush(self, request, context):
print(request)
return DomoPushRst(rst_string=request.digest+request.content+request.psd)
# 实例化server
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
# 注册
add_DomoPushHandlerServicer_to_server(Hello(),server)
# 绑定ip端口
server.add_insecure_port("[::]:50000")
server.start()
server.wait_for_termination()
定义client
import grpc
from rpc.test_pb2 import DomoPushRequest,DomoPushRst
from rpc.test_pb2_grpc import DomoPushHandlerStub
with grpc.insecure_channel("localhost:50000") as chanel:
stub = DomoPushHandlerStub(chanel)
response = stub.create_domopush(DomoPushRequest(digest="hello",content=",",psd="world"))
print(response.rst_string)
go
1)安装protoc
https://github.com/protocolbuffers/protobuf/releases
2)安装protoc-gen-go
go get github.com/golang/protobuf/protoc-gen-go
3)创建proto
syntax="proto3";
option go_package = "./;proto";
service Greeter{
rpc SayHello(HelloRequest) returns (HelloReply);
}
message HelloRequest{
string name = 1;
}
message HelloReply{
string message = 1;
}
4)生成go文件
protoc -I . helloworld.proto --go_out=plugins=grpc:.
5)安装grpc
go get -u google.golang.org/grpc
或下载
https://github.com/grpc/grpc-go
6)服务端
package main
//noinspection ALL
import (
"context"
"google.golang.org/grpc"
"gotest/proto"
"net"
)
type Server struct {}
func (s *Server) SayHello(ctx context.Context,request *proto.HelloRequest)(*proto.HelloReply,error){
return &proto.HelloReply{
Message: "hello,"+request.Name,
},nil
}
func main(){
g := grpc.NewServer()
proto.RegisterGreeterServer(g,&Server{})
lis,err := net.Listen("tcp","0.0.0.0:8080")
if err != nil{
panic("failed to listen"+err.Error())
}
g.Serve(lis)
}
7)客户端
package main
//noinspection ALL
import (
"context"
"fmt"
"google.golang.org/grpc"
"gotest/proto"
)
func main(){
conn,err := grpc.Dial("127.0.0.1:8080",grpc.WithInsecure())
if err != nil {
panic(err)
}
defer conn.Close()
c := proto.NewGreeterClient(conn)
r,err := c.SayHello(context.Background(),&proto.HelloRequest{Name:"world"})
if err != nil {
panic(err)
}
fmt.Println(r.Message)
}
grpc的四种数据流
- 单项数据
即客户端发送一个请求给服务端,从服务端获取一个应答,就像一次普通的函数调用。 - 服务端数据流
客户端发起一次请求,服务端不断向客户端发送数据 - 客户端数据流
客户端不断向服务端发送数据,如物联网应用 - 双向数据流
双方相互大量发送数据,如聊天机器人
1)定义proto
syntax = "proto3";
option go_package="./;proto";
service Greeter{
rpc GetString(StreamReqData)returns(stream StreamResData);
rpc PutString(stream StreamReqData)returns(stream StreamResData);
rpc AllString(stream StreamReqData)returns(stream StreamResData);
}
message StreamReqData{
string data = 1;
}
message StreamResData{
string data = 1;
}
2)服务端
package main
import (
"fmt"
"google.golang.org/grpc"
"gotest/strem_test/proto"
"net"
"sync"
"time"
)
type server struct {
}
//服务端流模式
func (s *server) GetString(req *proto.StreamReqData, res proto.Greeter_GetStringServer) error{
i := 0
fmt.Println(req.Data)
for{
i++
res.Send(&proto.StreamResData{Data: fmt.Sprintf("%v",time.Now().Unix())})
if i>10{
break
}
}
return nil
}
//客户端流模式
func (s *server) PutString(clistr proto.Greeter_PutStringServer) error{
for{
if a,err := clistr.Recv();err != nil{
fmt.Println(err)
break
}else {
fmt.Println(a.Data)
}
}
return nil
}
//双向流模式
func (s *server) AllString(allstr proto.Greeter_AllStringServer) error{
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
for{
data,_ := allstr.Recv()
fmt.Println("收到:"+data.Data)
}
}()
go func() {
defer wg.Done()
for{
_ = allstr.Send(&proto.StreamResData{
Data: "服务器消息",
})
time.Sleep(time.Second)
}
}()
wg.Wait()
return nil
}
func main() {
lis,err := net.Listen("tcp",":5555")
if err != nil{
panic(err)
}
s := grpc.NewServer()
proto.RegisterGreeterServer(s,&server{})
err = s.Serve(lis)
if err != nil{
panic(err)
}
}
3)客户端
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"gotest/strem_test/proto"
"sync"
"time"
)
func main(){
conn,err := grpc.Dial("localhost:5555",grpc.WithInsecure())
if err != nil{
panic(err)
}
//defer conn.Close()
c := proto.NewGreeterClient(conn)
/*---------------------------------*/
res,_ := c.GetString(context.Background(),&proto.StreamReqData{Data: "hello"})
for{
a,err := res.Recv()
if err != nil{
fmt.Println(err)
break
}
fmt.Println(a)
}
/*---------------------------------*/
puts,_ := c.PutString(context.Background())
i := 0
for{
i++
puts.Send(&proto.StreamReqData{Data: "a"})
time.Sleep(time.Second)
if i>10{
break
}
}
/*---------------------------------*/
allstr,_ := c.AllString(context.Background())
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
for{
data,_ := allstr.Recv()
fmt.Println("收到:"+data.Data)
}
}()
go func() {
defer wg.Done()
for{
_ = allstr.Send(&proto.StreamReqData{Data: "客户端消息"})
time.Sleep(time.Second)
}
}()
wg.Wait()
}还没有评论,来说两句吧
