Cap’n proto 号称是比protobuff更快的proto语言。官网截图

Cap’n Proto is an insanely fast data interchange format and capability-based RPC system. Think JSON, except binary. Or think Protocol Buffers, except faster. In fact, in benchmarks, Cap’n Proto is INFINITY TIMES faster than Protocol Buffers.

img

协议特性

Cap’n Proto’s RPC protocol has the following notable features. Since the protocol is complicated, the feature set has been divided into numbered “levels”, so that implementations may declare which features they have covered by advertising a level number.

  • Level 1: Object references and promise pipelining, as described above.
  • Level 2: Persistent capabilities. You may request to “save” a capability, receiving a persistent token which can be used to “restore” it in the future (on a new connection). Not all capabilities can be saved; the host app must implement support for it. Building this into the protocol makes it possible for a Cap’n-Proto-based data store to transparently save structures containing capabilities without knowledge of the particular capability types or the application built on them, as well as potentially enabling more powerful analysis and visualization of stored data.
  • Level 3: Three-way interactions. A network of Cap’n Proto vats (nodes) can pass object references to each other and automatically form direct connections as needed. For instance, if Alice (on machine A) sends Bob (on machine B) a reference to Carol (on machine C), then machine B will form a new connection to machine C so that Bob can call Carol directly without proxying through machine A.
  • Level 4: Reference equality / joining. If you receive a set of capabilities from different parties which should all point to the same underlying objects, you can verify securely that they in fact do. This is subtle, but enables many security patterns that rely on one party being able to verify that two or more other parties agree on something (imagine a digital escrow agent). See E’s page on equality.

目前GO只支持Level 1的特性,Level3的RPC特性已经在安排

下面整理其在Windows环境下的编译环境搭建步骤。

编译器

下载Windows32的编译包 (可能不是最新,可以从官网安装介绍 获取最新)。将 capnp.exe, capnpc-c++.exe, 和capnpc-capnp.exe加入系统环境变量,推荐解压到%GOPATH%.

然后安装GO的proto生成工具

go install capnproto.org/go/capnp/v3/capnpc-go@latest 

Annotations 包

目前Cap’n proto 的 Annotations是放入到代码仓库的,因为新版Go默认是启用了GOMODULE的,所以,需要按下面操作将仓库拉取到%GOPATH%.

go env -w GO111MODULE=off
go get -u capnproto.org/go/capnp/v3/
go env -w GO111MODULE=on

编译验证

一般模型

books.capnp文件

using Go = import "/go.capnp";
@0x85d3acc39d94e0f8;
$Go.package("books");
$Go.import("foo/books");

struct Book {
    title @0 :Text;
    # Title of the book.

    pageCount @1 :Int32;
    # Number of pages in the book.
}

编译

capnp compile -I %GOPATH%/src/capnproto.org/go/capnp/std -ogo:.. .\books.capnp

生成文件books.capnp.go

// Code generated by capnpc-go. DO NOT EDIT.

package books

import (
	capnp "capnproto.org/go/capnp/v3"
	text "capnproto.org/go/capnp/v3/encoding/text"
	schemas "capnproto.org/go/capnp/v3/schemas"
)

type Book struct{ capnp.Struct }

// Book_TypeID is the unique identifier for the type Book.
const Book_TypeID = 0x8100cc88d7d4d47c

func NewBook(s *capnp.Segment) (Book, error) {
	st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 1})
	return Book{st}, err
}

func NewRootBook(s *capnp.Segment) (Book, error) {
	st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 1})
	return Book{st}, err
}

func ReadRootBook(msg *capnp.Message) (Book, error) {
	root, err := msg.Root()
	return Book{root.Struct()}, err
}

func (s Book) String() string {
	str, _ := text.Marshal(0x8100cc88d7d4d47c, s.Struct)
	return str
}

func (s Book) Title() (string, error) {
	p, err := s.Struct.Ptr(0)
	return p.Text(), err
}

func (s Book) HasTitle() bool {
	return s.Struct.HasPtr(0)
}

func (s Book) TitleBytes() ([]byte, error) {
	p, err := s.Struct.Ptr(0)
	return p.TextBytes(), err
}

