Giter Site home page Giter Site logo

andeya / erpc Goto Github PK

View Code? Open in Web Editor NEW
2.5K 137.0 407.0 17.4 MB

An efficient, extensible and easy-to-use RPC framework.

Home Page: https://andeya.github.io/erpc-book

License: Apache License 2.0

Go 99.74% Thrift 0.06% Makefile 0.20%
rpc microservice socket peer-to-peer protocol go

erpc's Introduction

eRPC

tag Go Version GoDoc Build Status Go report License

eRPC is an efficient, extensible and easy-to-use RPC framework.

Suitable for RPC, Microservice, Peer-to-Peer, IM, Game and other fields.

简体中文

eRPC-Framework

Install

  • go vesion ≥ 1.18

  • install

GO111MODULE=on go get -u -v -insecure github.com/andeya/erpc/v7
  • import
import "github.com/andeya/erpc/v7"

Feature

  • Use peer to provide the same API package for the server and client
  • Provide multi-layout abstractions such as:
    • peer
    • session/socket
    • router
    • handle/context
    • message
    • protocol
    • codec
    • transfer filter
    • plugin
  • Support reboot and shutdown gracefully
  • HTTP-compatible message format:
    • Composed of two parts, the Header and the Body
    • Header contains metadata in the same format as HTTP header
    • Body supports for custom codec of Content Type-Like, already implemented:
      • Protobuf
      • Thrift
      • JSON
      • XML
      • Form
      • Plain
    • Support push, call-reply and more message types
  • Support custom message protocol, and provide some common implementations:
    • rawproto - Default high performance binary protocol
    • jsonproto - JSON message protocol
    • pbproto - Ptotobuf message protocol
    • thriftproto - Thrift message protocol
    • httproto - HTTP message protocol
  • Optimized high performance transport layer
    • Use Non-block socket and I/O multiplexing technology
    • Support setting the size of socket I/O buffer
    • Support setting the size of the reading message (if exceed disconnect it)
    • Support controling the connection file descriptor
  • Support a variety of network types:
    • tcp
    • tcp4
    • tcp6
    • unix
    • unixpacket
    • kcp
    • quic
    • other
      • websocket
      • evio
  • Provide a rich plug-in point, and already implemented:
    • auth
    • binder
    • heartbeat
    • ignorecase(service method)
    • overloader
    • proxy(for unknown service method)
    • secure
  • Powerful and flexible logging system:
    • Detailed log information, support print input and output details
    • Support setting slow operation alarm threshold
    • Support for custom implementation log component
  • Client session support automatically redials after disconnection

Benchmark

Self Test

  • A server and a client process, running on the same machine

  • CPU: Intel Xeon E312xx (Sandy Bridge) 16 cores 2.53GHz

  • Memory: 16G

  • OS: Linux 2.6.32-696.16.1.el6.centos.plus.x86_64, CentOS 6.4

  • Go: 1.9.2

  • Message size: 581 bytes

  • Message codec: protobuf

  • Sent total 1000000 messages

  • erpc

client concurrency mean(ms) median(ms) max(ms) min(ms) throughput(TPS)
100 1 0 16 0 75505
500 9 11 97 0 52192
1000 19 24 187 0 50040
2000 39 54 409 0 42551
5000 96 128 1148 0 46367
  • erpc/socket
client concurrency mean(ms) median(ms) max(ms) min(ms) throughput(TPS)
100 0 0 14 0 225682
500 2 1 24 0 212630
1000 4 3 51 0 180733
2000 8 6 64 0 183351
5000 21 18 651 0 133886

Comparison Test

EnvironmentThroughputsMean LatencyP99 Latency

More Detail

  • Profile torch of erpc/socket

erpc_socket_profile_torch

svg file

  • Heap torch of erpc/socket

erpc_socket_heap_torch

svg file

Example

server.go

package main

import (
	"fmt"
	"time"

	"github.com/andeya/erpc/v7"
)

