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)
}