func (s Book) SetTitle(v string) error {
	return s.Struct.SetText(0, v)
}

func (s Book) PageCount() int32 {
	return int32(s.Struct.Uint32(0))
}

func (s Book) SetPageCount(v int32) {
	s.Struct.SetUint32(0, uint32(v))
}

// Book_List is a list of Book.
type Book_List = capnp.StructList[Book]

// NewBook creates a new list of Book.
func NewBook_List(s *capnp.Segment, sz int32) (Book_List, error) {
	l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 8, PointerCount: 1}, sz)
	return capnp.StructList[Book]{List: l}, err
}

// Book_Future is a wrapper for a Book promised by a client call.
type Book_Future struct{ *capnp.Future }

func (p Book_Future) Struct() (Book, error) {
	s, err := p.Future.Struct()
	return Book{s}, err
}

const schema_85d3acc39d94e0f8 = "x\xda\x12Ht`1\xe4\xdd\xcf\xc8\xc0\x14(\xc2\xca" +
	"\xb6\xbf\xe6\xca\x95\xeb\x1dg\x1a\x03y\x18\x19\xff\xffx" +
	"0e\xee\xe15\x97[\x19X\x19\xd9\x19\x18\x04\x8fv" +
	"\x09\x9e\x05\xd1'\xcb\x19t\xff'\xe5\xe7g\x17\xeb%" +
	"'2\x16\xe4\x15X9\xe5\xe7g30\x0402\x06" +
	"r0\xb300\xb0020\x08j\x1a10\x04\xaa" +
	"03\x06\x1a0122\x8a0\x82\xc4t\x83\x18\x18" +
	"\x02u\x98\x19\x03-\x98\x18\xe5K2KrR\x19y" +
	"\x18\x98\x18y\x18\x18\xff\x17$\xa6\xa7:\xe7\x97\xe61" +
	"0\x960\xb2001\xb200\x02\x02\x00\x00\xff\xff" +
	"N\xd3$\xbc"

func init() {
	schemas.Register(schema_85d3acc39d94e0f8,
		0x8100cc88d7d4d47c)
}

序列化与反序列化参考官方GitHub https://github.com/capnproto/go-capnproto2/wiki/Getting-Started

服务

定义接口 hash.capnp

using Go = import "/go.capnp";
@0xdb8274f9144abc7e;
$Go.package("hashes");
$Go.import("foo/hashes");

interface HashFactory {
    newSha1 @0 () -> (hash :Hash);
}

interface Hash {
    write @0 (data :Data) -> ();
    sum @1 () -> (hash :Data);
}

编译

capnp compile -I %GOPATH%/src/capnproto.org/go/capnp/std -ogo:.. .\hash.capnp

生成的GO文件内容

// Code generated by capnpc-go. DO NOT EDIT.

package hashes

import (
	capnp "capnproto.org/go/capnp/v3"
	text "capnproto.org/go/capnp/v3/encoding/text"
	schemas "capnproto.org/go/capnp/v3/schemas"
	server "capnproto.org/go/capnp/v3/server"
	context "context"
)

type HashFactory struct{ Client *capnp.Client }

// HashFactory_TypeID is the unique identifier for the type HashFactory.
const HashFactory_TypeID = 0xaead580f97fddabc

func (c HashFactory) NewSha1(ctx context.Context, params func(HashFactory_newSha1_Params) error) (HashFactory_newSha1_Results_Future, capnp.ReleaseFunc) {
	s := capnp.Send{
		Method: capnp.Method{
			InterfaceID:   0xaead580f97fddabc,
			MethodID:      0,
			InterfaceName: "remote.capnp:HashFactory",
			MethodName:    "newSha1",
		},
	}
	if params != nil {
		s.ArgsSize = capnp.ObjectSize{DataSize: 0, PointerCount: 0}
		s.PlaceArgs = func(s capnp.Struct) error { return params(HashFactory_newSha1_Params{Struct: s}) }
	}
	ans, release := c.Client.SendCall(ctx, s)
	return HashFactory_newSha1_Results_Future{Future: ans.Future()}, release
}

func (c HashFactory) AddRef() HashFactory {
	return HashFactory{
		Client: c.Client.AddRef(),
	}
}

