github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调
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”库实现,可以注册回调的更多相关文章
- 使用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 下载速度很慢,然后下载一段时间 ...
- Android 配置从GitHub上下载下来的不太规则的源代码库,并保证程序正常运行
用过github的朋友一定会发现,我们在github上下载下来的源代码(例子和库),放到eclipse中并不是总能正常运行的,它有可能会出现这样或者那样的错误,例如:找不到jar包,配置文件错误,R文 ...
- github上用golang写的项目
1.moby/moby docker的新马甲 2.kubernetes/kubernetes 分布式容器管理 3.grafana/grafana 一个可视化面板,有漂亮的仪表盘,多种数据来源,适合做系 ...
- [resource]Github上维护的一个机器学习相关的框架,库和工具列表
https://github.com/josephmisiti/awesome-machine-learning A curated list of awesome Machine Learning ...
- 深度学习动手入门:GitHub上四个超棒的TensorFlow开源项目
作者简介:akshay pai,数据科学工程师,热爱研究机器学习问题.Source Dexter网站创办人. TensorFlow是Google的开源深度学习库,你可以使用这个框架以及Python编程 ...
- 【重要】使用Git命令行上传到GitHub上
[本人GitHub账号:] 用户名:chenhongshuang 密码:shuangshuang6300 邮箱:2452420371@qq.com 进入GitHub账号后 1·新建项目文件名称例dem ...
- C# 基于Directshow.Net lib库 USB摄像头使用DirectShow.NET获取摄像头视频流
https://blog.csdn.net/u010118312/article/details/91766787 https://download.csdn.net/download/u010118 ...
- Golang优秀开源项目汇总, 10大流行Go语言开源项目, golang 开源项目全集(golang/go/wiki/Projects), GitHub上优秀的Go开源项目
Golang优秀开源项目汇总(持续更新...)我把这个汇总放在github上了, 后面更新也会在github上更新. https://github.com/hackstoic/golang-open- ...
- GitHub Android 最火开源项目Top20 GitHub 上的开源项目不胜枚举,越来越多的开源项目正在迁移到GitHub平台上。基于不要重复造轮子的原则,了解当下比较流行的Android与iOS开源项目很是必要。利用这些项目,有时能够让你达到事半功倍的效果。
1. ActionBarSherlock(推荐) ActionBarSherlock应该算得上是GitHub上最火的Android开源项目了,它是一个独立的库,通过一个API和主题,开发者就可以很方便 ...
随机推荐
- Hadoop学习---CentOS中hadoop伪分布式集群安装
注意:此次搭建是在ssh无密码配置.jdk环境已经配置好的情况下进行的 可以参考: Hadoop完全分布式安装教程 CentOS环境下搭建hadoop伪分布式集群 1.更改主机名 执行命令:vi / ...
- vscode:解决操作git总让输入用户名及密码问题
只要是使用git操作,不管是同步,拉去,克隆,vscode总让我们输入用户名及密码,是一件很繁琐的事情 我们打开终端,会看到cmd定位在我们仓库位置,我们只要添加:git config --globa ...
- PHP----练习-----三级联动
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- [19/03/25-星期一] 容器_Collection(集合、容器)之Set(集合、安置,无顺序不可重复)
一.概念&方法 Set接口继承自Collection,Set接口中没有新增方法,方法和Collection保持完全一致.. Set容器特点:无序.不可重复.无序指Set中的元素没有索引,只能遍 ...
- 提交文件到ng-pages分支
一.提交dist文件夹到ng-pages分支 git subtree push --prefix=dist origin gh-pages 二.提交所有文件到ng-pages分支 text git:( ...
- python-装饰器的简单使用
一.介绍 首先我们先来看一个简单的例子,在基础平台中有一个home()和tv()函数,在业务平台中调用此函数时,给出了响应的打印内容: 基础平台: def home(): print('welcome ...
- PL\SQL设置中文
打开PL\SQL 1.菜单->Tools ->preferences->User Interface -> Appearance -> Language 选择 Chine ...
- Segmentation fault(Core Dump)
Segmentation fault 这个提示还是比较常见的,这个提示就是段错误,这是翻译还是十分恰当的. Core Dump 有的时候给我们呈现的翻译很有趣是”吐核“,但是实际上比较贴切的翻译是核心 ...
- 搭建 github.io 博客站点
前言 很多人都有搭建博客或知识库站点的想法,可自己买云服务器太不划算,部署管理也是个问题:基于免费又热门的 GitHub Pages 来搭建博客站点倒是省钱省力省事的好办法,于是上网一搜,满屏都是关于 ...
- Web—05-常用css列表
color 设置文字的颜色,如: color:red; font-size 设置文字的大小,如:font-size:12px; font-family 设置文字的字体,如:font-family:'微 ...