https://github.com/apachecn-archive/qrpc

https://github.com/apachecn-archive/qrpc

Science Score: 13.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
  • DOI references
  • Academic publication links
  • Academic email domains
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (5.9%) to scientific vocabulary
Last synced: 9 months ago · JSON representation

Repository

Basic Info
  • Host: GitHub
  • Owner: apachecn-archive
  • Language: Go
  • Default Branch: master
  • Size: 9 MB
Statistics
  • Stars: 0
  • Watchers: 1
  • Forks: 0
  • Open Issues: 0
  • Releases: 0
Created about 3 years ago · Last pushed about 3 years ago
Metadata Files
Readme

README.en_US.md

qrpc, tiny but powerful rpc framework

qrpc makes it tremendously easy to to perform rpc by offering 4 core features:

  • blocking or nonblocking
  • streaming or nonstreaming
  • server push
  • overlay network (refer to ws/README.md for detail)

By default each frame is blocking and nonstreaming, this allows traditional block-in-header sequencial behaviour like http/1.1, but you can make it behave tremendously different by attach flags to your frames!


Enough talk, let's demo!

blocking mode

server.go:

```golang package main import "github.com/zhiqiangxu/qrpc"

const ( HelloCmd qrpc.Cmd = iota HelloRespCmd ) func main() { handler := qrpc.NewServeMux() handler.HandleFunc(HelloCmd, func(writer qrpc.FrameWriter, request *qrpc.RequestFrame) { writer.StartWrite(request.RequestID, HelloRespCmd, 0)

    writer.WriteBytes(append([]byte("hello world "), request.Payload...))
    writer.EndWrite()
})
bindings := []qrpc.ServerBinding{
    qrpc.ServerBinding{Addr: "0.0.0.0:8080", Handler: handler}}
server := qrpc.NewServer(bindings)
server.ListenAndServe()

}

```

client.go:

```golang package main import ( "fmt" "github.com/zhiqiangxu/qrpc" )

const ( HelloCmd qrpc.Cmd = iota ) func main() { conf := qrpc.ConnectionConfig{}

conn, _ := qrpc.NewConnection("0.0.0.0:8080", conf, nil)

_, resp, _ := conn.Request(HelloCmd, 0/*no flags*/, []byte("xu"))
frame, _ := resp.GetFrame()
fmt.Println("resp is", string(frame.Payload))

} ```

In the above example, server will process each client frames in sequence order.

Nonblocking mode

To use this mode we only need to change 1 line in client.go: diff - _, resp, _ := conn.Request(HelloCmd, 0/*no flags*/, []byte("xu")) + _, resp, _ := conn.Request(HelloCmd, qrpc.NBFlag, []byte("xu")) In this mode request frames will be processed concurrently!

stream mode

stream is like chunked transfer in http, besides, it's bidirectional, we can make either request or response in stream, or we can make both!

Make request in stream mode:

streamclient.go:

```golang package main import ( "fmt" "github.com/zhiqiangxu/qrpc" )

const ( HelloCmd qrpc.Cmd = iota ) func main() { conf := qrpc.ConnectionConfig{}

conn, _ := qrpc.NewConnection("0.0.0.0:8080", conf, nil)

writer, resp, _ := conn.StreamRequest(HelloCmd, 0, []byte("first frame"))
writer.StartWrite(HelloCmd)
writer.WriteBytes([]byte("last frame"))
writer.EndWrite(true) // will attach StreamEndFlag
frame, _ := resp.GetFrame()
fmt.Println("resp is", string(frame.Payload))

}

```

streamserver.go:

```golang package main import ( "github.com/zhiqiangxu/qrpc" "fmt" )

const ( HelloCmd qrpc.Cmd = iota HelloRespCmd ) func main() { handler := qrpc.NewServeMux() handler.HandleFunc(HelloCmd, func(writer qrpc.FrameWriter, request *qrpc.RequestFrame) { writer.StartWrite(request.RequestID, HelloRespCmd, 0)

    writer.WriteBytes(append([]byte("first frame "), request.Payload...))

    for {
        continueFrames := <-request.FrameCh()
        if continueFrames == nil {
            break
        }
        writer.WriteBytes(append([]byte(" continue frame "), continueFrames.Payload...))
    }
    writer.EndWrite()
})
bindings := []qrpc.ServerBinding{
    qrpc.ServerBinding{Addr: "0.0.0.0:8080", Handler: handler}}
server := qrpc.NewServer(bindings)
err := server.ListenAndServe()
if err != nil {
    panic(err)
}

} ```