func (c HashFactory) Release() {
	c.Client.Release()
}

// A HashFactory_Server is a HashFactory with a local implementation.
type HashFactory_Server interface {
	NewSha1(context.Context, HashFactory_newSha1) error
}

// HashFactory_NewServer creates a new Server from an implementation of HashFactory_Server.
func HashFactory_NewServer(s HashFactory_Server, policy *server.Policy) *server.Server {
	c, _ := s.(server.Shutdowner)
	return server.New(HashFactory_Methods(nil, s), s, c, policy)
}

// HashFactory_ServerToClient creates a new Client from an implementation of HashFactory_Server.
// The caller is responsible for calling Release on the returned Client.
func HashFactory_ServerToClient(s HashFactory_Server, policy *server.Policy) HashFactory {
	return HashFactory{Client: capnp.NewClient(HashFactory_NewServer(s, policy))}
}

// HashFactory_Methods appends Methods to a slice that invoke the methods on s.
// This can be used to create a more complicated Server.
func HashFactory_Methods(methods []server.Method, s HashFactory_Server) []server.Method {
	if cap(methods) == 0 {
		methods = make([]server.Method, 0, 1)
	}

	methods = append(methods, server.Method{
		Method: capnp.Method{
			InterfaceID:   0xaead580f97fddabc,
			MethodID:      0,
			InterfaceName: "remote.capnp:HashFactory",
			MethodName:    "newSha1",
		},
		Impl: func(ctx context.Context, call *server.Call) error {
			return s.NewSha1(ctx, HashFactory_newSha1{call})
		},
	})

	return methods
}

// HashFactory_newSha1 holds the state for a server call to HashFactory.newSha1.
// See server.Call for documentation.
type HashFactory_newSha1 struct {
	*server.Call
}

// Args returns the call's arguments.
func (c HashFactory_newSha1) Args() HashFactory_newSha1_Params {
	return HashFactory_newSha1_Params{Struct: c.Call.Args()}
}

// AllocResults allocates the results struct.
func (c HashFactory_newSha1) AllocResults() (HashFactory_newSha1_Results, error) {
	r, err := c.Call.AllocResults(capnp.ObjectSize{DataSize: 0, PointerCount: 1})
	return HashFactory_newSha1_Results{Struct: r}, err
}

type HashFactory_newSha1_Params struct{ capnp.Struct }

// HashFactory_newSha1_Params_TypeID is the unique identifier for the type HashFactory_newSha1_Params.
const HashFactory_newSha1_Params_TypeID = 0x92b20ad1a58ca0ca

func NewHashFactory_newSha1_Params(s *capnp.Segment) (HashFactory_newSha1_Params, error) {
	st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 0})
	return HashFactory_newSha1_Params{st}, err
}

func NewRootHashFactory_newSha1_Params(s *capnp.Segment) (HashFactory_newSha1_Params, error) {
	st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 0})
	return HashFactory_newSha1_Params{st}, err
}

func ReadRootHashFactory_newSha1_Params(msg *capnp.Message) (HashFactory_newSha1_Params, error) {
	root, err := msg.Root()
	return HashFactory_newSha1_Params{root.Struct()}, err
}

func (s HashFactory_newSha1_Params) String() string {
	str, _ := text.Marshal(0x92b20ad1a58ca0ca, s.Struct)
	return str
}

// HashFactory_newSha1_Params_List is a list of HashFactory_newSha1_Params.
type HashFactory_newSha1_Params_List = capnp.StructList[HashFactory_newSha1_Params]

// NewHashFactory_newSha1_Params creates a new list of HashFactory_newSha1_Params.
func NewHashFactory_newSha1_Params_List(s *capnp.Segment, sz int32) (HashFactory_newSha1_Params_List, error) {
	l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 0}, sz)
	return capnp.StructList[HashFactory_newSha1_Params]{List: l}, err
}

// HashFactory_newSha1_Params_Future is a wrapper for a HashFactory_newSha1_Params promised by a client call.
type HashFactory_newSha1_Params_Future struct{ *capnp.Future }

