github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调。仅支持一个server和一个client交互。

地址:https://github.com/rocket049/rpc2d

公共包:

package rpc2d

import (
"bufio"
"bytes"
"encoding/binary"
"io"
"log"
"net"
"net/rpc"
"sync"
) //wrap message( []byte ): "T uint8 + length uint16 + bytes [length]byte". T = S/C/E
const (
S = byte('S') //Flag : Server Message
C = byte('C') //Flag : Client Message
E = byte('E') //Flag : Error
) //Pool: bytes.Buffer, use : bufPool.Get().(*bytes.Buffer)
var bufPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
} func newBuffer() *bytes.Buffer {
return bufPool.Get().(*bytes.Buffer)
} //ProviderType This is NOT must fit below struct. But this struct can help CALLBACK. See test server.go/client.go
type ProviderType struct {
Client *rpc.Client
Data interface{}
} //RpcNode double direction RPC
type RpcNode struct {
Server *rpc.Server
Client *rpc.Client
connC1, connC2 net.Conn
connS1, connS2 net.Conn
remote net.Conn
} //NewRpcNode create new Rpc.Node ,init rpc.Server with service provider
func NewRpcNode(provider interface{}) *RpcNode {
res := new(RpcNode)
res.Server = rpc.NewServer()
res.Server.Register(provider)
return res
} //WrapSend wrap and split message, send to remote
func (self *RpcNode) wrapSend(t byte, msg []byte, conn io.Writer) (nbytes int, e error) {
len1 := len(msg)
n := len1 / 65535
m := uint16(len1 % 65535)
//log.Printf("length:%d split:%d last:%d\n", len1, n, m)
var h1 = [3]byte{t, 0xff, 0xff}
//h1[0] = t
//binary.BigEndian.PutUint16(h1[1:2], 65535)
bufconn := bufio.NewWriter(conn)
b := newBuffer()
for i := 0; i < n; i++ {
//send
p := msg[i*65535 : i*65535+65535]
b.Reset()
b.Write(h1[:])
b.Write(p)
_, e := bufconn.Write(b.Bytes())
if e != nil {
return 0, e
}
}
if m > 0 {
//send
binary.BigEndian.PutUint16(h1[1:3], m)
p := msg[n*65535 : n*65535+int(m)]
b.Reset()
b.Write(h1[:])
b.Write(p)
_, e := bufconn.Write(b.Bytes())
if e != nil {
return 0, e
}
//log.Printf("length:%d split:%d last:%d\nfrom %c:%v\n", len1, n, m, t, b.Bytes())
}
bufPool.Put(b)
err := bufconn.Flush()
if err != nil {
log.Printf("WrapSend:%v\n", err)
return 0, err
} else {
return len1, nil
}
} //wrapRecv receive message from remote. Next: route to server or client
func (self *RpcNode) wrapRecv(conn io.Reader) (msg []byte, t byte) {
//bufconn := bufio.NewReader(conn)
var h1 [3]byte
n, _ := io.ReadFull(conn, h1[:])
if n != 3 {
return nil, E
}
length := binary.BigEndian.Uint16(h1[1:])
buf1 := make([]byte, int(length))
n, _ = io.ReadFull(conn, buf1)
if n == int(length) {
return buf1, h1[0]
} else {
return nil, E
}
} //proxyLoop proxy between remote and local server/client,redirect/wrapsend messages
func (self *RpcNode) proxyLoop(conn net.Conn) {
self.connS1, self.connS2 = net.Pipe()
self.connC1, self.connC2 = net.Pipe()
//self.Server = rpc.NewServer()
go func() {
self.Server.ServeConn(self.connS1)
//log.Println("end serve")
}()
self.Client = rpc.NewClient(self.connC1)
self.remote = conn
//loop next
go self.localToRemote(self.connC2, C)
go self.localToRemote(self.connS2, S)
go self.remoteToLocal() //block
} func (self *RpcNode) remoteToLocal() {
var bufremote = bufio.NewReader(self.remote) for {
msg, t := self.wrapRecv(bufremote)
switch t {
case S:
self.connC2.Write(msg)
//log.Printf("to C:%v\n", msg)
case C:
self.connS2.Write(msg)
//log.Printf("to S:%v\n", msg)
case E:
break
}
}
self.remote.Close()
log.Println("remote disconnect")
} func (self *RpcNode) localToRemote(from io.ReadCloser, t byte) {
var buf = make([]byte, 512)
for {
n, err := from.Read(buf)
if n > 0 {
_, err := self.wrapSend(t, buf[:n], self.remote)
if err != nil {
log.Printf("WrapSend:%v\n", err)
break
}
} else {
log.Printf("local Read:%v\n", err)
break
}
}
from.Close()
log.Printf("local disconnect: %c\n", t)
} //Dial connect to remote, and link local server/client,use after NewRpcNode
func (self *RpcNode) Dial(addr string) error {
conn, err := net.Dial("tcp", addr)
if err != nil {
return err
}
self.proxyLoop(conn)
return nil
} //Close close
func (self *RpcNode) Close() {
self.Client.Close()
self.connC2.Close()
self.connC1.Close()
self.connS2.Close()
self.connS1.Close()
} //Accept accept remote connection,and link local server/client
func Accept(l net.Listener, provider interface{}) (*RpcNode, error) {
conn, err := l.Accept()
if err != nil {
return nil, err
}
node1 := NewRpcNode(provider)
node1.proxyLoop(conn)
return node1, nil
}

  

