import "github.com/vmihailenco/msgpack" 有很多限制
-
-
Save changtimwu/0f8fbe78e9a11dbec464 to your computer and use it in GitHub Desktop.
test interoperability between ugorji msgpack
and smith
.
It has been known that ugorji msgpack RPC
as client doesn't work with a smith
server.
TODO:
- wrap
ugorji
to work withsmith
(using the way to we wrapvmihailenco
) -- done - or make smith becomes standard msgpack rpc compliant?
- compare their wired protocol -- done
- test pure data exchange
- test a deep & fat object -- done
- test a deep & fat object can be unmarshal to struct -- done
- test nodejs
Buffer
(can it be deserialized to []byte?) -- failed - test js
Undefined
-- failed
- test the case of deep nest collective variables. How to decode/encode between typed data and schemaless binary. -- done
- test ugorji rpc
- write example -- done
- study its API design -- done
- study its wired protocol with wireshark -- done by connection debugger
- write example to test asynchronize RPC call -- done
- make this implementation asynchronize -- done by
net/rpc
find a way to make following conversion
struct -> []interface{}
-> msgpack binary
http://golang.org/pkg/reflect/
Solved! simple and neat!
s := reflect.ValueOf(stvar)
hary:=make( []interface{}, s.NumField())
for i:=0; i<s.NumField(); i++ {
hary[i]= s.Field(i).Interface()
}
the call api design
var result int
cl.Call("mul", []int{3, 4}, &result)
Call
is from net/rpc.net/rpc
has some excellent designs.- registering APIs in server is very easy. It's just registering an instance and then all methods of this instance will become callable apis.
- It's encoding and transportation independent. You can adapt it on any encoding (json or msgpack) and any transportation(TCP/UNIX socket)
- supports both synchronize/asynchronies call. Invoking asynchronies call (
Go
) is more intopromise
instead ofcallback
. - arguments have to be collected into a single value, but they can be any type.
- return variable's type can be pre-declared, not restricted to
interface{}
.
For more examples, please see Richard's talk https://speakerdeck.com/dlackty/ruby-and-friends-taking-go-as-an-example
In Nodejs, quite a lot more msgpack implementations debut after we chose smith/msgpackjs 3 years ago.
- msgpack2 and msgpack3 improve encode/decode performance via native C/C++ implementation.
- msgpack-rpcjs is a pure JS implementation of msgpack rpc.
- framed-msgpack-rpc uses the same technique as
smith
, which prepends message length to each msgpack packets. It claims that in this way
receivers can efficiently buffer data until a full packet is available to decode. In an event-based context like node.js, framing simplifies implementation, and yields a faster decoder, especially for very large messages. - msgpack-stream combines
- improve performance by utilizing ES6
es.parse
- smith alike length prepending
- Its API design suitable for infinite stream process, which is GO idiomatic.
- improve performance by utilizing ES6
standard msgpack RPC binary
rpc call
cl.Call("Arith.Multiply", Args{A: 2, B: 99}, result)
generates
00000000 94 00 00 ae 41 72 69 74 68 2e 4d 75 6c 74 69 70 |....Arith.Multip|
00000010 6c 79 91 82 a1 41 02 a1 42 63 |ly...A..Bc|
which is encoding of the following
[0 0 "Arith.Multiply" [[map[A:2 B:99]]]
rpc call
cl.Call("Arith.Add", []int{55, 33, 77}, result)
generates
00000000 94 00 01 a9 41 72 69 74 68 2e 41 64 64 91 93 37 |....Arith.Add..7|
00000010 21 4d
which is encoding of
[0 1 "Arith.Add" [[55 33 77]]]
call ID is at the second integer. the first integer is always 0 in request and 1 in response.
func (c *msgpackSpecRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error {
...
r2 := []interface{}{0, uint32(r.Seq), r.ServiceMethod, bodyArr}
...
}
smith's binary
4-byte length + msgpack encoded binary
[ map[$ Seq] ... ]
smith's binary
4-byte length + msgpack encoded binary
rpc call
ret = apicall(trconn, "pow", &VarList{3, 4})
encoded as
[pow 3 4 map[$:4]]
returns
[4 81]
rpc call
ret = apicall(trconn, "threesum", &VarList{4, 5, 7})
encoded as
[threesum 4 5 7 map[$:5]]
returns
[5 16]
net/rpc call flow backtrace
- client make request
*[github.com/changtimwu/ugorji-go/codec.(*rpcCodec).write]
[github.com/changtimwu/ugorji-go/codec.(*msgpackSpecRpcCodec).WriteRequest]
[net/rpc.(*Client).send]
[net/rpc.(*Client).Go]
[net/rpc.(*Client).Call]
- server reads request reader * 3
*[github.com/changtimwu/ugorji-go/codec.(*rpcCodec).read]
[github.com/changtimwu/ugorji-go/codec.(*msgpackSpecRpcCodec).parseCustomHeader]
[github.com/changtimwu/ugorji-go/codec.(*msgpackSpecRpcCodec).ReadRequestHeader]
[net/rpc.(*Server).readRequestHeader]
[net/rpc.(*Server).readRequest]
[net/rpc.(*Server).ServeCodec]
- serve reads request body
*[github.com/changtimwu/ugorji-go/codec.(*rpcCodec).read]
[github.com/changtimwu/ugorji-go/codec.(*msgpackSpecRpcCodec).ReadRequestBody]
[net/rpc.(*Server).readRequest]
[net/rpc.(*Server).ServeCodec]
- server write response
*[github.com/changtimwu/ugorji-go/codec.(*rpcCodec).write]
[github.com/changtimwu/ugorji-go/codec.(*msgpackSpecRpcCodec).WriteResponse]
[net/rpc.(*Server).sendResponse]
- client reads response header * 3
*[github.com/changtimwu/ugorji-go/codec.(*rpcCodec).read]
[github.com/changtimwu/ugorji-go/codec.(*msgpackSpecRpcCodec).parseCustomHeader]
[github.com/changtimwu/ugorji-go/codec.(*msgpackSpecRpcCodec).ReadResponseHeader]
- client read response body
*[github.com/changtimwu/ugorji-go/codec.(*rpcCodec).read]
[github.com/changtimwu/ugorji-go/codec.(*rpcCodec).ReadResponseBody]
net/rpc
provides- ClientCodec asks
type ClientCodec interface {
// WriteRequest must be safe for concurrent use by multiple goroutines.
WriteRequest(*Request, interface{}) error
ReadResponseHeader(*Response) error
ReadResponseBody(interface{}) error
Close() error
}
- ServerCodec asks
type ServerCodec interface {
ReadRequestHeader(*Request) error
ReadRequestBody(interface{}) error
// WriteResponse must be safe for concurrent use by multiple goroutines.
WriteResponse(*Response, interface{}) error
Close() error
}
rpcCodec
is fundamental struct. It implements- low-level read/write functions which might be used while implementing
ServerCodec
andClientCodec
interfaces.
- low-level read/write functions which might be used while implementing
func (c *rpcCodec) BufferedReader() *bufio.Reader
func (c *rpcCodec) BufferedWriter() *bufio.Writer
func (c *rpcCodec) write(obj1, obj2 interface{}, writeObj2, doFlush bool) (err error)
func (c *rpcCodec) read(obj interface{}) (err error)
- Simple parts of
ServerCodec
andClientCodec
interface like
func (c *rpcCodec) Close() error
func (c *rpcCodec) ReadResponseBody(body interface{}) error
goRpcCodec
inheritsrpcCodec
(has-a
relation) and implementsBINC
specific methods
type goRpcCodec struct {
rpcCodec
}
func (c *goRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error
func (c *goRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error
func (c *goRpcCodec) ReadResponseHeader(r *rpc.Response) error
func (c *goRpcCodec) ReadRequestHeader(r *rpc.Request) error
msgpackSpecRpcCodec
inheritsrpcCodec
(viahas-a
) and implementsmsgpack
specific methods
type msgpackSpecRpcCodec struct {
rpcCodec
}
func (c *msgpackSpecRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error
func (c *msgpackSpecRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error
func (c *msgpackSpecRpcCodec) ReadResponseHeader(r *rpc.Response) error
func (c *msgpackSpecRpcCodec) ReadRequestHeader(r *rpc.Request) error
func (c *msgpackSpecRpcCodec) ReadRequestBody(body interface{}) error
goRpcCodec
implements both rpc.ServerCodec
and rpc.ClientCodec
so the same instance can be passed to both rpc.NewClientWithCodec(cc)
and rpc.NewServer().ServerCodec
msgpackSpecRpcCodec
is the same story.
https://github.com/ugorji/go/tree/master/codec is better
You can decode a heterogeneous array into a struct. ex.