3 minutes
Network_grpc
准备
- client
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
address = "localhost:50051"
defaultName = "world"
)
func main() {
// Set up a connection to the server.
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
conn, err := grpc.DialContext(ctx, address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
// Contact the server and print out its response.
success(c)
}
func success(c pb.GreeterClient) {
name := defaultName
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
}
- server
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
port = ":50051"
)
// server is used to implement helloworld.GreeterServer.
type server struct {
pb.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
成功的响应
先启动server, 在启动client, 正常收发没问题
- client:
2020/09/19 13:14:19 Greeting: Hello world
- server
2020/09/19 13:14:19 Received: world
直连场景下, DialContext连接 ip不存在
只启动client, 不启动server
- client
2020/09/19 13:17:52 did not connect: context deadline exceeded
很明显, 通过context 能够及时得到结果, 连接层抽象直接失败
直连场景下, DialContext 成功, 但是 方法调用过程ip不存在
修改client端 success 代码替换成调用 notFound(), 如下:
func notFound(c pb.GreeterClient) {
log.Println("begin sleep")
time.Sleep(time.Second * 5) // 等待一段时间来保证server关闭
log.Println("after sleep")
name := defaultName
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
}
先启动server, 再启动client, 看到 begin sleep
, 立即关闭server. 得到:
- client:
2020/09/19 13:25:48 begin sleep
2020/09/19 13:25:53 after sleep
2020/09/19 13:25:53 could not greet: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp 127.0.0.1:50051: connect: connection refused"
可以发现, client 也理解失败了
直连场景下, DialContext 成功, 但是 方法调用过程ip 不是 http 协议: tcp
添加 tcp server:
package main
import (
"log"
"net"
"time"
)
func main() {
var l net.Listener
var err error
l, err = net.Listen("tcp", ":50051")
if err != nil {
log.Fatal("listen tcp failed")
}
defer l.Close()
log.Println("accept connection iterative")
for {
conn, err := l.Accept()
if err != nil {
log.Println("accept failed")
time.Sleep(5 * time.Second)
continue
}
go handle(conn)
}
}
func handle(conn net.Conn) {
defer conn.Close()
for {
//io.Copy(conn, conn)
log.Println("handler before")
time.Sleep(10 * time.Second)
log.Println("handler after")
return
}
}
这里用的是tcp协议, server 可以返回响应, 也可以进行连接数据的copy.
- 超时的case
client直接超时, client 日志如下:
2020/09/19 21:12:16 did not connect: context deadline exceeded
- 数据拷贝, 无效数据的场景
client 会重试 请求 server 三次, 最终超时; server端打印
2020/09/19 21:15:16 accept
2020/09/19 21:15:16 handler before
2020/09/19 21:15:16 handler after
2020/09/19 21:15:17 accept
2020/09/19 21:15:17 handler before
2020/09/19 21:15:17 handler after
2020/09/19 21:15:18 accept
2020/09/19 21:15:18 handler before
2020/09/19 21:15:18 handler after
直连场景下, DialContext 成功, 但是 方法调用过程ip 是 http 协议, 不是 http2
编辑http server:
package main
import (
"net/http"
"time"
)
func ServerHttp(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Second * 10)
}
func main() {
http.HandleFunc("/", ServerHttp)
http.ListenAndServe(":50051", nil)
}
直连场景下, DialContext 成功, 但是 方法调用过程ip 是 http2 协议, 不是 grpc
添加 http2 server,
package main
import (
"net/http"
"golang.org/x/net/http2"
)
func main() {
var srv *http.Server
srv.Addr = ":50051"
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("hello func"))
})
http2.ConfigureServer(srv, &http2.Server{})
srv.ListenAndServe()
}
client 依旧 deadline
2020/09/19 21:42:31 did not connect: context deadline exceeded