func (p HashFactory_newSha1_Params_Future) Struct() (HashFactory_newSha1_Params, error) {
	s, err := p.Future.Struct()
	return HashFactory_newSha1_Params{s}, err
}

type HashFactory_newSha1_Results struct{ capnp.Struct }

// HashFactory_newSha1_Results_TypeID is the unique identifier for the type HashFactory_newSha1_Results.
const HashFactory_newSha1_Results_TypeID = 0xea3e50f7663f7bdf

func NewHashFactory_newSha1_Results(s *capnp.Segment) (HashFactory_newSha1_Results, error) {
	st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1})
	return HashFactory_newSha1_Results{st}, err
}

func NewRootHashFactory_newSha1_Results(s *capnp.Segment) (HashFactory_newSha1_Results, error) {
	st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1})
	return HashFactory_newSha1_Results{st}, err
}

func ReadRootHashFactory_newSha1_Results(msg *capnp.Message) (HashFactory_newSha1_Results, error) {
	root, err := msg.Root()
	return HashFactory_newSha1_Results{root.Struct()}, err
}

func (s HashFactory_newSha1_Results) String() string {
	str, _ := text.Marshal(0xea3e50f7663f7bdf, s.Struct)
	return str
}

func (s HashFactory_newSha1_Results) Hash() Hash {
	p, _ := s.Struct.Ptr(0)
	return Hash{Client: p.Interface().Client()}
}

func (s HashFactory_newSha1_Results) HasHash() bool {
	return s.Struct.HasPtr(0)
}

func (s HashFactory_newSha1_Results) SetHash(v Hash) error {
	if !v.Client.IsValid() {
		return s.Struct.SetPtr(0, capnp.Ptr{})
	}
	seg := s.Segment()
	in := capnp.NewInterface(seg, seg.Message().AddCap(v.Client))
	return s.Struct.SetPtr(0, in.ToPtr())
}

// HashFactory_newSha1_Results_List is a list of HashFactory_newSha1_Results.
type HashFactory_newSha1_Results_List = capnp.StructList[HashFactory_newSha1_Results]

// NewHashFactory_newSha1_Results creates a new list of HashFactory_newSha1_Results.
func NewHashFactory_newSha1_Results_List(s *capnp.Segment, sz int32) (HashFactory_newSha1_Results_List, error) {
	l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}, sz)
	return capnp.StructList[HashFactory_newSha1_Results]{List: l}, err
}

// HashFactory_newSha1_Results_Future is a wrapper for a HashFactory_newSha1_Results promised by a client call.
type HashFactory_newSha1_Results_Future struct{ *capnp.Future }

func (p HashFactory_newSha1_Results_Future) Struct() (HashFactory_newSha1_Results, error) {
	s, err := p.Future.Struct()
	return HashFactory_newSha1_Results{s}, err
}

func (p HashFactory_newSha1_Results_Future) Hash() Hash {
	return Hash{Client: p.Future.Field(0, nil).Client()}
}

type Hash struct{ Client *capnp.Client }

// Hash_TypeID is the unique identifier for the type Hash.
const Hash_TypeID = 0xf29f97dd675a9431

func (c Hash) Write(ctx context.Context, params func(Hash_write_Params) error) (Hash_write_Results_Future, capnp.ReleaseFunc) {
	s := capnp.Send{
		Method: capnp.Method{
			InterfaceID:   0xf29f97dd675a9431,
			MethodID:      0,
			InterfaceName: "remote.capnp:Hash",
			MethodName:    "write",
		},
	}
	if params != nil {
		s.ArgsSize = capnp.ObjectSize{DataSize: 0, PointerCount: 1}
		s.PlaceArgs = func(s capnp.Struct) error { return params(Hash_write_Params{Struct: s}) }
	}
	ans, release := c.Client.SendCall(ctx, s)
	return Hash_write_Results_Future{Future: ans.Future()}, release
}
func (c Hash) Sum(ctx context.Context, params func(Hash_sum_Params) error) (Hash_sum_Results_Future, capnp.ReleaseFunc) {
	s := capnp.Send{
		Method: capnp.Method{
			InterfaceID:   0xf29f97dd675a9431,
			MethodID:      1,
			InterfaceName: "remote.capnp:Hash",
			MethodName:    "sum",
		},
	}
	if params != nil {
		s.ArgsSize = capnp.ObjectSize{DataSize: 0, PointerCount: 0}
		s.PlaceArgs = func(s capnp.Struct) error { return params(Hash_sum_Params{Struct: s}) }
	}
	ans, release := c.Client.SendCall(ctx, s)
	return Hash_sum_Results_Future{Future: ans.Future()}, release
}

