Go语言学习笔记(十二)Tcp实现Rpc

1.Tcp实现Rpc:

既然可以直接利用Tcp传递消息,相对于Http来说便不在需要相关处理..同时利用Http实现Rpc时,服务端可以自动接管网络连接.然后负责对象连接管理.Tcp只能自行处理.

1.1服务端:

go 复制代码
package main

import (
	"errors"
	"fmt"
	"net"
	"net/rpc"
)

func main() {
	rpc.Register(new(UserHandler))
	listen, err := net.Listen("tcp", "127.0.0.1:8090")

	if err != nil {
		fmt.Println("监听tcp端口出错")
		return
	}

	for {
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println("建立tcp连接失败")
			continue
		}

		go func(conn net.Conn) {
			rpc.ServeConn(conn)
		}(conn)
	}
}

type UserHandler struct {
}

type Userdetail struct {
	Id       int
	Username string
	Nickname string
}

// 获取用户信息的方法绑定到结构体
func (handler *UserHandler) GetUserInfo(name string, user *Userdetail) (err error) {
	fmt.Println("try to get user info by %s", name)

	//校验入参.
	if len(name) == 0 {
		return errors.New("the user name is empty")
	}

	user.Id = 001
	user.Username = "itbo"
	user.Nickname = "尊敬的itbo"

	return nil
}

1.2客户端:

go 复制代码
package main

import (
	"fmt"
	"net/rpc"
)

func main() {
	//利用Tcp连接远程服务端.
	client, err := rpc.Dial("tcp", "127.0.0.1:8090")
	if err != nil {
		fmt.Println("与服务端建立连接出错")
		return
	}

	defer client.Close()

	user := new(Userdetail)
	client.Call("UserHandler.GetUserInfo", "golang", user)

	if err != nil {
		fmt.Println("获取用户信息出错", err)
		return
	}
	//打印获取的信息
	fmt.Printf("用户id:%+v\n", user.Id)
	fmt.Printf("用户名:%+v\n", user.Username)
	fmt.Printf("用户昵称:%+v\n", user.Nickname)

}

1.3执行结果:

​

1.4Http和Tcp实现Rpc区别:

Tcp实现的服务端代码失去了rpc.HandleHttp和http.Serve这两个函数的调用.其中rpc.HandleHttp用于注册默认的url和处理函数的映射关系.

打开http.service源码可以看到.

通过这里接收连接然后去处理.因为没有调用这个函数.所以tcp需要自己去处理连接.

2.Json格式实现Rpc通信:

2.1服务端:

go 复制代码
package main

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/rpc"
	"net/rpc/jsonrpc"
)

func main() {
	rpc.Register(new(UserHandler))
	listen, err := net.Listen("tcp", "127.0.0.1:8090")

	http.Serve(listen, nil)
	if err != nil {
		fmt.Println("监听tcp端口出错")
		return
	}

	for {
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println("建立tcp连接失败")
			continue
		}

		go func(conn net.Conn) {
			//利用jsonRpc处理连接.
			jsonrpc.ServeConn(conn)
		}(conn)
	}
}

type UserHandler struct {
}

type Userdetail struct {
	Id       int
	Username string
	Nickname string
}

// 获取用户信息的方法绑定到结构体
func (handler *UserHandler) GetUserInfo(name string, user *Userdetail) (err error) {
	fmt.Println("try to get user info by %s", name)

	//校验入参.
	if len(name) == 0 {
		return errors.New("the user name is empty")
	}

	user.Id = 001
	user.Username = "itbo"
	user.Nickname = "尊敬的itbo"

	return nil
}

2.2jsonrpc.ServeConn源码:

scss 复制代码
func ServeConn(conn io.ReadWriteCloser) {
	rpc.ServeCodec(NewServerCodec(conn))
}

2.3NewServerCodec源码:

可以看到底层有一个编码器和解码器.

go 复制代码
func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
	return &serverCodec{
		dec:     json.NewDecoder(conn),
		enc:     json.NewEncoder(conn),
		c:       conn,
		pending: make(map[uint64]*json.RawMessage),
	}
}

2.4客户端:

go 复制代码
package main

import (
	"fmt"
	"net/rpc"
	"net/rpc/jsonrpc"
)

func main() {
	//利用Tcp连接远程服务端.
	//client, err := rpc.Dial("tcp", "127.0.0.1:8090")
	client, err := jsonrpc.Dial("tcp", "127.0.0.1:8090")
	if err != nil {
		fmt.Println("与服务端建立连接出错")
		return
	}

	defer client.Close()

	user := new(Userdetail)
	client.Call("UserHandler.GetUserInfo", "golang", user)

	if err != nil {
		fmt.Println("获取用户信息出错", err)
		return
	}
	//打印获取的信息
	fmt.Printf("用户id:%+v\n", user.Id)
	fmt.Printf("用户名:%+v\n", user.Username)
	fmt.Printf("用户昵称:%+v\n", user.Nickname)
}
相关推荐
喵了几个咪10 小时前
GoWind CMS 拆解:在 Go 里给 TipTap 搭一套 Yjs 协同后端
开发语言·后端·golang
Flynt11 小时前
我把微信运动的排行榜和定点推送复刻了一遍:100万次步数更新只要4秒,坑在别处
redis·后端·性能优化
_孤傲_13 小时前
快速掌握 MySQL 语法
数据库·后端·mysql
IT_陈寒14 小时前
Java静态变量初始化坑得我头皮发麻
前端·人工智能·后端
步行cgn15 小时前
Thymeleaf 编辑表单详解:从字段回填到模拟 PUT 请求
后端
Song_RsHt16 小时前
Redis 与微服务,什么场景下无可替代
java·redis·后端·学习·微服务
学长毕设16 小时前
基于SpringBoot的建筑材料管理系统-附源码
java·spring boot·后端
程序员cxuan16 小时前
掀桌子了!Kimi K3.1 Pro 这效果也太离谱了。
人工智能·后端·程序员
摸爬滚打的小李16 小时前
关于 Arthas
java·后端
武子康17 小时前
黑图、彩色噪声、NaN、偏色怎么排查
人工智能·后端·agent