In a similar fasion we can also make response in stream mode:

```golang package main import ( "github.com/zhiqiangxu/qrpc" "fmt" )

const ( HelloCmd qrpc.Cmd = iota HelloRespCmd ) func main() { handler := qrpc.NewServeMux() handler.HandleFunc(HelloCmd, func(writer qrpc.FrameWriter, request *qrpc.RequestFrame) { writer.StartWrite(request.RequestID, HelloRespCmd, qrpc.StreamFlag) writer.WriteBytes(append([]byte("first frame "), request.Payload...)) writer.EndWrite()

    for {
        continueFrames := <-request.FrameCh()
        if continueFrames == nil {
            break
        }

        fmt.Printf("%s\n", continueFrames.Payload)
        if continueFrames.Flags.IsDone() {
            // it's the last frame,so flag it with qrpc.StreamEndFlag
            writer.StartWrite(request.RequestID, HelloRespCmd, qrpc.StreamEndFlag)
        } else {
            // no the last frame,just flag it with qrpc.StreamFlag
            writer.StartWrite(request.RequestID, HelloRespCmd, qrpc.StreamFlag)
        }
        writer.WriteBytes(append([]byte(" continue frame "), continueFrames.Payload...))
        writer.EndWrite()
    }
})
bindings := []qrpc.ServerBinding{
    qrpc.ServerBinding{Addr: "0.0.0.0:8080", Handler: handler}}
server := qrpc.NewServer(bindings)
err := server.ListenAndServe()
if err != nil {
    panic(err)
}

} ```

The key is StreamFlag!

push mode

```golang package main import ( "github.com/zhiqiangxu/qrpc" "github.com/zhiqiangxu/util" "sync" )

const ( HelloCmd qrpc.Cmd = iota HelloRespCmd ) func main() { handler := qrpc.NewServeMux() handler.HandleFunc(HelloCmd, func(writer qrpc.FrameWriter, request *qrpc.RequestFrame) { var ( wg sync.WaitGroup ) qserver := request.ConnectionInfo().Server() pushID := qserver.GetPushID() qserver.WalkConn(0, func(writer qrpc.FrameWriter, ci *qrpc.ConnectionInfo) bool { util.GoFunc(&wg, func() { writer.StartWrite(pushID, HelloCmd, qrpc.PushFlag) writer.WriteBytes([]byte("pushed msg")) writer.EndWrite() }) return true }) wg.Wait()

    writer.StartWrite(request.RequestID, HelloRespCmd, 0)
    writer.WriteBytes(append([]byte("push done"), request.Payload...))
    writer.EndWrite()
})
bindings := []qrpc.ServerBinding{
    qrpc.ServerBinding{Addr: "0.0.0.0:8080", Handler: handler}}
server := qrpc.NewServer(bindings)
err := server.ListenAndServe()
if err != nil {
    panic(err)
}

} ```

In the above example, server will push a message to all connections !

To handle pushed message, the relevant change at client side is:

diff - conn, _ := qrpc.NewConnection("0.0.0.0:8080", conf, nil) + conn, _ := qrpc.NewConnection("0.0.0.0:8080", conf, func(conn *qrpc.Connection, pushedFrame *qrpc.Frame) { + fmt.Println(pushedFrame) + })

There are even more features like StreamRstFlag!

Performance

avatar

About 4 times faster than http!

Stargazers

Stargazers over time

Owner

  • Name: ApacheCN 归档
  • Login: apachecn-archive
  • Kind: organization
  • Email: wizard.z@qq.com

防止重要项目丢失而设立的归档

GitHub Events

Total
Last Year

Dependencies

go.mod go
  • github.com/go-kit/kit v0.9.0
  • github.com/gogo/protobuf v1.3.1
  • github.com/gorilla/websocket v1.4.1
  • github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
  • github.com/modern-go/reflect2 v1.0.1
  • github.com/oklog/run v1.0.0
  • github.com/urfave/cli/v2 v2.2.0
  • github.com/zhiqiangxu/go-reuseport v0.2.1
  • github.com/zhiqiangxu/util v0.0.0-20200612094741-8e7a0d4b9665
  • go.uber.org/ratelimit v0.1.0
  • go.uber.org/zap v1.13.0
  • google.golang.org/grpc v1.26.0
  • gotest.tools/v3 v3.0.2
go.sum go
  • 167 dependencies