1
0
mirror of https://github.com/chai2010/advanced-go-programming-book.git synced 2025-05-24 12:32:21 +00:00

Merge branch 'master' into pr3-16

This commit is contained in:
wahaha 2018-06-28 16:19:18 +08:00 committed by GitHub
commit 09a44c3ae2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 2 deletions

View File

@ -17,7 +17,7 @@ TEXT symbol(SB), [flags,] $framesize[-argsize]
函数的定义部分由5个部分组成TEXT指令、函数名、可选的flags标志、函数帧大小和可选的函数参数大小。
其中Text用于定义函数符号,函数名中当前包的路径可以省略。函数的名字后面是`(SB)`表示是函数名符号相对于SB伪寄存器的偏移量二者组合在一起最终是绝对地址。作为全局的标识符的全局变量和全局函数的名字一般都是基于SB伪寄存器的相对地址。标志部分用于指示函数的一些特殊行为常见的NOSPLIT主要用于指示叶子函数不进行栈分裂。framesize部分表示函数的局部变量需要多少栈空间其中包含调用其它函数时准备调用参数的隐式栈空间。最后是可以省略的参数大小之所以可以省略是因为编译器可以从Go语言的函数声明中推导出函数参数的大小。
其中TEXT用于定义函数符号,函数名中当前包的路径可以省略。函数的名字后面是`(SB)`表示是函数名符号相对于SB伪寄存器的偏移量二者组合在一起最终是绝对地址。作为全局的标识符的全局变量和全局函数的名字一般都是基于SB伪寄存器的相对地址。标志部分用于指示函数的一些特殊行为常见的NOSPLIT主要用于指示叶子函数不进行栈分裂。framesize部分表示函数的局部变量需要多少栈空间其中包含调用其它函数时准备调用参数的隐式栈空间。最后是可以省略的参数大小之所以可以省略是因为编译器可以从Go语言的函数声明中推导出函数参数的大小。
下面是在main包中Add在汇编中两种定义方式
@ -31,7 +31,7 @@ TEXT ·Add(SB), $0
第一种是最完整的写法函数名部分包含了当前包的路径同时指明了函数的参数大小为24个字节对应参数和返回值的3个int类型。第二种写法则比较简洁省略了当前包的路径和参数的大小。需要注意的是标志参数中的NOSPLIT如果在Go语言函数声明中通过注释指明了标志应该也是可以省略的需要确认下
目前可能遇到的函数标志有NOSPLIT、WRAPPER和NEEDCTXT几个。其中NOSPLIT不会生成或包含栈分裂代码这一般用于没有任何其它函数调用的叶子函数这样可以适当提高性能。WRAPPER标志则表示这个是一个包装函数在panic或runtime.caller等某处理函数帧的地方不会增加函数帧计数。最后的NEEDCTXT表示需要一个上下文参数一般用于闭包函数。
目前可能遇到的函数标志有NOSPLIT、WRAPPER和NEEDCTXT几个。其中NOSPLIT不会生成或包含栈分裂代码这一般用于没有任何其它函数调用的叶子函数这样可以适当提高性能。WRAPPER标志则表示这个是一个包装函数在panic或runtime.caller等某处理函数帧的地方不会增加函数帧计数。最后的NEEDCTXT表示需要一个上下文参数一般用于闭包函数。
需要注意的是函数也没有类型上面定义的Add函数签名可以下面任意一种格式

View File

@ -0,0 +1,36 @@
package main
import (
"flag"
"fmt"
"log"
"net"
"net/rpc"
"net/rpc/jsonrpc"
)
var flagAddr = flag.String("addr", "localhost:1234", "server address")
func main() {
flag.Parse()
// nc localhost 1234
// {"method":"HelloService.Hello","params":["hello"],"id":0}
// echo -e '{"method":"HelloService.Hello","params":["hello2222"],"id":3}' | nc localhost 1234
// echo -e '{"method":"HelloService.Hello","params":["hello2222"],"id":3}{"method":"HelloService.Hello","params":["hello33"],"id":4}' | nc localhost 1234
conn, err := net.Dial("tcp", *flagAddr)
if err != nil {
log.Fatal("net.Dial:", err)
}
client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn))
var reply string
err = client.Call("HelloService.Hello", "hello", &reply)
if err != nil {
log.Fatal(err)
}
fmt.Println(reply)
}

View File

@ -0,0 +1,40 @@
package main
import (
"flag"
"fmt"
"log"
"net"
"net/rpc"
"net/rpc/jsonrpc"
)
type HelloService struct{}
func (p *HelloService) Hello(request string, reply *string) error {
*reply = "hello:" + request
return nil
}
var flagPort = flag.Int("port", 1234, "listen port")
func main() {
flag.Parse()
rpc.RegisterName("HelloService", new(HelloService))
// nc -l 2399
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", *flagPort))
if err != nil {
log.Fatal("ListenTCP error:", err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal("Accept error:", err)
}
go rpc.ServeCodec(jsonrpc.NewServerCodec(conn))
}
}