blog的搭建
利用thrift的跨平台机制实现进程通讯,本机是uos系统+go语言,virtualbox是windows系统+C++,在virtualbox上增加端口转发既可实现windows与uos两者不同系统不同语言的进程通讯。
thrift简介
1. 理论知识
Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作一个远程过程调用(RPC)框架来使用,是由Facebook为“大规模跨语言服务开发”而开发的。它通过一个代码生成引擎联合了一个软件栈,来创建不同程度的、无缝的跨平台高效服务,可以使用C#、C++(基于POSIX兼容系统)、Cappuccino、Cocoa、Delphi、Erlang、Go、Haskell、Java、Node.js、OCaml、Perl、PHP、Python、Ruby和Smalltalk。虽然它以前是由Facebook开发的,但它现在是Apache软件基金会的开源项目了。该实现被描述在2007年4月的一篇由Facebook发表的技术论文中,该论文现由Apache掌管。
2.注意事项
- Thrift支持的基本数据类型
- byte: 有符号字节
- i16: 16 位有符号整数
- i32 : 32 位有符号整数
- i64: 64 位有符号整数
- double : 64 位浮点数
- string : 字符串
- 可用容器类型
- list(t): 元素类型为t的有序表,容许元素重复。
- set(t):元素类型为t的无序表,不容许元素重复。对应c++中的set,java中的HashSet,python中的set,php中没有set,则转换为list类型。
- map(t,t): 键类型为t,值类型为t的kv对,键不容许重复。对用c++中的map, Java的HashMap, PHP 对应 array, Python/Ruby 的dictionary。
- Thrift 架构(图来自于网络)
thrift主要用于各个服务之间的RPC通信,支持跨语言。thrift是一个典型的CS结构,客户端和服务端可以使用不同的语言开发,thrift通过IDL(Interface Description Language)来关联客户端和服务端。thrift的整体架构图如下图所示
uos利用go实现thrift的客户端和服务端
goland安装thrift包
go get git.apache.org/thrift.git/lib/go/thrift
调用命令thrift -version
显示版本号即安装成功。下载的文件加入到
gopath
中编写属于接口的fuse.thrift的LDL文件,我本地要实现一个剪切板数据互发功能,所以接口为剪切板功能。
1
2
3
4
5
6
7
8
9
10
11namespace go fuse
service WindowsToUos {
//windows 剪切板发送到uos
bool sendCliboard(1:i32 nType, 2:string path);
void stop();
}
service UosToWindows{
//uos 剪切板发送到windows
bool sendCliboard(1:i32 nType, 2:string path, 3:string Vol);
}在service windowstouos中,是windows为客户端,uos为服务端。在uostowindows中,是windows为服务端,uos为客户端。两者可以来回通讯。
运行命令,生成相关代码,目录下就会存在一个gen-go的一个代码文件夹
thrift -r –gen go fuse.thrift
服务端接口初始化代码如下,
EchoServerImp
接口为空接口。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27type EchoServerImp struct {
}
func (s *Server) ServerStart(port int) {
protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
transportFactory := thrift.NewTBufferedTransportFactory(10000000)
serverTransport, err := thrift.NewTServerSocket("127.0.0.1:9150")
if err != nil {
fmt.Println("Error!", err)
os.Exit(1)
}
handler := &EchoServerImp{}
processor := fuse.NewWindowsToUosProcessor(handler)
server := thrift.NewTSimpleServer4(processor, serverTransport, transportFactory, protocolFactory)
fmt.Println("thrift server in", "127.0.0.1:9150")
server.Serve()
}
func main() {
go func() {
// ListenClipboard()
}()
ctxT, cancelFunc = context.WithCancel(context.Background())
sev := &Server{}
sev.ServerStart(8192)
}在服务端时,需要把LDL的函数实现,不然会报错,逻辑实现代码如下
1
2
3
4
5func (e *EchoServerImp) Stop(ctx context.Context) error {
logger.Info("Revice Stop!!!")
stop()
return nil
}客户端接口初始化代码如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
type Manager struct {
clipboard // interface com.deepin.ListenClipboard
proxy.Object
}
type ClipboardService struct {
loginManager *Manager
sessionSigLoop *dbusutil.SignalLoop
service *dbusutil.Service
}
func ListenClipboard() error {
var cb ClipboardService
//注册剪切板dbus信号
sessionBus, err := dbus.SessionBus()
if err != nil {
logger.Warning("failed to register clipboard changed signal:", err)
return err
}
cb.loginManager = NewCBManager(sessionBus)
cb.sessionSigLoop = dbusutil.NewSignalLoop(sessionBus, 10)
cb.sessionSigLoop.Start()
cb.loginManager.InitSignalExt(cb.sessionSigLoop, true)
//绑定剪切板变化dbus信号
//_, err = cb.loginManager.ConnectClipboardChange()qqq+
if err != nil {
logger.Warning("failed to connect clipboard changed signal:", err)
return err
}
return nil
}客户端调用服务端代码如下
1
cb.loginManager.SendCliboardToWindows(clipboardType, clipboardData, vol)