func main() {
	defer erpc.FlushLogger()
	// graceful
	go erpc.GraceSignal()

	// server peer
	srv := erpc.NewPeer(erpc.PeerConfig{
		CountTime:   true,
		ListenPort:  9090,
		PrintDetail: true,
	})
	// srv.SetTLSConfig(erpc.GenerateTLSConfigForServer())

	// router
	srv.RouteCall(new(Math))

	// broadcast per 5s
	go func() {
		for {
			time.Sleep(time.Second * 5)
			srv.RangeSession(func(sess erpc.Session) bool {
				sess.Push(
					"/push/status",
					fmt.Sprintf("this is a broadcast, server time: %v", time.Now()),
				)
				return true
			})
		}
	}()

	// listen and serve
	srv.ListenAndServe()
}

// Math handler
type Math struct {
	erpc.CallCtx
}

// Add handles addition request
func (m *Math) Add(arg *[]int) (int, *erpc.Status) {
	// test meta
	erpc.Infof("author: %s", m.PeekMeta("author"))
	// add
	var r int
	for _, a := range *arg {
		r += a
	}
	// response
	return r, nil
}

client.go

package main

import (
  "time"

  "github.com/andeya/erpc/v7"
)

func main() {
  defer erpc.SetLoggerLevel("ERROR")()

  cli := erpc.NewPeer(erpc.PeerConfig{})
  defer cli.Close()
  // cli.SetTLSConfig(&tls.Config{InsecureSkipVerify: true})

  cli.RoutePush(new(Push))

  sess, stat := cli.Dial(":9090")
  if !stat.OK() {
    erpc.Fatalf("%v", stat)
  }

  var result int
  stat = sess.Call("/math/add",
    []int{1, 2, 3, 4, 5},
    &result,
    erpc.WithAddMeta("author", "andeya"),
  ).Status()
  if !stat.OK() {
    erpc.Fatalf("%v", stat)
  }
  erpc.Printf("result: %d", result)
  erpc.Printf("Wait 10 seconds to receive the push...")
  time.Sleep(time.Second * 10)
}

// Push push handler
type Push struct {
  erpc.PushCtx
}

// Push handles '/push/status' message
func (p *Push) Status(arg *string) *erpc.Status {
  erpc.Printf("%s", *arg)
  return nil
}

More Examples

Usage

NOTE:

  • It is best to set the packet size when reading: SetReadLimit
  • The default packet size limit when reading is 1 GB

Peer(server or client) Demo

// Start a server
var peer1 = erpc.NewPeer(erpc.PeerConfig{
ListenPort: 9090, // for server role
})
peer1.Listen()

...

// Start a client
var peer2 = erpc.NewPeer(erpc.PeerConfig{})
var sess, err = peer2.Dial("127.0.0.1:8080")

Call-Struct API template

type Aaa struct {
    erpc.CallCtx
}
func (x *Aaa) XxZz(arg *<T>) (<T>, *erpc.Status) {
    ...
    return r, nil
}
  • register it to root router:
// register the call route
// HTTP mapping: /aaa/xx_zz
// RPC mapping: Aaa.XxZz
peer.RouteCall(new(Aaa))

// or register the call route
// HTTP mapping: /xx_zz
// RPC mapping: XxZz
peer.RouteCallFunc((*Aaa).XxZz)

Service method mapping

  • The default mapping(HTTPServiceMethodMapper) of struct(func) name to service methods:

    • AaBb -> /aa_bb
    • ABcXYz -> /abc_xyz
    • Aa__Bb -> /aa_bb
    • aa__bb -> /aa_bb
    • ABC__XYZ -> /abc_xyz
    • Aa_Bb -> /aa/bb
    • aa_bb -> /aa/bb
    • ABC_XYZ -> /abc/xyz
    erpc.SetServiceMethodMapper(erpc.HTTPServiceMethodMapper)
  • The mapping(RPCServiceMethodMapper) of struct(func) name to service methods:

    • AaBb -> AaBb
    • ABcXYz -> ABcXYz
    • Aa__Bb -> Aa_Bb
    • aa__bb -> aa_bb
    • ABC__XYZ -> ABC_XYZ
    • Aa_Bb -> Aa.Bb
    • aa_bb -> aa.bb
    • ABC_XYZ -> ABC.XYZ
    erpc.SetServiceMethodMapper(erpc.RPCServiceMethodMapper)

Call-Function API template

func XxZz(ctx erpc.CallCtx, arg *<T>) (<T>, *erpc.Status) {
    ...
    return r, nil
}
  • register it to root router:
