image.png

1 客户端和服务端都是Go

基于tcp实现, 只有当客户端和服务端都是Go程序时才能使用
golang写RPC程序,必须符合4个基本条件,不然RPC用不了

  • 结构体字段首字母要大写,可以别人调用
  • 函数名必须首字母大写
  • 函数第一参数是接收参数,第二个参数是返回给客户端的参数,必须是指针类型
  • 函数还必须有一个返回值error

    (1) server.go

    ```go package main

import ( “net” “net/rpc” )

type HelloService struct{}

func (s HelloService) Hello(request string, reply string) error { *reply = “hello,” + request return nil }

func main() { // 实例化一个server listener, _ := net.Listen(“tcp”, “:12345”)

  1. // 注册处理逻辑handler
  2. _ = rpc.RegisterName("HelloService", &HelloService{})
  3. // 启动服务
  4. for {
  5. conn, _ := listener.Accept()
  6. go rpc.ServeConn(conn)
  7. }

}

  1. <a name="Ypo3e"></a>
  2. ## (2) client.go
  3. ```go
  4. package main
  5. import (
  6. "fmt"
  7. "net/rpc"
  8. )
  9. func main() {
  10. // 建立连接
  11. client, err := rpc.Dial("tcp", ":12345")
  12. if err != nil {
  13. panic("连接失败")
  14. }
  15. var reply *string = new(string)
  16. err = client.Call("HelloService.Hello", "bobby", reply)
  17. if err != nil {
  18. panic("调用失败")
  19. }
  20. fmt.Println(*reply)
  21. }

2 服务端是Go, 客户端任意语言(基于json)

基于tcp实现
适用于服务端是go, 客户端可以是其它语言的程序

(1) server.go

  1. package main
  2. import (
  3. "net"
  4. "net/rpc"
  5. "net/rpc/jsonrpc"
  6. )
  7. type HelloService struct{}
  8. func (s *HelloService) Hello(request string, reply *string) error {
  9. *reply = "hello," + request
  10. return nil
  11. }
  12. func main() {
  13. // 实例化一个server
  14. listener, _ := net.Listen("tcp", ":6666")
  15. // 注册处理逻辑handler
  16. _ = rpc.RegisterName("HelloService", &HelloService{})
  17. // 启动服务
  18. for {
  19. conn, _ := listener.Accept()
  20. go rpc.ServeCodec(jsonrpc.NewServerCodec(conn))
  21. }
  22. }

(2) client.go

  1. package main
  2. import (
  3. "fmt"
  4. "net"
  5. "net/rpc"
  6. "net/rpc/jsonrpc"
  7. )
  8. func main() {
  9. // 建立连接
  10. conn, err := net.Dial("tcp", ":12345")
  11. if err != nil {
  12. panic("连接失败")
  13. }
  14. var reply *string = new(string)
  15. client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn))
  16. err = client.Call("HelloService.Hello", "bobby", reply)
  17. if err != nil {
  18. panic("调用失败")
  19. }
  20. fmt.Println(*reply)
  21. }

(3) client.py

  1. import json
  2. from socket import *
  3. tcp_socket = socket(AF_INET, SOCK_STREAM)
  4. tcp_socket.connect(("localhost", 6666))
  5. request = {
  6. "id": 0,
  7. "params": ["bobby"],
  8. "method": "HelloService.Hello"
  9. }
  10. tcp_socket.send(json.dumps(request).encode())
  11. rsp = tcp_socket.recv(4096).decode()
  12. rsp = json.loads(rsp)
  13. print(rsp)

3 封装代理

image.png

(1) handler.go

  1. package handler
  2. const HelloServiceName = "handler/HelloService"
  3. type NewHelloService struct {}
  4. func (s *NewHelloService) Hello(request string, reply *string) error {
  5. // 返回值是通过修改reply的值
  6. *reply = "hello," + request
  7. return nil
  8. }

(2) server_proxy.go

  1. package server_proxy
  2. import (
  3. "net/rpc"
  4. "new_hello/handler"
  5. )
  6. type HelloServicer interface {
  7. Hello(request string, reply *string) error
  8. }
  9. func RegisterHelloService(srv HelloServicer) error {
  10. return rpc.RegisterName(handler.HelloServiceName, srv)
  11. }

(3) server.go

  1. package main
  2. import (
  3. "net"
  4. "net/rpc"
  5. "new_hello/handler"
  6. "new_hello/server_proxy"
  7. )
  8. func main() {
  9. listener, _ := net.Listen("tcp", ":1234")
  10. _ = server_proxy.RegisterHelloService(&handler.NewHelloService{})
  11. for {
  12. conn, _ := listener.Accept()
  13. go rpc.ServeConn(conn)
  14. }
  15. }

(4) client_proxy.go

  1. package client_proxy
  2. import (
  3. "net/rpc"
  4. "new_hello/handler"
  5. )
  6. type HelloServiceStub struct {
  7. *rpc.Client
  8. }
  9. func NewHelloServiceClient(protocol, address string) HelloServiceStub {
  10. conn, err := rpc.Dial(protocol, address)
  11. if err != nil {
  12. panic("connect error")
  13. }
  14. return HelloServiceStub{conn}
  15. }
  16. func (c *HelloServiceStub) Hello(request string, reply *string) error {
  17. err := c.Call(handler.HelloServiceName+".Hello", request, reply)
  18. return err
  19. }

(5) client.go

  1. package main
  2. import (
  3. "new_hello/client_proxy"
  4. "fmt"
  5. )
  6. func main() {
  7. client := client_proxy.NewHelloServiceClient("tcp", ":1234")
  8. var reply string
  9. err := client.Hello("bobby", &reply)
  10. if err != nil {
  11. panic("调用失败")
  12. }
  13. fmt.Println(reply)
  14. }