func (c Hash) AddRef() Hash {
	return Hash{
		Client: c.Client.AddRef(),
	}
}

func (c Hash) Release() {
	c.Client.Release()
}

// A Hash_Server is a Hash with a local implementation.
type Hash_Server interface {
	Write(context.Context, Hash_write) error

	Sum(context.Context, Hash_sum) error
}

// Hash_NewServer creates a new Server from an implementation of Hash_Server.
func Hash_NewServer(s Hash_Server, policy *server.Policy) *server.Server {
	c, _ := s.(server.Shutdowner)
	return server.New(Hash_Methods(nil, s), s, c, policy)
}

// Hash_ServerToClient creates a new Client from an implementation of Hash_Server.
// The caller is responsible for calling Release on the returned Client.
func Hash_ServerToClient(s Hash_Server, policy *server.Policy) Hash {
	return Hash{Client: capnp.NewClient(Hash_NewServer(s, policy))}
}

// Hash_Methods appends Methods to a slice that invoke the methods on s.
// This can be used to create a more complicated Server.
func Hash_Methods(methods []server.Method, s Hash_Server) []server.Method {
	if cap(methods) == 0 {
		methods = make([]server.Method, 0, 2)
	}

	methods = append(methods, server.Method{
		Method: capnp.Method{
			InterfaceID:   0xf29f97dd675a9431,
			MethodID:      0,
			InterfaceName: "remote.capnp:Hash",
			MethodName:    "write",
		},
		Impl: func(ctx context.Context, call *server.Call) error {
			return s.Write(ctx, Hash_write{call})
		},
	})

	methods = append(methods, server.Method{
		Method: capnp.Method{
			InterfaceID:   0xf29f97dd675a9431,
			MethodID:      1,
			InterfaceName: "remote.capnp:Hash",
			MethodName:    "sum",
		},
		Impl: func(ctx context.Context, call *server.Call) error {
			return s.Sum(ctx, Hash_sum{call})
		},
	})

	return methods
}

// Hash_write holds the state for a server call to Hash.write.
// See server.Call for documentation.
type Hash_write struct {
	*server.Call
}

// Args returns the call's arguments.
func (c Hash_write) Args() Hash_write_Params {
	return Hash_write_Params{Struct: c.Call.Args()}
}

// AllocResults allocates the results struct.
func (c Hash_write) AllocResults() (Hash_write_Results, error) {
	r, err := c.Call.AllocResults(capnp.ObjectSize{DataSize: 0, PointerCount: 0})
	return Hash_write_Results{Struct: r}, err
}

// Hash_sum holds the state for a server call to Hash.sum.
// See server.Call for documentation.
type Hash_sum struct {
	*server.Call
}

// Args returns the call's arguments.
func (c Hash_sum) Args() Hash_sum_Params {
	return Hash_sum_Params{Struct: c.Call.Args()}
}

// AllocResults allocates the results struct.
func (c Hash_sum) AllocResults() (Hash_sum_Results, error) {
	r, err := c.Call.AllocResults(capnp.ObjectSize{DataSize: 0, PointerCount: 1})
	return Hash_sum_Results{Struct: r}, err
}

type Hash_write_Params struct{ capnp.Struct }

// Hash_write_Params_TypeID is the unique identifier for the type Hash_write_Params.
const Hash_write_Params_TypeID = 0xdffe94ae546cdee3

func NewHash_write_Params(s *capnp.Segment) (Hash_write_Params, error) {
	st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1})
	return Hash_write_Params{st}, err
}

func NewRootHash_write_Params(s *capnp.Segment) (Hash_write_Params, error) {
	st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1})
	return Hash_write_Params{st}, err
}