// register the call route
// HTTP mapping: /xx_zz
// RPC mapping: XxZz
peer.RouteCallFunc(XxZz)

Push-Struct API template

type Bbb struct {
    erpc.PushCtx
}
func (b *Bbb) YyZz(arg *<T>) *erpc.Status {
    ...
    return nil
}
  • register it to root router:
// register the push handler
// HTTP mapping: /bbb/yy_zz
// RPC mapping: Bbb.YyZz
peer.RoutePush(new(Bbb))

// or register the push handler
// HTTP mapping: /yy_zz
// RPC mapping: YyZz
peer.RoutePushFunc((*Bbb).YyZz)

Push-Function API template

// YyZz register the handler
func YyZz(ctx erpc.PushCtx, arg *<T>) *erpc.Status {
    ...
    return nil
}
  • register it to root router:
// register the push handler
// HTTP mapping: /yy_zz
// RPC mapping: YyZz
peer.RoutePushFunc(YyZz)

Unknown-Call-Function API template

func XxxUnknownCall (ctx erpc.UnknownCallCtx) (interface{}, *erpc.Status) {
    ...
    return r, nil
}
  • register it to root router:
// register the unknown call route: /*
peer.SetUnknownCall(XxxUnknownCall)

Unknown-Push-Function API template

func XxxUnknownPush(ctx erpc.UnknownPushCtx) *erpc.Status {
    ...
    return nil
}
  • register it to root router:
// register the unknown push route: /*
peer.SetUnknownPush(XxxUnknownPush)

Plugin Demo

// NewIgnoreCase Returns a ignoreCase plugin.
func NewIgnoreCase() *ignoreCase {
    return &ignoreCase{}
}

type ignoreCase struct{}

var (
    _ erpc.PostReadCallHeaderPlugin = new(ignoreCase)
    _ erpc.PostReadPushHeaderPlugin = new(ignoreCase)
)

func (i *ignoreCase) Name() string {
    return "ignoreCase"
}

func (i *ignoreCase) PostReadCallHeader(ctx erpc.ReadCtx) *erpc.Status {
    // Dynamic transformation path is lowercase
    ctx.UriObject().Path = strings.ToLower(ctx.UriObject().Path)
    return nil
}

func (i *ignoreCase) PostReadPushHeader(ctx erpc.ReadCtx) *erpc.Status {
    // Dynamic transformation path is lowercase
    ctx.UriObject().Path = strings.ToLower(ctx.UriObject().Path)
    return nil
}

Register above handler and plugin

// add router group
group := peer.SubRoute("test")
// register to test group
group.RouteCall(new(Aaa), NewIgnoreCase())
peer.RouteCallFunc(XxZz, NewIgnoreCase())
group.RoutePush(new(Bbb))
peer.RoutePushFunc(YyZz)
peer.SetUnknownCall(XxxUnknownCall)
peer.SetUnknownPush(XxxUnknownPush)

Config

type PeerConfig struct {
    Network            string        `yaml:"network"              ini:"network"              comment:"Network; tcp, tcp4, tcp6, unix, unixpacket, kcp or quic"`
    LocalIP            string        `yaml:"local_ip"             ini:"local_ip"             comment:"Local IP"`
    ListenPort         uint16        `yaml:"listen_port"          ini:"listen_port"          comment:"Listen port; for server role"`
    DialTimeout time.Duration `yaml:"dial_timeout" ini:"dial_timeout" comment:"Default maximum duration for dialing; for client role; ns,µs,ms,s,m,h"`
    RedialTimes        int32         `yaml:"redial_times"         ini:"redial_times"         comment:"The maximum times of attempts to redial, after the connection has been unexpectedly broken; Unlimited when <0; for client role"`
	RedialInterval     time.Duration `yaml:"redial_interval"      ini:"redial_interval"      comment:"Interval of redialing each time, default 100ms; for client role; ns,µs,ms,s,m,h"`
    DefaultBodyCodec   string        `yaml:"default_body_codec"   ini:"default_body_codec"   comment:"Default body codec type id"`
    DefaultSessionAge  time.Duration `yaml:"default_session_age"  ini:"default_session_age"  comment:"Default session max age, if less than or equal to 0, no time limit; ns,µs,ms,s,m,h"`
    DefaultContextAge  time.Duration `yaml:"default_context_age"  ini:"default_context_age"  comment:"Default CALL or PUSH context max age, if less than or equal to 0, no time limit; ns,µs,ms,s,m,h"`
    SlowCometDuration  time.Duration `yaml:"slow_comet_duration"  ini:"slow_comet_duration"  comment:"Slow operation alarm threshold; ns,µs,ms,s ..."`
    PrintDetail        bool          `yaml:"print_detail"         ini:"print_detail"         comment:"Is print body and metadata or not"`
    CountTime          bool          `yaml:"count_time"           ini:"count_time"           comment:"Is count cost time or not"`
}