server端代码:

package main

import (
"fmt"
"log"
"net"
"time" rpc2d "../rpc2d"
) type ServerStu rpc2d.ProviderType var p = new(ServerStu)
var count = 0 func (self *ServerStu) FuncName(arg *string, reply *int) error {
time.Sleep(2 * time.Second)
var ret int
p.Client.Call("ClentStu."+*arg, "this is callback from ServerStu.FuncName.", &ret)
return nil
} func (self *ServerStu) Show(arg string, reply *int) error {
fmt.Printf(" ServerStuRecv: %s count: %d\n", arg, count)
*reply = count
count++
go Sleepfun()
return nil
} func Sleepfun() {
time.Sleep(2 * time.Second)
var ret int
p.Client.Call("ClentStu.Show", "this is callback from ServerStu.Show.", &ret)
} func main() {
listener, err := net.Listen("tcp", "127.0.0.1:5678")
if err != nil {
log.Fatal("Listen:", err)
}
defer listener.Close() node1, err := rpc2d.Accept(listener, p)
if err != nil {
log.Fatal("Accept:", err)
}
defer node1.Close()
p.Client = node1.Client
var s string
var ret int
fmt.Println("------------")
for i := 0; i < 10; i++ {
fmt.Scanln(&s)
node1.Client.Call("ClentStu.Show", s, &ret)
log.Printf("Return: %d\n", ret)
}
}

  

  

客户端代码:

package main

import (
"fmt"
"log" rpc2d "../rpc2d"
) type ClentStu int var p = new(ClentStu) var count = 10 func (self *ClentStu) Show(arg string, reply *int) error {
fmt.Printf("ClentStu Recv: %s\n", arg)
*reply = count
count++
return nil
} func main() { node1 := rpc2d.NewRpcNode(p)
err := node1.Dial("127.0.0.1:5678")
if err != nil {
log.Fatal("Dial:", err)
}
//p.Client = node1.Client
defer node1.Close()
var s string
var ret int
fmt.Println("------------")
for i := 0; i < 10; i++ {
fmt.Scanln(&s)
node1.Client.Call("ServerStu.Show", s, &ret)
node1.Client.Call("ServerStu.FuncName", "Show", &ret)
log.Printf("Return: %d\n", ret)
}
}

  