func ReadRootHash_write_Params(msg *capnp.Message) (Hash_write_Params, error) {
	root, err := msg.Root()
	return Hash_write_Params{root.Struct()}, err
}

func (s Hash_write_Params) String() string {
	str, _ := text.Marshal(0xdffe94ae546cdee3, s.Struct)
	return str
}

func (s Hash_write_Params) Data() ([]byte, error) {
	p, err := s.Struct.Ptr(0)
	return []byte(p.Data()), err
}

func (s Hash_write_Params) HasData() bool {
	return s.Struct.HasPtr(0)
}

func (s Hash_write_Params) SetData(v []byte) error {
	return s.Struct.SetData(0, v)
}

// Hash_write_Params_List is a list of Hash_write_Params.
type Hash_write_Params_List = capnp.StructList[Hash_write_Params]

// NewHash_write_Params creates a new list of Hash_write_Params.
func NewHash_write_Params_List(s *capnp.Segment, sz int32) (Hash_write_Params_List, error) {
	l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}, sz)
	return capnp.StructList[Hash_write_Params]{List: l}, err
}

// Hash_write_Params_Future is a wrapper for a Hash_write_Params promised by a client call.
type Hash_write_Params_Future struct{ *capnp.Future }

func (p Hash_write_Params_Future) Struct() (Hash_write_Params, error) {
	s, err := p.Future.Struct()
	return Hash_write_Params{s}, err
}

type Hash_write_Results struct{ capnp.Struct }

// Hash_write_Results_TypeID is the unique identifier for the type Hash_write_Results.
const Hash_write_Results_TypeID = 0x80ac741ec7fb8f65

func NewHash_write_Results(s *capnp.Segment) (Hash_write_Results, error) {
	st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 0})
	return Hash_write_Results{st}, err
}

func NewRootHash_write_Results(s *capnp.Segment) (Hash_write_Results, error) {
	st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 0})
	return Hash_write_Results{st}, err
}

func ReadRootHash_write_Results(msg *capnp.Message) (Hash_write_Results, error) {
	root, err := msg.Root()
	return Hash_write_Results{root.Struct()}, err
}

func (s Hash_write_Results) String() string {
	str, _ := text.Marshal(0x80ac741ec7fb8f65, s.Struct)
	return str
}

// Hash_write_Results_List is a list of Hash_write_Results.
type Hash_write_Results_List = capnp.StructList[Hash_write_Results]

// NewHash_write_Results creates a new list of Hash_write_Results.
func NewHash_write_Results_List(s *capnp.Segment, sz int32) (Hash_write_Results_List, error) {
	l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 0}, sz)
	return capnp.StructList[Hash_write_Results]{List: l}, err
}

// Hash_write_Results_Future is a wrapper for a Hash_write_Results promised by a client call.
type Hash_write_Results_Future struct{ *capnp.Future }

func (p Hash_write_Results_Future) Struct() (Hash_write_Results, error) {
	s, err := p.Future.Struct()
	return Hash_write_Results{s}, err
}

type Hash_sum_Params struct{ capnp.Struct }

// Hash_sum_Params_TypeID is the unique identifier for the type Hash_sum_Params.
const Hash_sum_Params_TypeID = 0xe74bb2d0190cf89c

func NewHash_sum_Params(s *capnp.Segment) (Hash_sum_Params, error) {
	st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 0})
	return Hash_sum_Params{st}, err
}

func NewRootHash_sum_Params(s *capnp.Segment) (Hash_sum_Params, error) {
	st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 0})
	return Hash_sum_Params{st}, err
}

func ReadRootHash_sum_Params(msg *capnp.Message) (Hash_sum_Params, error) {
	root, err := msg.Root()
	return Hash_sum_Params{root.Struct()}, err
}

func (s Hash_sum_Params) String() string {
	str, _ := text.Marshal(0xe74bb2d0190cf89c, s.Struct)
	return str
}

// Hash_sum_Params_List is a list of Hash_sum_Params.
type Hash_sum_Params_List = capnp.StructList[Hash_sum_Params]