Optimize

  • SetMessageSizeLimit sets max message size. If maxSize<=0, set it to max uint32.

    func SetMessageSizeLimit(maxMessageSize uint32)
  • SetSocketKeepAlive sets whether the operating system should send keepalive messages on the connection.

    func SetSocketKeepAlive(keepalive bool)
  • SetSocketKeepAlivePeriod sets period between keep alives.

    func SetSocketKeepAlivePeriod(d time.Duration)
  • SetSocketNoDelay controls whether the operating system should delay message transmission in hopes of sending fewer messages (Nagle's algorithm). The default is true (no delay), meaning that data is sent as soon as possible after a Write.

    func SetSocketNoDelay(_noDelay bool)
  • SetSocketReadBuffer sets the size of the operating system's receive buffer associated with the connection.

    func SetSocketReadBuffer(bytes int)
  • SetSocketWriteBuffer sets the size of the operating system's transmit buffer associated with the connection.

    func SetSocketWriteBuffer(bytes int)

Extensions

Codec

package import description
json "github.com/andeya/erpc/v7/codec" JSON codec(erpc own)
protobuf "github.com/andeya/erpc/v7/codec" Protobuf codec(erpc own)
thrift "github.com/andeya/erpc/v7/codec" Form(url encode) codec(erpc own)
xml "github.com/andeya/erpc/v7/codec" Form(url encode) codec(erpc own)
plain "github.com/andeya/erpc/v7/codec" Plain text codec(erpc own)
form "github.com/andeya/erpc/v7/codec" Form(url encode) codec(erpc own)

Plugin

package import description
auth "github.com/andeya/erpc/v7/plugin/auth" An auth plugin for verifying peer at the first time
binder "github.com/andeya/erpc/v7/plugin/binder" Parameter Binding Verification for Struct Handler
heartbeat "github.com/andeya/erpc/v7/plugin/heartbeat" A generic timing heartbeat plugin
proxy "github.com/andeya/erpc/v7/plugin/proxy" A proxy plugin for handling unknown calling or pushing
secure "github.com/andeya/erpc/v7/plugin/secure" Encrypting/decrypting the message body
overloader "github.com/andeya/erpc/v7/plugin/overloader" A plugin to protect erpc from overload

Protocol

package import description
rawproto "github.com/andeya/erpc/v7/proto/rawproto A fast socket communication protocol(erpc default protocol)
jsonproto "github.com/andeya/erpc/v7/proto/jsonproto" A JSON socket communication protocol
pbproto "github.com/andeya/erpc/v7/proto/pbproto" A Protobuf socket communication protocol
thriftproto "github.com/andeya/erpc/v7/proto/thriftproto" A Thrift communication protocol
httproto "github.com/andeya/erpc/v7/proto/httproto" A HTTP style socket communication protocol

Transfer-Filter

package import description
gzip "github.com/andeya/erpc/v7/xfer/gzip" Gzip(erpc own)
md5 "github.com/andeya/erpc/v7/xfer/md5" Provides a integrity check transfer filter

Mixer

package import description
multiclient "github.com/andeya/erpc/v7/mixer/multiclient" Higher throughput client connection pool when transferring large messages (such as downloading files)
websocket "github.com/andeya/erpc/v7/mixer/websocket" Makes the eRPC framework compatible with websocket protocol as specified in RFC 6455
evio "github.com/andeya/erpc/v7/mixer/evio" A fast event-loop networking framework that uses the erpc API layer
html html "github.com/xiaoenai/tp-micro/helper/mod-html" HTML render for http client

Projects based on eRPC

project description
TP-Micro TP-Micro is a simple, powerful micro service framework based on eRPC
Pholcus Pholcus is a distributed, high concurrency and powerful web crawler software

Business Users

深圳市梦之舵信息技术有限公司    平安科技
北京风行在线技术有限公司    北京可即时代网络公司 快手短视频平台

License

eRPC is under Apache v2 License. See the LICENSE file for the full license text

erpc's People

Contributors

andeya avatar bnyu avatar deepziyu avatar fyyang avatar kevinma2010 avatar liu-jing-yao avatar lou-lan avatar mougecm avatar osgochina avatar panguncle avatar wgffgw avatar yangwenmai avatar yuhao5 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

erpc's Issues

AsyncPull 怎样从PullCmd 中获取session 信息?

有一组peer,对这组peer 发起一个异步的请求,并使用pingCmdChan 接受所有peer 返回的结果,问题是如何从返回的PullCmd 中获取session (即怎么确认结果是哪个peer 返回的)?
(ps: 是不是AsyncPull 不能这么用)

部分代码如下:

	pingCmdChan := make(chan tp.PullCmd, batch)
	for _, peer := range hub.others {
                ......
		peer.sess.AsyncPull(
			"/peer/ping",
			"ping",
			new(string),
			pingCmdChan,
		)
	}
        ......
	for pingCmd := range pingCmdChan {
		result, rerr := pingCmd.Reply()
                sess = pingCmd.XXXXX // ?
        }

关于sequence length

在说明文档中,sequence length是2bytes;
{2 bytes sequence length}
{sequence}

但在文件github.com/henrylee2cn/teleport/socket/protocol.go中sequence length是1bytes;
{1 bytes sequence length}
{sequence}
{1 byte message type} # e.g. CALL:1; REPLY:2; PUSH:3
{1 bytes service method length}
请问是以谁为准呢?还想请教一下seq的编码解码是怎么计算的呢.

go get 报错

go get -u -f github.com/henrylee2cn/erpc

github.com/henrylee2cn/erpc/quic

github.com\henrylee2cn\erpc\quic\quic.go:27:36: not enough arguments in call to sess.OpenStreamSync
have ()
want (context.Context)
github.com\henrylee2cn\erpc\quic\quic.go:96:27: not enough arguments in call to l.lis.Accept
have ()
want (context.Context)
github.com\henrylee2cn\erpc\quic\quic.go:100:34: not enough arguments in call to sess.AcceptStream
have ()
want (context.Context)

提个小小的建议

plugin/auth/auth.go下的Session的interface可以加个LocalAddr()嘛。。
因为在认证的时候有可能会用到,其他session也都带了这个方法,每次更新库了忘记改了就很尴尬。

handler处理panic了

这里是大致的实现:

https://gist.github.com/chenqinghe/cadea0fc76f545154204b4dab35a4bef

panic信息:

[2019/03/16 22:40:01.223] [PRIN] The current process PID: 2884
[2019/03/16 22:40:01.232] [PRIN] register CALL handler: /user/login
[2019/03/16 22:40:01.241] [PRIN] listen and serve (network:tcp, addr:[::]:9090)
[2019/03/16 22:40:12.296] [INFO] accept ok (network:tcp, addr:127.0.0.1:2964, id:127.0.0.1:2964)
[2019/03/16 22:40:12.297] [DEBU] panic:runtime error: invalid memory address or nil pointer dereference
........../server/manager.(*Manager).Add(0x0, 0x0, 0x0, 0xc000194080)
........../server/manager/manager.go:21 +0x2d
........../server/handler.(*User).Login(0xc000194000, 0xc00016b260, 0x0, 0x0, 0x0)
........../server/handler/user.go:20 +0x12b
reflect.Value.call(0xc0001608a0, 0xc000098528, 0x13, 0x8da74a, 0x4, 0xc00017bd80, 0x2, 0x2, 0x0, 0xc000192180, ...)
C:/Go/src/reflect/value.go:447 +0x450
reflect.Value.Call(0xc0001608a0, 0xc000098528, 0x13, 0xc00017bd80, 0x2, 0x2, 0x0, 0x0, 0xc00017bdb0)
C:/Go/src/reflect/value.go:308 +0xab
........../vendor/github.com/henrylee2cn/teleport.makeCallHandlersFromStruct.func2(0xc0000cd810, 0x8261c0, 0xc00016b260, 0x16)
........../vendor/github.com/henrylee2cn/teleport/router.go:506 +0x138
........../vendor/github.com/henrylee2cn/teleport.(*handlerCtx).handleCall(0xc0000cd810)
........../vendor/github.com/henrylee2cn/teleport/context.go:513 +0x391
........../vendor/github.com/henrylee2cn/teleport.(*handlerCtx).handle(0xc0000cd810)
........../vendor/github.com/henrylee2cn/teleport/context.go:366 +0x35f

初步猜测可能是反射复制Manager实例的时候漏了mux字段导致。具体原因暂不详。

Server端调用了Close,监听还是存在,如何退出服务器?

例子是simple里的。

服务器端:
在ListenAndServe前加了个定时器,2秒后关闭服务器
go func() {
time.Sleep(2 * time.Second)
srv.Close()
}()
srv.ListenAndServe()
fmt.Println("exit.............")

客户端:
在 cli.Dial(":9090") 后也加了个定时器,3秒后重连
go func() {
time.Sleep(3 *time.Second)
cli.Dial(":9090")
}()

服务器2秒后执行关闭,并没有退出监听,后面打印也没继续,3秒后客户端还是继续连接成功
看代码还是阻塞在Accept那,这如何退出服务器?

运行example/Simple失败:qtls.ConnectionState not compatible with tls.ConnectionState

运行Simple例子失败,
Win7 64bits

panic: qtls.ConnectionState not compatible with tls.ConnectionState

goroutine 1 [running]:
github.com/ourcolour/xnettools/vendor/github.com/lucas-clemente/quic-go/internal/handshake.init.0()
E:/goprojects/src/github.com/ourcolour/xnettools/vendor/github.com/lucas-clemente/quic-go/internal/handshake/unsafe.go:17 +0x2b3


你好,发现一个问题,不知道是不是一个bug

问题描述如下:
我是用了auth plugin,但是每次断线重连之后在plugin这块都会直接返回connection close的error信息,跟踪代码后发现,在renewSessionForClient方法中,在p.pluginContainer.postDial(sess)时,当前session的状态依然是Closed,导致后续写消息直接判断状态返回了,
现修改如下:


func (p *peer) renewSessionForClient(sess *session, dialFunc func() (net.Conn, error), addr string, protoFuncs []ProtoFunc) error {
	var conn, dialErr = dialFunc()
	if dialErr != nil {
		return dialErr
	}
	if p.tlsConfig != nil {
		conn = tls.Client(conn, p.tlsConfig)
	}
	oldIP := sess.LocalAddr().String()
	oldID := sess.ID()
	oldConn := sess.getConn()
	if oldConn != nil {
		oldConn.Close()
	}
	sess.socket.Reset(conn, protoFuncs...)
	if oldIP == oldID {
		sess.socket.SetID(sess.LocalAddr().String())
	} else {
		sess.socket.SetID(oldID)
	}
	atomic.StoreInt32(&sess.status, statusOk) //将状态修改放在plugin之前
	if rerr := p.pluginContainer.postDial(sess); rerr != nil {
		sess.Close()
		return rerr.ToError()
	}
	// atomic.StoreInt32(&sess.status, statusOk)
	AnywayGo(sess.startReadAndHandle)
	p.sessHub.Set(sess)
	return nil
}

不知道这样改动会不会引发其他问题,还没有完全吃透teleport的源码

c++ client

可以使用C++客户端连接erpc的服务吗. 这种情况下, erpc服务使用哪种协议比较方便客户端组包或解包? pb、raw?
有没有可能erpc服务自定义数据包的格式. 比如 |len|version|body-bytes-data...|
这样客户端可以比较方便的与服务端做数据交互,而且也提供了自定义协议的能力.

quic网络类型报错

quic模式啊,我看了下最新的teleport中的类型没有这个,所以我这里按照quic的Demo一跑就报“Invalid network config, refer to the following: tcp, tcp4, tcp6, unix or unixpacket.”

服务端重启后,客户端无法重现建立连接

客户端使用RedialTimes: -1,参数设置不断尝试重连,当服务端停止,然后重启服务端,客户端无法正常重建连接。后发现,修改peer.go的以下代码:

stat = p.renewSessionForClient(sess, dialFunc, addr, protoFuncs)
if !stat.OK() { // 此处改为 if stat.OK() {
    Infof("redial ok (network:%s, addr:%s, id:%s)", p.network, sess.RemoteAddr().String(), sess.ID())
    return true
}

经过修正后,客户端能重连成功。

如何才能正确获取push事件返回的status?

如题,客户端代码:

Cli.RoutePush(new(Push))
// 连接服务端
sess, stat := Cli.Dial(serverUrl)
...

type Push struct {
	tp.PushCtx
}

func (p *Push) Table(msg *vos.TableMsg) *tp.Status {
	if true {
		return tp.NewStatusByCodeText(tp.CodeInternalServerError, "test return error", false)
	}
        return nil
}

服务器端代码:

status := session.Push("/push/table", msg)
logs.Logger.Debug("status value.",zap.Any("status",status)) // 打印得到的是nil值

现在的问题是:为什么服务器端得到的status一直是nil值?求助。

可以根据teleport开发socket.io的插件吗?

我们的项目之前是根据socket.io开发的实时推送服务,最近用户猛增,导致服务器转发消息延迟很大,想用go重写服务端,但是客户端还用socket.io兼容,估计只能适配socket.io的协议来改服务端这一块,不知道意义可大,plugin的方式可不可行。

windows 下報錯,mac下是可以的

go的版本是:
$ go version
go version go1.8 windows/386
go 当前的 env是:
$ go env
set GOARCH=386
set GOBIN=
set GOEXE=.exe
set GOHOSTARCH=386
set GOHOSTOS=windows
set GOOS=windows
set GOPATH=D:\workspace\go
set GORACE=
set GOROOT=D:\Go
set GOTOOLDIR=D:\Go\pkg\tool\windows_386
set GCCGO=gccgo
set GO386=
set CC=gcc
set GOGCCFLAGS=-m32 -mthreads -fmessage-length=0 -fdebug-prefix-map=C:\Users\ADMINI~1\AppData\Local\Temp\go-build765695343=/tmp/go-build -gno-record-gcc-switches
set CXX=g++
set CGO_ENABLED=1
set PKG_CONFIG=pkg-config
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2

报的错误是:
$ go run client.go
[2017/11/19 14:17:42.098] [PRIN] The current process PID: 11000<github.com/henrylee2cn/teleport/utils.go:58>
[2017/11/19 14:17:42.103] [PRIN] register push handler: /push/test<github.com/henrylee2cn/teleport/router.go:89>
[2017/11/19 14:17:42.108] [INFO] dial ok (addr: 127.0.0.1:9090, id: 127.0.0.1:56087)<github.com/henrylee2cn/teleport/peer.go:142>
[2017/11/19 14:17:42.108] [DEBU] panic:
runtime error: invalid memory address or nil pointer dereference
sync/atomic.LoadUint64(0x126e440c, 0x12776000, 0x127027fc)
D:/Go/src/sync/atomic/asm_386.s:159 +0xb
github.com/henrylee2cn/teleport.(*session).ReadTimeout(0x126e4370, 0x0, 0x0)
D:/workspace/go/src/github.com/henrylee2cn/teleport/session.go:197 +0x28
github.com/henrylee2cn/teleport.(*session).startReadAndHandle(0x126e4370)
D:/workspace/go/src/github.com/henrylee2cn/teleport/session.go:404 +0xcf
github.com/henrylee2cn/teleport.(*session).(github.com/henrylee2cn/teleport.startReadAndHandle)-fm()
D:/workspace/go/src/github.com/henrylee2cn/teleport/peer.go:140 +0x20
github.com/henrylee2cn/goutil/pool.(*GoPool).goroutineFunc(0x1275f780, 0x1274f820)
D:/workspace/go/src/github.com/henrylee2cn/goutil/pool/GoPool.go:223 +0x63
github.com/henrylee2cn/goutil/pool.(*GoPool).getCh.func1(0x1275f780, 0x1274f820, 0x6a7540, 0x1274f820)
D:/workspace/go/src/github.com/henrylee2cn/goutil/pool/GoPool.go:199 +0x29
created by github.com/henrylee2cn/goutil/pool.(*GoPool).getCh
D:/workspace/go/src/github.com/henrylee2cn/goutil/pool/GoPool.go:201 +0xe8<github.com/henrylee2cn/teleport/session.go:383>
[2017/11/19 14:17:42.115] [ERRO] panic:
runtime error: invalid memory address or nil pointer dereference
sync/atomic.LoadUint64(0x126e4414, 0x126e43b0, 0x0)
D:/Go/src/sync/atomic/asm_386.s:159 +0xb
github.com/henrylee2cn/teleport.(*session).WriteTimeout(0x126e4370, 0x0, 0x1a0250)
D:/workspace/go/src/github.com/henrylee2cn/teleport/session.go:202 +0x28
github.com/henrylee2cn/teleport.(*session).write(0x126e4370, 0x1275f8c0, 0x0, 0x0)
D:/workspace/go/src/github.com/henrylee2cn/teleport/session.go:446 +0x56
github.com/henrylee2cn/teleport.(*session).GoPull(0x126e4370, 0x723653, 0x23, 0x6cc9c0, 0x1274f900, 0x6a8880, 0x126cfe78, 0x1275f880, 0x0, 0x0, ...)
D:/workspace/go/src/github.com/henrylee2cn/teleport/session.go:292 +0x4cf<github.com/henrylee2cn/teleport/session.go:285>
[2017/11/19 14:19:16.861] [INFO] shutting down process...<github.com/henrylee2cn/goutil/graceful/grace_a.go:34>
[2017/11/19 14:19:36.868] [ERRO] [shutdown-timeout] context deadline exceeded<github.com/henrylee2cn/goutil/graceful/grace.go:86>

go get报错

信息如下

-> go get -u github.com/henrylee2cn/teleport
go: finding golang.org/x/sys latest
go: finding github.com/henrylee2cn/goutil latest
go: finding github.com/henrylee2cn/cfgo latest
go: finding golang.org/x/crypto latest
go: finding golang.org/x/net latest
go: finding gopkg.in/tomb.v1 latest
go: finding golang.org/x/tools latest
go: finding golang.org/x/sync latest
go: finding gopkg.in/check.v1 latest
# github.com/lucas-clemente/quic-go/internal/handshake
../gopath/pkg/mod/github.com/lucas-clemente/[email protected]/internal/handshake/crypto_setup.go:115:5: cannot use &cryptoSetup literal (type *cryptoSetup) as type qtls.RecordLayer in assignment:
	*cryptoSetup does not implement qtls.RecordLayer (wrong type for SetReadKey method)
		have SetReadKey(*qtls.CipherSuite, []byte)
		want SetReadKey(qtls.EncryptionLevel, *qtls.CipherSuite, []byte)
../gopath/pkg/mod/github.com/lucas-clemente/[email protected]/internal/handshake/crypto_setup.go:216:35: cannot use cs (type *cryptoSetup) as type qtls.RecordLayer in argument to tlsConfigToQtlsConfig:
	*cryptoSetup does not implement qtls.RecordLayer (wrong type for SetReadKey method)
		have SetReadKey(*qtls.CipherSuite, []byte)
		want SetReadKey(qtls.EncryptionLevel, *qtls.CipherSuite, []byte)

如何保存会话状态?

貌似框架对会话的状态的管理不太友好啊。每次请求过来之后,都会路由到不同的handler实例,这样就不能通过handler来管理会话状态了,得要自己再重新封装一层。后面这块会考虑重构吗?

使用govendor后的报错

不使用govendor的话正常,但是使用了govendor会有一些的报错,老哥能帮忙看看嘛。。

vendor/github.com/henrylee2cn/erpc/plugin/auth/auth.go:111:21: cannot use sess (type erpc.PreSession) as type Session in argument to a.bearerFunc:
erpc.PreSession does not implement Session (wrong type for Swap method)
have Swap() "github.com/henrylee2cn/goutil".Map
want Swap() "rock/agent/vendor/github.com/henrylee2cn/goutil".Map

vendor/github.com/henrylee2cn/erpc/context.go:375:20: cannot use statCodeMtypeNotAllowed (type *"rock/agent/vendor/github.com/henrylee2cn/goutil/status".Status) as type *"github.com/henrylee2cn/goutil/status".Status in argument to c.output.SetStatus

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.