github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调的更多相关文章

  1. 使用git克隆github上的项目失败,报错error: RPC failed; curl 56 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 10054

    错误描述 今天在github上使用 git clone 某个项目代码的时, git clone https://github.com/XXXX/xxx-blog.git 下载速度很慢,然后下载一段时间 ...

  2. Android 配置从GitHub上下载下来的不太规则的源代码库,并保证程序正常运行

    用过github的朋友一定会发现,我们在github上下载下来的源代码(例子和库),放到eclipse中并不是总能正常运行的,它有可能会出现这样或者那样的错误,例如:找不到jar包,配置文件错误,R文 ...

  3. github上用golang写的项目

    1.moby/moby docker的新马甲 2.kubernetes/kubernetes 分布式容器管理 3.grafana/grafana 一个可视化面板,有漂亮的仪表盘,多种数据来源,适合做系 ...

  4. [resource]Github上维护的一个机器学习相关的框架,库和工具列表

    https://github.com/josephmisiti/awesome-machine-learning  A curated list of awesome Machine Learning ...

  5. 深度学习动手入门:GitHub上四个超棒的TensorFlow开源项目

    作者简介:akshay pai,数据科学工程师,热爱研究机器学习问题.Source Dexter网站创办人. TensorFlow是Google的开源深度学习库,你可以使用这个框架以及Python编程 ...

  6. 【重要】使用Git命令行上传到GitHub上

    [本人GitHub账号:] 用户名:chenhongshuang 密码:shuangshuang6300 邮箱:2452420371@qq.com 进入GitHub账号后 1·新建项目文件名称例dem ...

  7. C# 基于Directshow.Net lib库 USB摄像头使用DirectShow.NET获取摄像头视频流

    https://blog.csdn.net/u010118312/article/details/91766787 https://download.csdn.net/download/u010118 ...

  8. Golang优秀开源项目汇总, 10大流行Go语言开源项目, golang 开源项目全集(golang/go/wiki/Projects), GitHub上优秀的Go开源项目

    Golang优秀开源项目汇总(持续更新...)我把这个汇总放在github上了, 后面更新也会在github上更新. https://github.com/hackstoic/golang-open- ...

  9. GitHub Android 最火开源项目Top20 GitHub 上的开源项目不胜枚举,越来越多的开源项目正在迁移到GitHub平台上。基于不要重复造轮子的原则,了解当下比较流行的Android与iOS开源项目很是必要。利用这些项目,有时能够让你达到事半功倍的效果。

    1. ActionBarSherlock(推荐) ActionBarSherlock应该算得上是GitHub上最火的Android开源项目了,它是一个独立的库,通过一个API和主题,开发者就可以很方便 ...

随机推荐

  1. June 25th 2017 Week 26th Sunday

    There is always that one song that brings back old memories. 总有那么一首歌,让你想起那些旧的回忆. There are seveal so ...

  2. 转 C++11之std::function和std::bind

    std::function是可调用对象的包装器,它最重要的功能是实现延时调用: #include "stdafx.h" #include<iostream>// std ...

  3. maven工程src/main/java目录无法创建问题

    在项目上右键选择properties,然后点击Javabuild path,在Librarys下,编辑JRE System Library,选择 workspace default jre 即可

  4. hdu 3068 最长回文_Manacher模板

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/neng18/article/details/24269469 pid=3068" rel= ...

  5. hbase hfilev2

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/u014393917/article/details/25508809 HFileV2文件 HFile ...

  6. 2018 Multi-University Training Contest 3 Problem F. Grab The Tree 【YY+BFS】

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6324 Problem F. Grab The Tree Time Limit: 2000/1000 MS ...

  7. Codeforces Round #528 (Div. 2, based on Technocup 2019 Elimination Round 4) C. Connect Three 【模拟】

    传送门:http://codeforces.com/contest/1087/problem/C C. Connect Three time limit per test 1 second memor ...

  8. PAT——1018. 锤子剪刀布

    大家应该都会玩“锤子剪刀布”的游戏:两人同时给出手势,胜负规则如图所示: 现给出两人的交锋记录,请统计双方的胜.平.负次数,并且给出双方分别出什么手势的胜算最大. 输入格式: 输入第1行给出正整数N( ...

  9. Matplotlib——中级

    关于Matplotlib的愚见 初级中,我只是简单介绍了Matplotlib的使用方法,在中级部分,我系统地说一下我总结的内容. 上图是我画的关于Matplotlib几个对象之间的关系图.它们都来自于 ...

  10. OpenID Connect Core 1.0(二)ID Token

    2.ID Token(ID Token) OpenID Connect主要是对OAuth 2.0 能够使得终端用户通过ID Token的数据结构进行验证.当客户端和潜在的其他请求声明,ID Token ...