// NewHash_sum_Params creates a new list of Hash_sum_Params.
func NewHash_sum_Params_List(s *capnp.Segment, sz int32) (Hash_sum_Params_List, error) {
	l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 0}, sz)
	return capnp.StructList[Hash_sum_Params]{List: l}, err
}

// Hash_sum_Params_Future is a wrapper for a Hash_sum_Params promised by a client call.
type Hash_sum_Params_Future struct{ *capnp.Future }

func (p Hash_sum_Params_Future) Struct() (Hash_sum_Params, error) {
	s, err := p.Future.Struct()
	return Hash_sum_Params{s}, err
}

type Hash_sum_Results struct{ capnp.Struct }

// Hash_sum_Results_TypeID is the unique identifier for the type Hash_sum_Results.
const Hash_sum_Results_TypeID = 0xd093963b95a4e107

func NewHash_sum_Results(s *capnp.Segment) (Hash_sum_Results, error) {
	st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1})
	return Hash_sum_Results{st}, err
}

func NewRootHash_sum_Results(s *capnp.Segment) (Hash_sum_Results, error) {
	st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1})
	return Hash_sum_Results{st}, err
}

func ReadRootHash_sum_Results(msg *capnp.Message) (Hash_sum_Results, error) {
	root, err := msg.Root()
	return Hash_sum_Results{root.Struct()}, err
}

func (s Hash_sum_Results) String() string {
	str, _ := text.Marshal(0xd093963b95a4e107, s.Struct)
	return str
}

func (s Hash_sum_Results) Hash() ([]byte, error) {
	p, err := s.Struct.Ptr(0)
	return []byte(p.Data()), err
}

func (s Hash_sum_Results) HasHash() bool {
	return s.Struct.HasPtr(0)
}

func (s Hash_sum_Results) SetHash(v []byte) error {
	return s.Struct.SetData(0, v)
}

// Hash_sum_Results_List is a list of Hash_sum_Results.
type Hash_sum_Results_List = capnp.StructList[Hash_sum_Results]

// NewHash_sum_Results creates a new list of Hash_sum_Results.
func NewHash_sum_Results_List(s *capnp.Segment, sz int32) (Hash_sum_Results_List, error) {
	l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}, sz)
	return capnp.StructList[Hash_sum_Results]{List: l}, err
}

// Hash_sum_Results_Future is a wrapper for a Hash_sum_Results promised by a client call.
type Hash_sum_Results_Future struct{ *capnp.Future }

func (p Hash_sum_Results_Future) Struct() (Hash_sum_Results, error) {
	s, err := p.Future.Struct()
	return Hash_sum_Results{s}, err
}

const schema_db8274f9144abc7e = "x\xda|\x92?h\x14A\x18\xc5\xdf\x9b\x9bu\xe3\x9f" +
	"\xe5\x18'\x16\xd7\x18\x91\x0b\x82\xc8\xe1\x19,T\xf4\x8e" +
	"\x14*\xb1\xd9\x8d\x16b7\xc4\xd5\x15rI\xb8\xdd#" +
	"\x88\xa0b#\x82 \xc4h\x1aA\x0b\xed4E\xea\xb4" +
	"\"\x04\x84\xa4U\xce\x10,\x84\x94\x01\xd1(\xba\xb2{" +
	"\xeem@/\xdd\xc2\x9b\xef}\xbf\xef\xed;\xc0\xba\xac" +
	":\x87$\x84w\xd4\xda\x11\xfb\x8f~\xbe\xdb\x1f\xbd\xbe" +
	"\x0b\xb5\x97\x80\xb4\x81\xa1M\x0aB\xc6K/\x1e\xbeZ" +
	"\xd9\xb50\x03U\xca\x946\x87\x13e\xf1\xc3\xaf\xb9\xe2" +
	"\xe57\xf3PN!\xbe\xbd8\xd2\xbf\x19\xdd\xfb\x08P" +
	"\xbf\xe5\x92^\xa1\x0d\xe8\xf7<\xa7\xbf&_\xb1\xbd\xf6" +
	"\xf2\xc9\xa9\xa7\x8f\x97;\x0b\xacTms\x03\xd4k\xac" +
	"\x81\xf1\xe7O\xe3\x97\xe6g\x7f\xafn\xd5)~\x80\xda" +
	"\x12\x89\xfe\xec\xfb\x9e\xd2\xf2\xc2\x85/9\xa0\x1e\x14\xeb" +
	"\x90\xf1\xea\xad\xda\xb5o\xee\x99\xf5\x0e_:8\xb4S" +
	"\x8c\x10\xd4\xfb\xd2\xc9\xea\xec\x95\xeb\xed\xb9\xe7\x1b\xff`" +
	"\x1e\x173\xfa\xb4H\x9cN\x88\xfb\xfa\x81\xb0q$n" +
	"\xfa\x8d\xc9\xc8\xaf\x8c\xed6S\x13S'\xcf\x9b0\xa8" +
	"L7oD~y\xd4\x0f[\xe3Q\x88\xecAW?" +
	"k\xc6\xa2\xc9\xe6\xcd\xca\x84?}10\xd5\xb2k\x9a" +
	"\xa6\xd1\xfb\x1d\xe0\x92\x9e,X@7Zf7(5" +
	"\x0c\xa1,\xfb\xce_\xb3:]\xb2\xcb$r\xa6\xb0\xd5" +
	"(\x8f\xfa\x03)\x92'\x0b\x12\x90\x04\x94s\x18\xf0\xfa" +
	"\x0a\xf4\xfa\x05\x8b\x81\x09\x03:\x10t\xf0_\x8f\xce]" +
	"\xb5\x0eo/\x93\xab&2\xdb\x99$ \xae)&\x16" +
	"]Y\xf6\xcc&\x0b\x11\xdb2\xab\xfc\x97\x81T[\x16" +
	"3sf\x90\xa4\xd8\x97\xa6\x985\x87Y\x87U\xf5\x18" +
	"\x84\x1a\xb4\x99\xb7\x86Y\xfdT\xe9 \x84r\xec\x81\xf4" +
	"\xfa:\xed\xb0\xd5HS\xfe\x13\x00\x00\xff\xff\xcf\xa2\xe6" +
	"\xb3"

func init() {
	schemas.Register(schema_db8274f9144abc7e,
		0x80ac741ec7fb8f65,
		0x92b20ad1a58ca0ca,
		0xaead580f97fddabc,
		0xd093963b95a4e107,
		0xdffe94ae546cdee3,
		0xe74bb2d0190cf89c,
		0xea3e50f7663f7bdf,
		0xf29f97dd675a9431)
}

客户端调用

func client(ctx context.Context, rwc io.ReadWriteCloser) error {
    // Create a connection that we can use to get the HashFactory.
    conn := rpc.NewConn(rpc.NewStreamTransport(rwc), nil) // nil sets default options
    defer conn.Close()

    // Get the "bootstrap" interface.  This is the capability set with
    // rpc.MainInterface on the remote side.
    hf := hashes.HashFactory{Client: conn.Bootstrap(ctx)}

    // Now we can call methods on hf, and they will be sent over c.
    // The NewSha1 method does not have any parameters we can set, so we
    // pass a nil function.
    f, free := hf.NewSha1(ctx, nil)
    defer free()

    // 'NewSha1' returns a future, which allows us to pipeline calls to
    // returned values before they are actually delivered.  Here, we issue
    // calls to an as-of-yet-unresolved Sha1 instance.
    s := f.Hash()

    // s refers to a remote Hash.  Method calls are delivered in order.
    f, free = s.Write(ctx, func(p hashes.Hash_write_Params) error {
        return p.SetData([]byte("Hello, "))
    })
    defer free()
    f, free = s.Write(ctx, func(p hashes.Hash_write_Params) error {
        return p.SetData([]byte("World!"))
    })
    defer free()

    // Get the sum, waiting for the result.
    f, free = s.Sum(ctx, nil)
    defer free()
    result, err := f.Struct()
    if err != nil {
        return err
    }

    // Display the result.
    sha1Val, err := result.Hash()
    if err != nil {
        return err
    }
    fmt.Printf("sha1: %x\n", sha1Val)
    return nil
}

func main() {
    ctx := context.Background()
    c1, c2 := net.Pipe()
    go serveHash(ctx, c1)
    client(ctx, c2)
}

参考链接